Home | History | Annotate | Download | only in test
      1 #!/usr/bin/env python
      2 
      3 """Unit tests for the with statement specified in PEP 343."""
      4 
      5 
      6 __author__ = "Mike Bland"
      7 __email__ = "mbland at acm dot org"
      8 
      9 import sys
     10 import unittest
     11 from collections import deque
     12 from contextlib import GeneratorContextManager, contextmanager
     13 from test.test_support import run_unittest
     14 
     15 
     16 class MockContextManager(GeneratorContextManager):
     17     def __init__(self, gen):
     18         GeneratorContextManager.__init__(self, gen)
     19         self.enter_called = False
     20         self.exit_called = False
     21         self.exit_args = None
     22 
     23     def __enter__(self):
     24         self.enter_called = True
     25         return GeneratorContextManager.__enter__(self)
     26 
     27     def __exit__(self, type, value, traceback):
     28         self.exit_called = True
     29         self.exit_args = (type, value, traceback)
     30         return GeneratorContextManager.__exit__(self, type,
     31                                                 value, traceback)
     32 
     33 
     34 def mock_contextmanager(func):
     35     def helper(*args, **kwds):
     36         return MockContextManager(func(*args, **kwds))
     37     return helper
     38 
     39 
     40 class MockResource(object):
     41     def __init__(self):
     42         self.yielded = False
     43         self.stopped = False
     44 
     45 
     46 @mock_contextmanager
     47 def mock_contextmanager_generator():
     48     mock = MockResource()
     49     try:
     50         mock.yielded = True
     51         yield mock
     52     finally:
     53         mock.stopped = True
     54 
     55 
     56 class Nested(object):
     57 
     58     def __init__(self, *managers):
     59         self.managers = managers
     60         self.entered = None
     61 
     62     def __enter__(self):
     63         if self.entered is not None:
     64             raise RuntimeError("Context is not reentrant")
     65         self.entered = deque()
     66         vars = []
     67         try:
     68             for mgr in self.managers:
     69                 vars.append(mgr.__enter__())
     70                 self.entered.appendleft(mgr)
     71         except:
     72             if not self.__exit__(*sys.exc_info()):
     73                 raise
     74         return vars
     75 
     76     def __exit__(self, *exc_info):
     77         # Behave like nested with statements
     78         # first in, last out
     79         # New exceptions override old ones
     80         ex = exc_info
     81         for mgr in self.entered:
     82             try:
     83                 if mgr.__exit__(*ex):
     84                     ex = (None, None, None)
     85             except:
     86                 ex = sys.exc_info()
     87         self.entered = None
     88         if ex is not exc_info:
     89             raise ex[0], ex[1], ex[2]
     90 
     91 
     92 class MockNested(Nested):
     93     def __init__(self, *managers):
     94         Nested.__init__(self, *managers)
     95         self.enter_called = False
     96         self.exit_called = False
     97         self.exit_args = None
     98 
     99     def __enter__(self):
    100         self.enter_called = True
    101         return Nested.__enter__(self)
    102 
    103     def __exit__(self, *exc_info):
    104         self.exit_called = True
    105         self.exit_args = exc_info
    106         return Nested.__exit__(self, *exc_info)
    107 
    108 
    109 class FailureTestCase(unittest.TestCase):
    110     def testNameError(self):
    111         def fooNotDeclared():
    112             with foo: pass
    113         self.assertRaises(NameError, fooNotDeclared)
    114 
    115     def testEnterAttributeError(self):
    116         class LacksEnter(object):
    117             def __exit__(self, type, value, traceback):
    118                 pass
    119 
    120         def fooLacksEnter():
    121             foo = LacksEnter()
    122             with foo: pass
    123         self.assertRaises(AttributeError, fooLacksEnter)
    124 
    125     def testExitAttributeError(self):
    126         class LacksExit(object):
    127             def __enter__(self):
    128                 pass
    129 
    130         def fooLacksExit():
    131             foo = LacksExit()
    132             with foo: pass
    133         self.assertRaises(AttributeError, fooLacksExit)
    134 
    135     def assertRaisesSyntaxError(self, codestr):
    136         def shouldRaiseSyntaxError(s):
    137             compile(s, '', 'single')
    138         self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr)
    139 
    140     def testAssignmentToNoneError(self):
    141         self.assertRaisesSyntaxError('with mock as None:\n  pass')
    142         self.assertRaisesSyntaxError(
    143             'with mock as (None):\n'
    144             '  pass')
    145 
    146     def testAssignmentToEmptyTupleError(self):
    147         self.assertRaisesSyntaxError(
    148             'with mock as ():\n'
    149             '  pass')
    150 
    151     def testAssignmentToTupleOnlyContainingNoneError(self):
    152         self.assertRaisesSyntaxError('with mock as None,:\n  pass')
    153         self.assertRaisesSyntaxError(
    154             'with mock as (None,):\n'
    155             '  pass')
    156 
    157     def testAssignmentToTupleContainingNoneError(self):
    158         self.assertRaisesSyntaxError(
    159             'with mock as (foo, None, bar):\n'
    160             '  pass')
    161 
    162     def testEnterThrows(self):
    163         class EnterThrows(object):
    164             def __enter__(self):
    165                 raise RuntimeError("Enter threw")
    166             def __exit__(self, *args):
    167                 pass
    168 
    169         def shouldThrow():
    170             ct = EnterThrows()
    171             self.foo = None
    172             with ct as self.foo:
    173                 pass
    174         self.assertRaises(RuntimeError, shouldThrow)
    175         self.assertEqual(self.foo, None)
    176 
    177     def testExitThrows(self):
    178         class ExitThrows(object):
    179             def __enter__(self):
    180                 return
    181             def __exit__(self, *args):
    182                 raise RuntimeError(42)
    183         def shouldThrow():
    184             with ExitThrows():
    185                 pass
    186         self.assertRaises(RuntimeError, shouldThrow)
    187 
    188 class ContextmanagerAssertionMixin(object):
    189     TEST_EXCEPTION = RuntimeError("test exception")
    190 
    191     def assertInWithManagerInvariants(self, mock_manager):
    192         self.assertTrue(mock_manager.enter_called)
    193         self.assertFalse(mock_manager.exit_called)
    194         self.assertEqual(mock_manager.exit_args, None)
    195 
    196     def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
    197         self.assertTrue(mock_manager.enter_called)
    198         self.assertTrue(mock_manager.exit_called)
    199         self.assertEqual(mock_manager.exit_args, exit_args)
    200 
    201     def assertAfterWithManagerInvariantsNoError(self, mock_manager):
    202         self.assertAfterWithManagerInvariants(mock_manager,
    203             (None, None, None))
    204 
    205     def assertInWithGeneratorInvariants(self, mock_generator):
    206         self.assertTrue(mock_generator.yielded)
    207         self.assertFalse(mock_generator.stopped)
    208 
    209     def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
    210         self.assertTrue(mock_generator.yielded)
    211         self.assertTrue(mock_generator.stopped)
    212 
    213     def raiseTestException(self):
    214         raise self.TEST_EXCEPTION
    215 
    216     def assertAfterWithManagerInvariantsWithError(self, mock_manager,
    217                                                   exc_type=None):
    218         self.assertTrue(mock_manager.enter_called)
    219         self.assertTrue(mock_manager.exit_called)
    220         if exc_type is None:
    221             self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
    222             exc_type = type(self.TEST_EXCEPTION)
    223         self.assertEqual(mock_manager.exit_args[0], exc_type)
    224         # Test the __exit__ arguments. Issue #7853
    225         self.assertIsInstance(mock_manager.exit_args[1], exc_type)
    226         self.assertIsNot(mock_manager.exit_args[2], None)
    227 
    228     def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
    229         self.assertTrue(mock_generator.yielded)
    230         self.assertTrue(mock_generator.stopped)
    231 
    232 
    233 class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
    234     def testInlineGeneratorSyntax(self):
    235         with mock_contextmanager_generator():
    236             pass
    237 
    238     def testUnboundGenerator(self):
    239         mock = mock_contextmanager_generator()
    240         with mock:
    241             pass
    242         self.assertAfterWithManagerInvariantsNoError(mock)
    243 
    244     def testInlineGeneratorBoundSyntax(self):
    245         with mock_contextmanager_generator() as foo:
    246             self.assertInWithGeneratorInvariants(foo)
    247         # FIXME: In the future, we'll try to keep the bound names from leaking
    248         self.assertAfterWithGeneratorInvariantsNoError(foo)
    249 
    250     def testInlineGeneratorBoundToExistingVariable(self):
    251         foo = None
    252         with mock_contextmanager_generator() as foo:
    253             self.assertInWithGeneratorInvariants(foo)
    254         self.assertAfterWithGeneratorInvariantsNoError(foo)
    255 
    256     def testInlineGeneratorBoundToDottedVariable(self):
    257         with mock_contextmanager_generator() as self.foo:
    258             self.assertInWithGeneratorInvariants(self.foo)
    259         self.assertAfterWithGeneratorInvariantsNoError(self.foo)
    260 
    261     def testBoundGenerator(self):
    262         mock = mock_contextmanager_generator()
    263         with mock as foo:
    264             self.assertInWithGeneratorInvariants(foo)
    265             self.assertInWithManagerInvariants(mock)
    266         self.assertAfterWithGeneratorInvariantsNoError(foo)
    267         self.assertAfterWithManagerInvariantsNoError(mock)
    268 
    269     def testNestedSingleStatements(self):
    270         mock_a = mock_contextmanager_generator()
    271         with mock_a as foo:
    272             mock_b = mock_contextmanager_generator()
    273             with mock_b as bar:
    274                 self.assertInWithManagerInvariants(mock_a)
    275                 self.assertInWithManagerInvariants(mock_b)
    276                 self.assertInWithGeneratorInvariants(foo)
    277                 self.assertInWithGeneratorInvariants(bar)
    278             self.assertAfterWithManagerInvariantsNoError(mock_b)
    279             self.assertAfterWithGeneratorInvariantsNoError(bar)
    280             self.assertInWithManagerInvariants(mock_a)
    281             self.assertInWithGeneratorInvariants(foo)
    282         self.assertAfterWithManagerInvariantsNoError(mock_a)
    283         self.assertAfterWithGeneratorInvariantsNoError(foo)
    284 
    285 
    286 class NestedNonexceptionalTestCase(unittest.TestCase,
    287     ContextmanagerAssertionMixin):
    288     def testSingleArgInlineGeneratorSyntax(self):
    289         with Nested(mock_contextmanager_generator()):
    290             pass
    291 
    292     def testSingleArgBoundToNonTuple(self):
    293         m = mock_contextmanager_generator()
    294         # This will bind all the arguments to nested() into a single list
    295         # assigned to foo.
    296         with Nested(m) as foo:
    297             self.assertInWithManagerInvariants(m)
    298         self.assertAfterWithManagerInvariantsNoError(m)
    299 
    300     def testSingleArgBoundToSingleElementParenthesizedList(self):
    301         m = mock_contextmanager_generator()
    302         # This will bind all the arguments to nested() into a single list
    303         # assigned to foo.
    304         with Nested(m) as (foo):
    305             self.assertInWithManagerInvariants(m)
    306         self.assertAfterWithManagerInvariantsNoError(m)
    307 
    308     def testSingleArgBoundToMultipleElementTupleError(self):
    309         def shouldThrowValueError():
    310             with Nested(mock_contextmanager_generator()) as (foo, bar):
    311                 pass
    312         self.assertRaises(ValueError, shouldThrowValueError)
    313 
    314     def testSingleArgUnbound(self):
    315         mock_contextmanager = mock_contextmanager_generator()
    316         mock_nested = MockNested(mock_contextmanager)
    317         with mock_nested:
    318             self.assertInWithManagerInvariants(mock_contextmanager)
    319             self.assertInWithManagerInvariants(mock_nested)
    320         self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
    321         self.assertAfterWithManagerInvariantsNoError(mock_nested)
    322 
    323     def testMultipleArgUnbound(self):
    324         m = mock_contextmanager_generator()
    325         n = mock_contextmanager_generator()
    326         o = mock_contextmanager_generator()
    327         mock_nested = MockNested(m, n, o)
    328         with mock_nested:
    329             self.assertInWithManagerInvariants(m)
    330             self.assertInWithManagerInvariants(n)
    331             self.assertInWithManagerInvariants(o)
    332             self.assertInWithManagerInvariants(mock_nested)
    333         self.assertAfterWithManagerInvariantsNoError(m)
    334         self.assertAfterWithManagerInvariantsNoError(n)
    335         self.assertAfterWithManagerInvariantsNoError(o)
    336         self.assertAfterWithManagerInvariantsNoError(mock_nested)
    337 
    338     def testMultipleArgBound(self):
    339         mock_nested = MockNested(mock_contextmanager_generator(),
    340             mock_contextmanager_generator(), mock_contextmanager_generator())
    341         with mock_nested as (m, n, o):
    342             self.assertInWithGeneratorInvariants(m)
    343             self.assertInWithGeneratorInvariants(n)
    344             self.assertInWithGeneratorInvariants(o)
    345             self.assertInWithManagerInvariants(mock_nested)
    346         self.assertAfterWithGeneratorInvariantsNoError(m)
    347         self.assertAfterWithGeneratorInvariantsNoError(n)
    348         self.assertAfterWithGeneratorInvariantsNoError(o)
    349         self.assertAfterWithManagerInvariantsNoError(mock_nested)
    350 
    351 
    352 class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
    353     def testSingleResource(self):
    354         cm = mock_contextmanager_generator()
    355         def shouldThrow():
    356             with cm as self.resource:
    357                 self.assertInWithManagerInvariants(cm)
    358                 self.assertInWithGeneratorInvariants(self.resource)
    359                 self.raiseTestException()
    360         self.assertRaises(RuntimeError, shouldThrow)
    361         self.assertAfterWithManagerInvariantsWithError(cm)
    362         self.assertAfterWithGeneratorInvariantsWithError(self.resource)
    363 
    364     def testExceptionNormalized(self):
    365         cm = mock_contextmanager_generator()
    366         def shouldThrow():
    367             with cm as self.resource:
    368                 # Note this relies on the fact that 1 // 0 produces an exception
    369                 # that is not normalized immediately.
    370                 1 // 0
    371         self.assertRaises(ZeroDivisionError, shouldThrow)
    372         self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
    373 
    374     def testNestedSingleStatements(self):
    375         mock_a = mock_contextmanager_generator()
    376         mock_b = mock_contextmanager_generator()
    377         def shouldThrow():
    378             with mock_a as self.foo:
    379                 with mock_b as self.bar:
    380                     self.assertInWithManagerInvariants(mock_a)
    381                     self.assertInWithManagerInvariants(mock_b)
    382                     self.assertInWithGeneratorInvariants(self.foo)
    383                     self.assertInWithGeneratorInvariants(self.bar)
    384                     self.raiseTestException()
    385         self.assertRaises(RuntimeError, shouldThrow)
    386         self.assertAfterWithManagerInvariantsWithError(mock_a)
    387         self.assertAfterWithManagerInvariantsWithError(mock_b)
    388         self.assertAfterWithGeneratorInvariantsWithError(self.foo)
    389         self.assertAfterWithGeneratorInvariantsWithError(self.bar)
    390 
    391     def testMultipleResourcesInSingleStatement(self):
    392         cm_a = mock_contextmanager_generator()
    393         cm_b = mock_contextmanager_generator()
    394         mock_nested = MockNested(cm_a, cm_b)
    395         def shouldThrow():
    396             with mock_nested as (self.resource_a, self.resource_b):
    397                 self.assertInWithManagerInvariants(cm_a)
    398                 self.assertInWithManagerInvariants(cm_b)
    399                 self.assertInWithManagerInvariants(mock_nested)
    400                 self.assertInWithGeneratorInvariants(self.resource_a)
    401                 self.assertInWithGeneratorInvariants(self.resource_b)
    402                 self.raiseTestException()
    403         self.assertRaises(RuntimeError, shouldThrow)
    404         self.assertAfterWithManagerInvariantsWithError(cm_a)
    405         self.assertAfterWithManagerInvariantsWithError(cm_b)
    406         self.assertAfterWithManagerInvariantsWithError(mock_nested)
    407         self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
    408         self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
    409 
    410     def testNestedExceptionBeforeInnerStatement(self):
    411         mock_a = mock_contextmanager_generator()
    412         mock_b = mock_contextmanager_generator()
    413         self.bar = None
    414         def shouldThrow():
    415             with mock_a as self.foo:
    416                 self.assertInWithManagerInvariants(mock_a)
    417                 self.assertInWithGeneratorInvariants(self.foo)
    418                 self.raiseTestException()
    419                 with mock_b as self.bar:
    420                     pass
    421         self.assertRaises(RuntimeError, shouldThrow)
    422         self.assertAfterWithManagerInvariantsWithError(mock_a)
    423         self.assertAfterWithGeneratorInvariantsWithError(self.foo)
    424 
    425         # The inner statement stuff should never have been touched
    426         self.assertEqual(self.bar, None)
    427         self.assertFalse(mock_b.enter_called)
    428         self.assertFalse(mock_b.exit_called)
    429         self.assertEqual(mock_b.exit_args, None)
    430 
    431     def testNestedExceptionAfterInnerStatement(self):
    432         mock_a = mock_contextmanager_generator()
    433         mock_b = mock_contextmanager_generator()
    434         def shouldThrow():
    435             with mock_a as self.foo:
    436                 with mock_b as self.bar:
    437                     self.assertInWithManagerInvariants(mock_a)
    438                     self.assertInWithManagerInvariants(mock_b)
    439                     self.assertInWithGeneratorInvariants(self.foo)
    440                     self.assertInWithGeneratorInvariants(self.bar)
    441                 self.raiseTestException()
    442         self.assertRaises(RuntimeError, shouldThrow)
    443         self.assertAfterWithManagerInvariantsWithError(mock_a)
    444         self.assertAfterWithManagerInvariantsNoError(mock_b)
    445         self.assertAfterWithGeneratorInvariantsWithError(self.foo)
    446         self.assertAfterWithGeneratorInvariantsNoError(self.bar)
    447 
    448     def testRaisedStopIteration1(self):
    449         # From bug 1462485
    450         @contextmanager
    451         def cm():
    452             yield
    453 
    454         def shouldThrow():
    455             with cm():
    456                 raise StopIteration("from with")
    457 
    458         self.assertRaises(StopIteration, shouldThrow)
    459 
    460     def testRaisedStopIteration2(self):
    461         # From bug 1462485
    462         class cm(object):
    463             def __enter__(self):
    464                 pass
    465             def __exit__(self, type, value, traceback):
    466                 pass
    467 
    468         def shouldThrow():
    469             with cm():
    470                 raise StopIteration("from with")
    471 
    472         self.assertRaises(StopIteration, shouldThrow)
    473 
    474     def testRaisedStopIteration3(self):
    475         # Another variant where the exception hasn't been instantiated
    476         # From bug 1705170
    477         @contextmanager
    478         def cm():
    479             yield
    480 
    481         def shouldThrow():
    482             with cm():
    483                 raise iter([]).next()
    484 
    485         self.assertRaises(StopIteration, shouldThrow)
    486 
    487     def testRaisedGeneratorExit1(self):
    488         # From bug 1462485
    489         @contextmanager
    490         def cm():
    491             yield
    492 
    493         def shouldThrow():
    494             with cm():
    495                 raise GeneratorExit("from with")
    496 
    497         self.assertRaises(GeneratorExit, shouldThrow)
    498 
    499     def testRaisedGeneratorExit2(self):
    500         # From bug 1462485
    501         class cm (object):
    502             def __enter__(self):
    503                 pass
    504             def __exit__(self, type, value, traceback):
    505                 pass
    506 
    507         def shouldThrow():
    508             with cm():
    509                 raise GeneratorExit("from with")
    510 
    511         self.assertRaises(GeneratorExit, shouldThrow)
    512 
    513     def testErrorsInBool(self):
    514         # issue4589: __exit__ return code may raise an exception
    515         # when looking at its truth value.
    516 
    517         class cm(object):
    518             def __init__(self, bool_conversion):
    519                 class Bool:
    520                     def __nonzero__(self):
    521                         return bool_conversion()
    522                 self.exit_result = Bool()
    523             def __enter__(self):
    524                 return 3
    525             def __exit__(self, a, b, c):
    526                 return self.exit_result
    527 
    528         def trueAsBool():
    529             with cm(lambda: True):
    530                 self.fail("Should NOT see this")
    531         trueAsBool()
    532 
    533         def falseAsBool():
    534             with cm(lambda: False):
    535                 self.fail("Should raise")
    536         self.assertRaises(AssertionError, falseAsBool)
    537 
    538         def failAsBool():
    539             with cm(lambda: 1 // 0):
    540                 self.fail("Should NOT see this")
    541         self.assertRaises(ZeroDivisionError, failAsBool)
    542 
    543 
    544 class NonLocalFlowControlTestCase(unittest.TestCase):
    545 
    546     def testWithBreak(self):
    547         counter = 0
    548         while True:
    549             counter += 1
    550             with mock_contextmanager_generator():
    551                 counter += 10
    552                 break
    553             counter += 100 # Not reached
    554         self.assertEqual(counter, 11)
    555 
    556     def testWithContinue(self):
    557         counter = 0
    558         while True:
    559             counter += 1
    560             if counter > 2:
    561                 break
    562             with mock_contextmanager_generator():
    563                 counter += 10
    564                 continue
    565             counter += 100 # Not reached
    566         self.assertEqual(counter, 12)
    567 
    568     def testWithReturn(self):
    569         def foo():
    570             counter = 0
    571             while True:
    572                 counter += 1
    573                 with mock_contextmanager_generator():
    574                     counter += 10
    575                     return counter
    576                 counter += 100 # Not reached
    577         self.assertEqual(foo(), 11)
    578 
    579     def testWithYield(self):
    580         def gen():
    581             with mock_contextmanager_generator():
    582                 yield 12
    583                 yield 13
    584         x = list(gen())
    585         self.assertEqual(x, [12, 13])
    586 
    587     def testWithRaise(self):
    588         counter = 0
    589         try:
    590             counter += 1
    591             with mock_contextmanager_generator():
    592                 counter += 10
    593                 raise RuntimeError
    594             counter += 100 # Not reached
    595         except RuntimeError:
    596             self.assertEqual(counter, 11)
    597         else:
    598             self.fail("Didn't raise RuntimeError")
    599 
    600 
    601 class AssignmentTargetTestCase(unittest.TestCase):
    602 
    603     def testSingleComplexTarget(self):
    604         targets = {1: [0, 1, 2]}
    605         with mock_contextmanager_generator() as targets[1][0]:
    606             self.assertEqual(targets.keys(), [1])
    607             self.assertEqual(targets[1][0].__class__, MockResource)
    608         with mock_contextmanager_generator() as targets.values()[0][1]:
    609             self.assertEqual(targets.keys(), [1])
    610             self.assertEqual(targets[1][1].__class__, MockResource)
    611         with mock_contextmanager_generator() as targets[2]:
    612             keys = targets.keys()
    613             keys.sort()
    614             self.assertEqual(keys, [1, 2])
    615         class C: pass
    616         blah = C()
    617         with mock_contextmanager_generator() as blah.foo:
    618             self.assertEqual(hasattr(blah, "foo"), True)
    619 
    620     def testMultipleComplexTargets(self):
    621         class C:
    622             def __enter__(self): return 1, 2, 3
    623             def __exit__(self, t, v, tb): pass
    624         targets = {1: [0, 1, 2]}
    625         with C() as (targets[1][0], targets[1][1], targets[1][2]):
    626             self.assertEqual(targets, {1: [1, 2, 3]})
    627         with C() as (targets.values()[0][2], targets.values()[0][1], targets.values()[0][0]):
    628             self.assertEqual(targets, {1: [3, 2, 1]})
    629         with C() as (targets[1], targets[2], targets[3]):
    630             self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
    631         class B: pass
    632         blah = B()
    633         with C() as (blah.one, blah.two, blah.three):
    634             self.assertEqual(blah.one, 1)
    635             self.assertEqual(blah.two, 2)
    636             self.assertEqual(blah.three, 3)
    637 
    638 
    639 class ExitSwallowsExceptionTestCase(unittest.TestCase):
    640 
    641     def testExitTrueSwallowsException(self):
    642         class AfricanSwallow:
    643             def __enter__(self): pass
    644             def __exit__(self, t, v, tb): return True
    645         try:
    646             with AfricanSwallow():
    647                 1 // 0
    648         except ZeroDivisionError:
    649             self.fail("ZeroDivisionError should have been swallowed")
    650 
    651     def testExitFalseDoesntSwallowException(self):
    652         class EuropeanSwallow:
    653             def __enter__(self): pass
    654             def __exit__(self, t, v, tb): return False
    655         try:
    656             with EuropeanSwallow():
    657                 1 // 0
    658         except ZeroDivisionError:
    659             pass
    660         else:
    661             self.fail("ZeroDivisionError should have been raised")
    662 
    663 
    664 class NestedWith(unittest.TestCase):
    665 
    666     class Dummy(object):
    667         def __init__(self, value=None, gobble=False):
    668             if value is None:
    669                 value = self
    670             self.value = value
    671             self.gobble = gobble
    672             self.enter_called = False
    673             self.exit_called = False
    674 
    675         def __enter__(self):
    676             self.enter_called = True
    677             return self.value
    678 
    679         def __exit__(self, *exc_info):
    680             self.exit_called = True
    681             self.exc_info = exc_info
    682             if self.gobble:
    683                 return True
    684 
    685     class InitRaises(object):
    686         def __init__(self): raise RuntimeError()
    687 
    688     class EnterRaises(object):
    689         def __enter__(self): raise RuntimeError()
    690         def __exit__(self, *exc_info): pass
    691 
    692     class ExitRaises(object):
    693         def __enter__(self): pass
    694         def __exit__(self, *exc_info): raise RuntimeError()
    695 
    696     def testNoExceptions(self):
    697         with self.Dummy() as a, self.Dummy() as b:
    698             self.assertTrue(a.enter_called)
    699             self.assertTrue(b.enter_called)
    700         self.assertTrue(a.exit_called)
    701         self.assertTrue(b.exit_called)
    702 
    703     def testExceptionInExprList(self):
    704         try:
    705             with self.Dummy() as a, self.InitRaises():
    706                 pass
    707         except:
    708             pass
    709         self.assertTrue(a.enter_called)
    710         self.assertTrue(a.exit_called)
    711 
    712     def testExceptionInEnter(self):
    713         try:
    714             with self.Dummy() as a, self.EnterRaises():
    715                 self.fail('body of bad with executed')
    716         except RuntimeError:
    717             pass
    718         else:
    719             self.fail('RuntimeError not reraised')
    720         self.assertTrue(a.enter_called)
    721         self.assertTrue(a.exit_called)
    722 
    723     def testExceptionInExit(self):
    724         body_executed = False
    725         with self.Dummy(gobble=True) as a, self.ExitRaises():
    726             body_executed = True
    727         self.assertTrue(a.enter_called)
    728         self.assertTrue(a.exit_called)
    729         self.assertTrue(body_executed)
    730         self.assertNotEqual(a.exc_info[0], None)
    731 
    732     def testEnterReturnsTuple(self):
    733         with self.Dummy(value=(1,2)) as (a1, a2), \
    734              self.Dummy(value=(10, 20)) as (b1, b2):
    735             self.assertEqual(1, a1)
    736             self.assertEqual(2, a2)
    737             self.assertEqual(10, b1)
    738             self.assertEqual(20, b2)
    739 
    740 def test_main():
    741     run_unittest(FailureTestCase, NonexceptionalTestCase,
    742                  NestedNonexceptionalTestCase, ExceptionalTestCase,
    743                  NonLocalFlowControlTestCase,
    744                  AssignmentTargetTestCase,
    745                  ExitSwallowsExceptionTestCase,
    746                  NestedWith)
    747 
    748 
    749 if __name__ == '__main__':
    750     test_main()
    751