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