blob: f59032eed688c0ae0e395379c593b8ed29b26a22 [file] [log] [blame]
Tim Peters400cbc32006-02-28 18:44:41 +00001#!/usr/bin/env python
2
3"""Unit tests for the with statement specified in PEP 343."""
4
Thomas Wouters34aa7ba2006-02-28 19:02:24 +00005
Tim Peters400cbc32006-02-28 18:44:41 +00006__author__ = "Mike Bland"
7__email__ = "mbland at acm dot org"
8
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00009import sys
Tim Peters400cbc32006-02-28 18:44:41 +000010import unittest
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000011from collections import deque
12from contextlib import GeneratorContextManager, contextmanager
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test.support import run_unittest
Tim Peters400cbc32006-02-28 18:44:41 +000014
15
16class MockContextManager(GeneratorContextManager):
17 def __init__(self, gen):
18 GeneratorContextManager.__init__(self, gen)
Tim Peters400cbc32006-02-28 18:44:41 +000019 self.enter_called = False
20 self.exit_called = False
21 self.exit_args = None
22
Tim Peters400cbc32006-02-28 18:44:41 +000023 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)
Thomas Wouters477c8d52006-05-27 19:21:47 +000030 return GeneratorContextManager.__exit__(self, type,
31 value, traceback)
Tim Peters400cbc32006-02-28 18:44:41 +000032
33
34def mock_contextmanager(func):
35 def helper(*args, **kwds):
36 return MockContextManager(func(*args, **kwds))
37 return helper
38
39
40class MockResource(object):
41 def __init__(self):
42 self.yielded = False
43 self.stopped = False
44
45
46@mock_contextmanager
47def mock_contextmanager_generator():
48 mock = MockResource()
49 try:
50 mock.yielded = True
51 yield mock
52 finally:
53 mock.stopped = True
54
55
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000056class Nested(object):
57
Thomas Wouters477c8d52006-05-27 19:21:47 +000058 def __init__(self, *managers):
59 self.managers = managers
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000060 self.entered = None
61
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000062 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:
Thomas Wouters477c8d52006-05-27 19:21:47 +000068 for mgr in self.managers:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000069 vars.append(mgr.__enter__())
70 self.entered.appendleft(mgr)
71 except:
Guido van Rossumf6694362006-03-10 02:28:35 +000072 if not self.__exit__(*sys.exc_info()):
73 raise
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000074 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:
Guido van Rossumf6694362006-03-10 02:28:35 +000083 if mgr.__exit__(*ex):
84 ex = (None, None, None)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000085 except:
86 ex = sys.exc_info()
87 self.entered = None
88 if ex is not exc_info:
Collin Winter828f04a2007-08-31 00:04:24 +000089 raise ex[0](ex[1]).with_traceback(ex[2])
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000090
91
92class MockNested(Nested):
Thomas Wouters477c8d52006-05-27 19:21:47 +000093 def __init__(self, *managers):
94 Nested.__init__(self, *managers)
Tim Peters400cbc32006-02-28 18:44:41 +000095 self.enter_called = False
96 self.exit_called = False
97 self.exit_args = None
98
Tim Peters400cbc32006-02-28 18:44:41 +000099 def __enter__(self):
100 self.enter_called = True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000101 return Nested.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +0000102
103 def __exit__(self, *exc_info):
104 self.exit_called = True
105 self.exit_args = exc_info
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000106 return Nested.__exit__(self, *exc_info)
Tim Peters400cbc32006-02-28 18:44:41 +0000107
108
109class FailureTestCase(unittest.TestCase):
110 def testNameError(self):
111 def fooNotDeclared():
112 with foo: pass
113 self.assertRaises(NameError, fooNotDeclared)
114
Tim Peters400cbc32006-02-28 18:44:41 +0000115 def testEnterAttributeError(self):
116 class LacksEnter(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000117 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):
Tim Peters400cbc32006-02-28 18:44:41 +0000127 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
Tim Peters400cbc32006-02-28 18:44:41 +0000162 def testEnterThrows(self):
163 class EnterThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000164 def __enter__(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000165 raise RuntimeError("Enter threw")
Tim Peters400cbc32006-02-28 18:44:41 +0000166 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):
Tim Peters400cbc32006-02-28 18:44:41 +0000179 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
188class ContextmanagerAssertionMixin(object):
Collin Winterba21f612007-09-01 20:29:04 +0000189
190 def setUp(self):
191 self.TEST_EXCEPTION = RuntimeError("test exception")
Tim Peters400cbc32006-02-28 18:44:41 +0000192
193 def assertInWithManagerInvariants(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000194 self.assertTrue(mock_manager.enter_called)
195 self.assertFalse(mock_manager.exit_called)
196 self.assertEqual(mock_manager.exit_args, None)
197
198 def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
Tim Peters400cbc32006-02-28 18:44:41 +0000199 self.assertTrue(mock_manager.enter_called)
200 self.assertTrue(mock_manager.exit_called)
201 self.assertEqual(mock_manager.exit_args, exit_args)
202
203 def assertAfterWithManagerInvariantsNoError(self, mock_manager):
204 self.assertAfterWithManagerInvariants(mock_manager,
205 (None, None, None))
206
207 def assertInWithGeneratorInvariants(self, mock_generator):
208 self.assertTrue(mock_generator.yielded)
209 self.assertFalse(mock_generator.stopped)
210
211 def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
212 self.assertTrue(mock_generator.yielded)
213 self.assertTrue(mock_generator.stopped)
214
215 def raiseTestException(self):
216 raise self.TEST_EXCEPTION
217
218 def assertAfterWithManagerInvariantsWithError(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000219 self.assertTrue(mock_manager.enter_called)
220 self.assertTrue(mock_manager.exit_called)
221 self.assertEqual(mock_manager.exit_args[0], RuntimeError)
222 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
223
224 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
225 self.assertTrue(mock_generator.yielded)
226 self.assertTrue(mock_generator.stopped)
227
228
229class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
230 def testInlineGeneratorSyntax(self):
231 with mock_contextmanager_generator():
232 pass
233
234 def testUnboundGenerator(self):
235 mock = mock_contextmanager_generator()
236 with mock:
237 pass
238 self.assertAfterWithManagerInvariantsNoError(mock)
239
240 def testInlineGeneratorBoundSyntax(self):
241 with mock_contextmanager_generator() as foo:
242 self.assertInWithGeneratorInvariants(foo)
243 # FIXME: In the future, we'll try to keep the bound names from leaking
244 self.assertAfterWithGeneratorInvariantsNoError(foo)
245
246 def testInlineGeneratorBoundToExistingVariable(self):
247 foo = None
248 with mock_contextmanager_generator() as foo:
249 self.assertInWithGeneratorInvariants(foo)
250 self.assertAfterWithGeneratorInvariantsNoError(foo)
251
252 def testInlineGeneratorBoundToDottedVariable(self):
253 with mock_contextmanager_generator() as self.foo:
254 self.assertInWithGeneratorInvariants(self.foo)
255 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
256
257 def testBoundGenerator(self):
258 mock = mock_contextmanager_generator()
259 with mock as foo:
260 self.assertInWithGeneratorInvariants(foo)
261 self.assertInWithManagerInvariants(mock)
262 self.assertAfterWithGeneratorInvariantsNoError(foo)
263 self.assertAfterWithManagerInvariantsNoError(mock)
264
265 def testNestedSingleStatements(self):
266 mock_a = mock_contextmanager_generator()
267 with mock_a as foo:
268 mock_b = mock_contextmanager_generator()
269 with mock_b as bar:
270 self.assertInWithManagerInvariants(mock_a)
271 self.assertInWithManagerInvariants(mock_b)
272 self.assertInWithGeneratorInvariants(foo)
273 self.assertInWithGeneratorInvariants(bar)
274 self.assertAfterWithManagerInvariantsNoError(mock_b)
275 self.assertAfterWithGeneratorInvariantsNoError(bar)
276 self.assertInWithManagerInvariants(mock_a)
277 self.assertInWithGeneratorInvariants(foo)
278 self.assertAfterWithManagerInvariantsNoError(mock_a)
279 self.assertAfterWithGeneratorInvariantsNoError(foo)
280
281
282class NestedNonexceptionalTestCase(unittest.TestCase,
283 ContextmanagerAssertionMixin):
284 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000285 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000286 pass
287
Tim Peters400cbc32006-02-28 18:44:41 +0000288 def testSingleArgBoundToNonTuple(self):
289 m = mock_contextmanager_generator()
290 # This will bind all the arguments to nested() into a single list
291 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000292 with Nested(m) as foo:
Tim Peters400cbc32006-02-28 18:44:41 +0000293 self.assertInWithManagerInvariants(m)
294 self.assertAfterWithManagerInvariantsNoError(m)
295
296 def testSingleArgBoundToSingleElementParenthesizedList(self):
297 m = mock_contextmanager_generator()
298 # This will bind all the arguments to nested() into a single list
299 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000300 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000301 self.assertInWithManagerInvariants(m)
302 self.assertAfterWithManagerInvariantsNoError(m)
303
304 def testSingleArgBoundToMultipleElementTupleError(self):
305 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000306 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000307 pass
308 self.assertRaises(ValueError, shouldThrowValueError)
309
310 def testSingleArgUnbound(self):
311 mock_contextmanager = mock_contextmanager_generator()
312 mock_nested = MockNested(mock_contextmanager)
313 with mock_nested:
314 self.assertInWithManagerInvariants(mock_contextmanager)
315 self.assertInWithManagerInvariants(mock_nested)
316 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
317 self.assertAfterWithManagerInvariantsNoError(mock_nested)
318
319 def testMultipleArgUnbound(self):
320 m = mock_contextmanager_generator()
321 n = mock_contextmanager_generator()
322 o = mock_contextmanager_generator()
323 mock_nested = MockNested(m, n, o)
324 with mock_nested:
325 self.assertInWithManagerInvariants(m)
326 self.assertInWithManagerInvariants(n)
327 self.assertInWithManagerInvariants(o)
328 self.assertInWithManagerInvariants(mock_nested)
329 self.assertAfterWithManagerInvariantsNoError(m)
330 self.assertAfterWithManagerInvariantsNoError(n)
331 self.assertAfterWithManagerInvariantsNoError(o)
332 self.assertAfterWithManagerInvariantsNoError(mock_nested)
333
334 def testMultipleArgBound(self):
335 mock_nested = MockNested(mock_contextmanager_generator(),
336 mock_contextmanager_generator(), mock_contextmanager_generator())
337 with mock_nested as (m, n, o):
338 self.assertInWithGeneratorInvariants(m)
339 self.assertInWithGeneratorInvariants(n)
340 self.assertInWithGeneratorInvariants(o)
341 self.assertInWithManagerInvariants(mock_nested)
342 self.assertAfterWithGeneratorInvariantsNoError(m)
343 self.assertAfterWithGeneratorInvariantsNoError(n)
344 self.assertAfterWithGeneratorInvariantsNoError(o)
345 self.assertAfterWithManagerInvariantsNoError(mock_nested)
346
347
Collin Winterba21f612007-09-01 20:29:04 +0000348class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
Tim Peters400cbc32006-02-28 18:44:41 +0000349 def testSingleResource(self):
350 cm = mock_contextmanager_generator()
351 def shouldThrow():
352 with cm as self.resource:
353 self.assertInWithManagerInvariants(cm)
354 self.assertInWithGeneratorInvariants(self.resource)
355 self.raiseTestException()
356 self.assertRaises(RuntimeError, shouldThrow)
357 self.assertAfterWithManagerInvariantsWithError(cm)
358 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
359
360 def testNestedSingleStatements(self):
361 mock_a = mock_contextmanager_generator()
362 mock_b = mock_contextmanager_generator()
363 def shouldThrow():
364 with mock_a as self.foo:
365 with mock_b as self.bar:
366 self.assertInWithManagerInvariants(mock_a)
367 self.assertInWithManagerInvariants(mock_b)
368 self.assertInWithGeneratorInvariants(self.foo)
369 self.assertInWithGeneratorInvariants(self.bar)
370 self.raiseTestException()
371 self.assertRaises(RuntimeError, shouldThrow)
372 self.assertAfterWithManagerInvariantsWithError(mock_a)
373 self.assertAfterWithManagerInvariantsWithError(mock_b)
374 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
375 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
376
377 def testMultipleResourcesInSingleStatement(self):
378 cm_a = mock_contextmanager_generator()
379 cm_b = mock_contextmanager_generator()
380 mock_nested = MockNested(cm_a, cm_b)
381 def shouldThrow():
382 with mock_nested as (self.resource_a, self.resource_b):
383 self.assertInWithManagerInvariants(cm_a)
384 self.assertInWithManagerInvariants(cm_b)
385 self.assertInWithManagerInvariants(mock_nested)
386 self.assertInWithGeneratorInvariants(self.resource_a)
387 self.assertInWithGeneratorInvariants(self.resource_b)
388 self.raiseTestException()
389 self.assertRaises(RuntimeError, shouldThrow)
390 self.assertAfterWithManagerInvariantsWithError(cm_a)
391 self.assertAfterWithManagerInvariantsWithError(cm_b)
392 self.assertAfterWithManagerInvariantsWithError(mock_nested)
393 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
394 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
395
396 def testNestedExceptionBeforeInnerStatement(self):
397 mock_a = mock_contextmanager_generator()
398 mock_b = mock_contextmanager_generator()
399 self.bar = None
400 def shouldThrow():
401 with mock_a as self.foo:
402 self.assertInWithManagerInvariants(mock_a)
403 self.assertInWithGeneratorInvariants(self.foo)
404 self.raiseTestException()
405 with mock_b as self.bar:
406 pass
407 self.assertRaises(RuntimeError, shouldThrow)
408 self.assertAfterWithManagerInvariantsWithError(mock_a)
409 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
410
411 # The inner statement stuff should never have been touched
412 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000413 self.assertFalse(mock_b.enter_called)
414 self.assertFalse(mock_b.exit_called)
415 self.assertEqual(mock_b.exit_args, None)
416
417 def testNestedExceptionAfterInnerStatement(self):
418 mock_a = mock_contextmanager_generator()
419 mock_b = mock_contextmanager_generator()
420 def shouldThrow():
421 with mock_a as self.foo:
422 with mock_b as self.bar:
423 self.assertInWithManagerInvariants(mock_a)
424 self.assertInWithManagerInvariants(mock_b)
425 self.assertInWithGeneratorInvariants(self.foo)
426 self.assertInWithGeneratorInvariants(self.bar)
427 self.raiseTestException()
428 self.assertRaises(RuntimeError, shouldThrow)
429 self.assertAfterWithManagerInvariantsWithError(mock_a)
430 self.assertAfterWithManagerInvariantsNoError(mock_b)
431 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
432 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
433
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000434 def testRaisedStopIteration1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000435 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000436 @contextmanager
437 def cm():
438 yield
439
440 def shouldThrow():
441 with cm():
442 raise StopIteration("from with")
443
444 self.assertRaises(StopIteration, shouldThrow)
445
446 def testRaisedStopIteration2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000447 # From bug 1462485
Thomas Wouters477c8d52006-05-27 19:21:47 +0000448 class cm(object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000449 def __enter__(self):
450 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000451 def __exit__(self, type, value, traceback):
452 pass
453
454 def shouldThrow():
455 with cm():
456 raise StopIteration("from with")
457
458 self.assertRaises(StopIteration, shouldThrow)
459
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000460 def testRaisedStopIteration3(self):
461 # Another variant where the exception hasn't been instantiated
462 # From bug 1705170
463 @contextmanager
464 def cm():
465 yield
466
467 def shouldThrow():
468 with cm():
469 raise next(iter([]))
470
471 self.assertRaises(StopIteration, shouldThrow)
472
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000473 def testRaisedGeneratorExit1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000474 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000475 @contextmanager
476 def cm():
477 yield
478
479 def shouldThrow():
480 with cm():
481 raise GeneratorExit("from with")
482
483 self.assertRaises(GeneratorExit, shouldThrow)
484
485 def testRaisedGeneratorExit2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000486 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000487 class cm (object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000488 def __enter__(self):
489 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000490 def __exit__(self, type, value, traceback):
491 pass
492
493 def shouldThrow():
494 with cm():
495 raise GeneratorExit("from with")
496
497 self.assertRaises(GeneratorExit, shouldThrow)
498
Amaury Forgeot d'Arc10b24e82008-12-10 23:49:33 +0000499 def testErrorsInBool(self):
500 # issue4589: __exit__ return code may raise an exception
501 # when looking at its truth value.
502
503 class cm(object):
504 def __init__(self, bool_conversion):
505 class Bool:
506 def __bool__(self):
507 return bool_conversion()
508 self.exit_result = Bool()
509 def __enter__(self):
510 return 3
511 def __exit__(self, a, b, c):
512 return self.exit_result
513
514 def trueAsBool():
515 with cm(lambda: True):
516 self.fail("Should NOT see this")
517 trueAsBool()
518
519 def falseAsBool():
520 with cm(lambda: False):
521 self.fail("Should raise")
522 self.assertRaises(AssertionError, falseAsBool)
523
524 def failAsBool():
525 with cm(lambda: 1//0):
526 self.fail("Should NOT see this")
527 self.assertRaises(ZeroDivisionError, failAsBool)
528
Tim Peters400cbc32006-02-28 18:44:41 +0000529
530class NonLocalFlowControlTestCase(unittest.TestCase):
531
532 def testWithBreak(self):
533 counter = 0
534 while True:
535 counter += 1
536 with mock_contextmanager_generator():
537 counter += 10
538 break
539 counter += 100 # Not reached
540 self.assertEqual(counter, 11)
541
542 def testWithContinue(self):
543 counter = 0
544 while True:
545 counter += 1
546 if counter > 2:
547 break
548 with mock_contextmanager_generator():
549 counter += 10
550 continue
551 counter += 100 # Not reached
552 self.assertEqual(counter, 12)
553
554 def testWithReturn(self):
555 def foo():
556 counter = 0
557 while True:
558 counter += 1
559 with mock_contextmanager_generator():
560 counter += 10
561 return counter
562 counter += 100 # Not reached
563 self.assertEqual(foo(), 11)
564
565 def testWithYield(self):
566 def gen():
567 with mock_contextmanager_generator():
568 yield 12
569 yield 13
570 x = list(gen())
571 self.assertEqual(x, [12, 13])
572
573 def testWithRaise(self):
574 counter = 0
575 try:
576 counter += 1
577 with mock_contextmanager_generator():
578 counter += 10
579 raise RuntimeError
580 counter += 100 # Not reached
581 except RuntimeError:
582 self.assertEqual(counter, 11)
583 else:
584 self.fail("Didn't raise RuntimeError")
585
586
587class AssignmentTargetTestCase(unittest.TestCase):
588
589 def testSingleComplexTarget(self):
590 targets = {1: [0, 1, 2]}
591 with mock_contextmanager_generator() as targets[1][0]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000592 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000593 self.assertEqual(targets[1][0].__class__, MockResource)
Guido van Rossum87b63952007-02-11 07:05:21 +0000594 with mock_contextmanager_generator() as list(targets.values())[0][1]:
595 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000596 self.assertEqual(targets[1][1].__class__, MockResource)
597 with mock_contextmanager_generator() as targets[2]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000598 keys = list(targets.keys())
Tim Peters400cbc32006-02-28 18:44:41 +0000599 keys.sort()
600 self.assertEqual(keys, [1, 2])
601 class C: pass
602 blah = C()
603 with mock_contextmanager_generator() as blah.foo:
604 self.assertEqual(hasattr(blah, "foo"), True)
605
606 def testMultipleComplexTargets(self):
607 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000608 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000609 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000610 targets = {1: [0, 1, 2]}
611 with C() as (targets[1][0], targets[1][1], targets[1][2]):
612 self.assertEqual(targets, {1: [1, 2, 3]})
Guido van Rossum87b63952007-02-11 07:05:21 +0000613 with C() as (list(targets.values())[0][2], list(targets.values())[0][1], list(targets.values())[0][0]):
Tim Peters400cbc32006-02-28 18:44:41 +0000614 self.assertEqual(targets, {1: [3, 2, 1]})
615 with C() as (targets[1], targets[2], targets[3]):
616 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
617 class B: pass
618 blah = B()
619 with C() as (blah.one, blah.two, blah.three):
620 self.assertEqual(blah.one, 1)
621 self.assertEqual(blah.two, 2)
622 self.assertEqual(blah.three, 3)
623
624
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000625class ExitSwallowsExceptionTestCase(unittest.TestCase):
626
Guido van Rossumf6694362006-03-10 02:28:35 +0000627 def testExitTrueSwallowsException(self):
628 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000629 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000630 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000631 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000632 with AfricanSwallow():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000633 1/0
634 except ZeroDivisionError:
635 self.fail("ZeroDivisionError should have been swallowed")
636
Guido van Rossumf6694362006-03-10 02:28:35 +0000637 def testExitFalseDoesntSwallowException(self):
638 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000639 def __enter__(self): pass
640 def __exit__(self, t, v, tb): return False
641 try:
642 with EuropeanSwallow():
643 1/0
644 except ZeroDivisionError:
645 pass
646 else:
647 self.fail("ZeroDivisionError should have been raised")
648
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000649
Georg Brandl0c315622009-05-25 21:10:36 +0000650class NestedWith(unittest.TestCase):
651
652 class Dummy(object):
653 def __init__(self, value=None, gobble=False):
654 if value is None:
655 value = self
656 self.value = value
657 self.gobble = gobble
658 self.enter_called = False
659 self.exit_called = False
660
661 def __enter__(self):
662 self.enter_called = True
663 return self.value
664
665 def __exit__(self, *exc_info):
666 self.exit_called = True
667 self.exc_info = exc_info
668 if self.gobble:
669 return True
670
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000671 class InitRaises(object):
Georg Brandl0c315622009-05-25 21:10:36 +0000672 def __init__(self): raise RuntimeError()
673
674 class EnterRaises(object):
675 def __enter__(self): raise RuntimeError()
676 def __exit__(self, *exc_info): pass
677
678 class ExitRaises(object):
679 def __enter__(self): pass
680 def __exit__(self, *exc_info): raise RuntimeError()
681
682 def testNoExceptions(self):
683 with self.Dummy() as a, self.Dummy() as b:
684 self.assertTrue(a.enter_called)
685 self.assertTrue(b.enter_called)
686 self.assertTrue(a.exit_called)
687 self.assertTrue(b.exit_called)
688
689 def testExceptionInExprList(self):
690 try:
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000691 with self.Dummy() as a, self.InitRaises():
Georg Brandl0c315622009-05-25 21:10:36 +0000692 pass
693 except:
694 pass
695 self.assertTrue(a.enter_called)
696 self.assertTrue(a.exit_called)
697
698 def testExceptionInEnter(self):
699 try:
700 with self.Dummy() as a, self.EnterRaises():
701 self.fail('body of bad with executed')
702 except RuntimeError:
703 pass
704 else:
705 self.fail('RuntimeError not reraised')
706 self.assertTrue(a.enter_called)
707 self.assertTrue(a.exit_called)
708
709 def testExceptionInExit(self):
710 body_executed = False
711 with self.Dummy(gobble=True) as a, self.ExitRaises():
712 body_executed = True
713 self.assertTrue(a.enter_called)
714 self.assertTrue(a.exit_called)
Benjamin Peterson78565b22009-06-28 19:19:51 +0000715 self.assertTrue(body_executed)
Georg Brandl0c315622009-05-25 21:10:36 +0000716 self.assertNotEqual(a.exc_info[0], None)
717
718 def testEnterReturnsTuple(self):
719 with self.Dummy(value=(1,2)) as (a1, a2), \
720 self.Dummy(value=(10, 20)) as (b1, b2):
721 self.assertEquals(1, a1)
722 self.assertEquals(2, a2)
723 self.assertEquals(10, b1)
724 self.assertEquals(20, b2)
725
Tim Peters400cbc32006-02-28 18:44:41 +0000726def test_main():
727 run_unittest(FailureTestCase, NonexceptionalTestCase,
728 NestedNonexceptionalTestCase, ExceptionalTestCase,
729 NonLocalFlowControlTestCase,
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000730 AssignmentTargetTestCase,
Georg Brandl0c315622009-05-25 21:10:36 +0000731 ExitSwallowsExceptionTestCase,
732 NestedWith)
Tim Peters400cbc32006-02-28 18:44:41 +0000733
734
735if __name__ == '__main__':
736 test_main()