blob: e7dd001b53924a41122b5b99e49677a3f490df3c [file] [log] [blame]
Tim Peters400cbc32006-02-28 18:44:41 +00001"""Unit tests for the with statement specified in PEP 343."""
2
Thomas Wouters34aa7ba2006-02-28 19:02:24 +00003
Tim Peters400cbc32006-02-28 18:44:41 +00004__author__ = "Mike Bland"
5__email__ = "mbland at acm dot org"
6
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00007import sys
Tim Peters400cbc32006-02-28 18:44:41 +00008import unittest
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00009from collections import deque
Nick Coghlanafd5e632006-05-03 13:02:47 +000010from contextlib import GeneratorContextManager, contextmanager
Tim Peters400cbc32006-02-28 18:44:41 +000011from test.test_support import run_unittest
12
13
Nick Coghlanafd5e632006-05-03 13:02:47 +000014class MockContextManager(GeneratorContextManager):
Tim Peters400cbc32006-02-28 18:44:41 +000015 def __init__(self, gen):
Nick Coghlanafd5e632006-05-03 13:02:47 +000016 GeneratorContextManager.__init__(self, gen)
Tim Peters400cbc32006-02-28 18:44:41 +000017 self.enter_called = False
18 self.exit_called = False
19 self.exit_args = None
20
Tim Peters400cbc32006-02-28 18:44:41 +000021 def __enter__(self):
22 self.enter_called = True
Nick Coghlanafd5e632006-05-03 13:02:47 +000023 return GeneratorContextManager.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +000024
25 def __exit__(self, type, value, traceback):
26 self.exit_called = True
27 self.exit_args = (type, value, traceback)
Nick Coghlanafd5e632006-05-03 13:02:47 +000028 return GeneratorContextManager.__exit__(self, type,
29 value, traceback)
Tim Peters400cbc32006-02-28 18:44:41 +000030
31
32def mock_contextmanager(func):
33 def helper(*args, **kwds):
34 return MockContextManager(func(*args, **kwds))
35 return helper
36
37
38class MockResource(object):
39 def __init__(self):
40 self.yielded = False
41 self.stopped = False
42
43
44@mock_contextmanager
45def mock_contextmanager_generator():
46 mock = MockResource()
47 try:
48 mock.yielded = True
49 yield mock
50 finally:
51 mock.stopped = True
52
53
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000054class Nested(object):
55
Guido van Rossumda5b7012006-05-02 19:47:52 +000056 def __init__(self, *managers):
57 self.managers = managers
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000058 self.entered = None
59
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000060 def __enter__(self):
61 if self.entered is not None:
62 raise RuntimeError("Context is not reentrant")
63 self.entered = deque()
64 vars = []
65 try:
Guido van Rossumda5b7012006-05-02 19:47:52 +000066 for mgr in self.managers:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000067 vars.append(mgr.__enter__())
68 self.entered.appendleft(mgr)
69 except:
Guido van Rossumf6694362006-03-10 02:28:35 +000070 if not self.__exit__(*sys.exc_info()):
71 raise
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000072 return vars
73
74 def __exit__(self, *exc_info):
75 # Behave like nested with statements
76 # first in, last out
77 # New exceptions override old ones
78 ex = exc_info
79 for mgr in self.entered:
80 try:
Guido van Rossumf6694362006-03-10 02:28:35 +000081 if mgr.__exit__(*ex):
82 ex = (None, None, None)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000083 except:
84 ex = sys.exc_info()
85 self.entered = None
86 if ex is not exc_info:
87 raise ex[0], ex[1], ex[2]
88
89
90class MockNested(Nested):
Guido van Rossumda5b7012006-05-02 19:47:52 +000091 def __init__(self, *managers):
92 Nested.__init__(self, *managers)
Tim Peters400cbc32006-02-28 18:44:41 +000093 self.enter_called = False
94 self.exit_called = False
95 self.exit_args = None
96
Tim Peters400cbc32006-02-28 18:44:41 +000097 def __enter__(self):
98 self.enter_called = True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000099 return Nested.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +0000100
101 def __exit__(self, *exc_info):
102 self.exit_called = True
103 self.exit_args = exc_info
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000104 return Nested.__exit__(self, *exc_info)
Tim Peters400cbc32006-02-28 18:44:41 +0000105
106
107class FailureTestCase(unittest.TestCase):
108 def testNameError(self):
109 def fooNotDeclared():
110 with foo: pass
111 self.assertRaises(NameError, fooNotDeclared)
112
Tim Peters400cbc32006-02-28 18:44:41 +0000113 def testEnterAttributeError(self):
114 class LacksEnter(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000115 def __exit__(self, type, value, traceback):
116 pass
117
118 def fooLacksEnter():
119 foo = LacksEnter()
120 with foo: pass
121 self.assertRaises(AttributeError, fooLacksEnter)
122
123 def testExitAttributeError(self):
124 class LacksExit(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000125 def __enter__(self):
126 pass
127
128 def fooLacksExit():
129 foo = LacksExit()
130 with foo: pass
131 self.assertRaises(AttributeError, fooLacksExit)
132
133 def assertRaisesSyntaxError(self, codestr):
134 def shouldRaiseSyntaxError(s):
135 compile(s, '', 'single')
136 self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr)
137
138 def testAssignmentToNoneError(self):
139 self.assertRaisesSyntaxError('with mock as None:\n pass')
140 self.assertRaisesSyntaxError(
141 'with mock as (None):\n'
142 ' pass')
143
144 def testAssignmentToEmptyTupleError(self):
145 self.assertRaisesSyntaxError(
146 'with mock as ():\n'
147 ' pass')
148
149 def testAssignmentToTupleOnlyContainingNoneError(self):
150 self.assertRaisesSyntaxError('with mock as None,:\n pass')
151 self.assertRaisesSyntaxError(
152 'with mock as (None,):\n'
153 ' pass')
154
155 def testAssignmentToTupleContainingNoneError(self):
156 self.assertRaisesSyntaxError(
157 'with mock as (foo, None, bar):\n'
158 ' pass')
159
Tim Peters400cbc32006-02-28 18:44:41 +0000160 def testEnterThrows(self):
161 class EnterThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000162 def __enter__(self):
Guido van Rossumda5b7012006-05-02 19:47:52 +0000163 raise RuntimeError("Enter threw")
Tim Peters400cbc32006-02-28 18:44:41 +0000164 def __exit__(self, *args):
165 pass
166
167 def shouldThrow():
168 ct = EnterThrows()
169 self.foo = None
170 with ct as self.foo:
171 pass
172 self.assertRaises(RuntimeError, shouldThrow)
173 self.assertEqual(self.foo, None)
174
175 def testExitThrows(self):
176 class ExitThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000177 def __enter__(self):
178 return
179 def __exit__(self, *args):
180 raise RuntimeError(42)
181 def shouldThrow():
182 with ExitThrows():
183 pass
184 self.assertRaises(RuntimeError, shouldThrow)
185
186class ContextmanagerAssertionMixin(object):
187 TEST_EXCEPTION = RuntimeError("test exception")
188
189 def assertInWithManagerInvariants(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000190 self.assertTrue(mock_manager.enter_called)
191 self.assertFalse(mock_manager.exit_called)
192 self.assertEqual(mock_manager.exit_args, None)
193
194 def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
Tim Peters400cbc32006-02-28 18:44:41 +0000195 self.assertTrue(mock_manager.enter_called)
196 self.assertTrue(mock_manager.exit_called)
197 self.assertEqual(mock_manager.exit_args, exit_args)
198
199 def assertAfterWithManagerInvariantsNoError(self, mock_manager):
200 self.assertAfterWithManagerInvariants(mock_manager,
201 (None, None, None))
202
203 def assertInWithGeneratorInvariants(self, mock_generator):
204 self.assertTrue(mock_generator.yielded)
205 self.assertFalse(mock_generator.stopped)
206
207 def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
208 self.assertTrue(mock_generator.yielded)
209 self.assertTrue(mock_generator.stopped)
210
211 def raiseTestException(self):
212 raise self.TEST_EXCEPTION
213
Benjamin Peterson4a7ff1d2010-02-05 01:53:27 +0000214 def assertAfterWithManagerInvariantsWithError(self, mock_manager,
215 exc_type=None):
Tim Peters400cbc32006-02-28 18:44:41 +0000216 self.assertTrue(mock_manager.enter_called)
217 self.assertTrue(mock_manager.exit_called)
Benjamin Peterson4a7ff1d2010-02-05 01:53:27 +0000218 if exc_type is None:
219 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
220 exc_type = type(self.TEST_EXCEPTION)
221 self.assertEqual(mock_manager.exit_args[0], exc_type)
222 # Test the __exit__ arguments. Issue #7853
223 self.assertIsInstance(mock_manager.exit_args[1], exc_type)
224 self.assertIsNot(mock_manager.exit_args[2], None)
Tim Peters400cbc32006-02-28 18:44:41 +0000225
226 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
227 self.assertTrue(mock_generator.yielded)
228 self.assertTrue(mock_generator.stopped)
229
230
231class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
232 def testInlineGeneratorSyntax(self):
233 with mock_contextmanager_generator():
234 pass
235
236 def testUnboundGenerator(self):
237 mock = mock_contextmanager_generator()
238 with mock:
239 pass
240 self.assertAfterWithManagerInvariantsNoError(mock)
241
242 def testInlineGeneratorBoundSyntax(self):
243 with mock_contextmanager_generator() as foo:
244 self.assertInWithGeneratorInvariants(foo)
245 # FIXME: In the future, we'll try to keep the bound names from leaking
246 self.assertAfterWithGeneratorInvariantsNoError(foo)
247
248 def testInlineGeneratorBoundToExistingVariable(self):
249 foo = None
250 with mock_contextmanager_generator() as foo:
251 self.assertInWithGeneratorInvariants(foo)
252 self.assertAfterWithGeneratorInvariantsNoError(foo)
253
254 def testInlineGeneratorBoundToDottedVariable(self):
255 with mock_contextmanager_generator() as self.foo:
256 self.assertInWithGeneratorInvariants(self.foo)
257 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
258
259 def testBoundGenerator(self):
260 mock = mock_contextmanager_generator()
261 with mock as foo:
262 self.assertInWithGeneratorInvariants(foo)
263 self.assertInWithManagerInvariants(mock)
264 self.assertAfterWithGeneratorInvariantsNoError(foo)
265 self.assertAfterWithManagerInvariantsNoError(mock)
266
267 def testNestedSingleStatements(self):
268 mock_a = mock_contextmanager_generator()
269 with mock_a as foo:
270 mock_b = mock_contextmanager_generator()
271 with mock_b as bar:
272 self.assertInWithManagerInvariants(mock_a)
273 self.assertInWithManagerInvariants(mock_b)
274 self.assertInWithGeneratorInvariants(foo)
275 self.assertInWithGeneratorInvariants(bar)
276 self.assertAfterWithManagerInvariantsNoError(mock_b)
277 self.assertAfterWithGeneratorInvariantsNoError(bar)
278 self.assertInWithManagerInvariants(mock_a)
279 self.assertInWithGeneratorInvariants(foo)
280 self.assertAfterWithManagerInvariantsNoError(mock_a)
281 self.assertAfterWithGeneratorInvariantsNoError(foo)
282
283
284class NestedNonexceptionalTestCase(unittest.TestCase,
285 ContextmanagerAssertionMixin):
286 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000287 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000288 pass
289
Tim Peters400cbc32006-02-28 18:44:41 +0000290 def testSingleArgBoundToNonTuple(self):
291 m = mock_contextmanager_generator()
292 # This will bind all the arguments to nested() into a single list
293 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000294 with Nested(m) as foo:
Tim Peters400cbc32006-02-28 18:44:41 +0000295 self.assertInWithManagerInvariants(m)
296 self.assertAfterWithManagerInvariantsNoError(m)
297
298 def testSingleArgBoundToSingleElementParenthesizedList(self):
299 m = mock_contextmanager_generator()
300 # This will bind all the arguments to nested() into a single list
301 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000302 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000303 self.assertInWithManagerInvariants(m)
304 self.assertAfterWithManagerInvariantsNoError(m)
305
306 def testSingleArgBoundToMultipleElementTupleError(self):
307 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000308 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000309 pass
310 self.assertRaises(ValueError, shouldThrowValueError)
311
312 def testSingleArgUnbound(self):
313 mock_contextmanager = mock_contextmanager_generator()
314 mock_nested = MockNested(mock_contextmanager)
315 with mock_nested:
316 self.assertInWithManagerInvariants(mock_contextmanager)
317 self.assertInWithManagerInvariants(mock_nested)
318 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
319 self.assertAfterWithManagerInvariantsNoError(mock_nested)
320
321 def testMultipleArgUnbound(self):
322 m = mock_contextmanager_generator()
323 n = mock_contextmanager_generator()
324 o = mock_contextmanager_generator()
325 mock_nested = MockNested(m, n, o)
326 with mock_nested:
327 self.assertInWithManagerInvariants(m)
328 self.assertInWithManagerInvariants(n)
329 self.assertInWithManagerInvariants(o)
330 self.assertInWithManagerInvariants(mock_nested)
331 self.assertAfterWithManagerInvariantsNoError(m)
332 self.assertAfterWithManagerInvariantsNoError(n)
333 self.assertAfterWithManagerInvariantsNoError(o)
334 self.assertAfterWithManagerInvariantsNoError(mock_nested)
335
336 def testMultipleArgBound(self):
337 mock_nested = MockNested(mock_contextmanager_generator(),
338 mock_contextmanager_generator(), mock_contextmanager_generator())
339 with mock_nested as (m, n, o):
340 self.assertInWithGeneratorInvariants(m)
341 self.assertInWithGeneratorInvariants(n)
342 self.assertInWithGeneratorInvariants(o)
343 self.assertInWithManagerInvariants(mock_nested)
344 self.assertAfterWithGeneratorInvariantsNoError(m)
345 self.assertAfterWithGeneratorInvariantsNoError(n)
346 self.assertAfterWithGeneratorInvariantsNoError(o)
347 self.assertAfterWithManagerInvariantsNoError(mock_nested)
348
349
350class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
351 def testSingleResource(self):
352 cm = mock_contextmanager_generator()
353 def shouldThrow():
354 with cm as self.resource:
355 self.assertInWithManagerInvariants(cm)
356 self.assertInWithGeneratorInvariants(self.resource)
357 self.raiseTestException()
358 self.assertRaises(RuntimeError, shouldThrow)
359 self.assertAfterWithManagerInvariantsWithError(cm)
360 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
361
Benjamin Peterson4a7ff1d2010-02-05 01:53:27 +0000362 def testExceptionNormalized(self):
363 cm = mock_contextmanager_generator()
364 def shouldThrow():
365 with cm as self.resource:
366 # Note this relies on the fact that 1 // 0 produces an exception
367 # that is not normalized immediately.
368 1 // 0
369 self.assertRaises(ZeroDivisionError, shouldThrow)
370 self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
371
Tim Peters400cbc32006-02-28 18:44:41 +0000372 def testNestedSingleStatements(self):
373 mock_a = mock_contextmanager_generator()
374 mock_b = mock_contextmanager_generator()
375 def shouldThrow():
376 with mock_a as self.foo:
377 with mock_b as self.bar:
378 self.assertInWithManagerInvariants(mock_a)
379 self.assertInWithManagerInvariants(mock_b)
380 self.assertInWithGeneratorInvariants(self.foo)
381 self.assertInWithGeneratorInvariants(self.bar)
382 self.raiseTestException()
383 self.assertRaises(RuntimeError, shouldThrow)
384 self.assertAfterWithManagerInvariantsWithError(mock_a)
385 self.assertAfterWithManagerInvariantsWithError(mock_b)
386 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
387 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
388
389 def testMultipleResourcesInSingleStatement(self):
390 cm_a = mock_contextmanager_generator()
391 cm_b = mock_contextmanager_generator()
392 mock_nested = MockNested(cm_a, cm_b)
393 def shouldThrow():
394 with mock_nested as (self.resource_a, self.resource_b):
395 self.assertInWithManagerInvariants(cm_a)
396 self.assertInWithManagerInvariants(cm_b)
397 self.assertInWithManagerInvariants(mock_nested)
398 self.assertInWithGeneratorInvariants(self.resource_a)
399 self.assertInWithGeneratorInvariants(self.resource_b)
400 self.raiseTestException()
401 self.assertRaises(RuntimeError, shouldThrow)
402 self.assertAfterWithManagerInvariantsWithError(cm_a)
403 self.assertAfterWithManagerInvariantsWithError(cm_b)
404 self.assertAfterWithManagerInvariantsWithError(mock_nested)
405 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
406 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
407
408 def testNestedExceptionBeforeInnerStatement(self):
409 mock_a = mock_contextmanager_generator()
410 mock_b = mock_contextmanager_generator()
411 self.bar = None
412 def shouldThrow():
413 with mock_a as self.foo:
414 self.assertInWithManagerInvariants(mock_a)
415 self.assertInWithGeneratorInvariants(self.foo)
416 self.raiseTestException()
417 with mock_b as self.bar:
418 pass
419 self.assertRaises(RuntimeError, shouldThrow)
420 self.assertAfterWithManagerInvariantsWithError(mock_a)
421 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
422
423 # The inner statement stuff should never have been touched
424 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000425 self.assertFalse(mock_b.enter_called)
426 self.assertFalse(mock_b.exit_called)
427 self.assertEqual(mock_b.exit_args, None)
428
429 def testNestedExceptionAfterInnerStatement(self):
430 mock_a = mock_contextmanager_generator()
431 mock_b = mock_contextmanager_generator()
432 def shouldThrow():
433 with mock_a as self.foo:
434 with mock_b as self.bar:
435 self.assertInWithManagerInvariants(mock_a)
436 self.assertInWithManagerInvariants(mock_b)
437 self.assertInWithGeneratorInvariants(self.foo)
438 self.assertInWithGeneratorInvariants(self.bar)
439 self.raiseTestException()
440 self.assertRaises(RuntimeError, shouldThrow)
441 self.assertAfterWithManagerInvariantsWithError(mock_a)
442 self.assertAfterWithManagerInvariantsNoError(mock_b)
443 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
444 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
445
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000446 def testRaisedStopIteration1(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000447 # From bug 1462485
Nick Coghlanafd5e632006-05-03 13:02:47 +0000448 @contextmanager
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000449 def cm():
450 yield
451
452 def shouldThrow():
453 with cm():
454 raise StopIteration("from with")
455
456 self.assertRaises(StopIteration, shouldThrow)
457
458 def testRaisedStopIteration2(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000459 # From bug 1462485
Guido van Rossumda5b7012006-05-02 19:47:52 +0000460 class cm(object):
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000461 def __enter__(self):
462 pass
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000463 def __exit__(self, type, value, traceback):
464 pass
465
466 def shouldThrow():
467 with cm():
468 raise StopIteration("from with")
469
470 self.assertRaises(StopIteration, shouldThrow)
471
Nick Coghlan3814a912007-11-02 10:09:12 +0000472 def testRaisedStopIteration3(self):
473 # Another variant where the exception hasn't been instantiated
474 # From bug 1705170
475 @contextmanager
476 def cm():
477 yield
478
479 def shouldThrow():
480 with cm():
481 raise iter([]).next()
482
483 self.assertRaises(StopIteration, shouldThrow)
484
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000485 def testRaisedGeneratorExit1(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000486 # From bug 1462485
Nick Coghlanafd5e632006-05-03 13:02:47 +0000487 @contextmanager
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000488 def cm():
489 yield
490
491 def shouldThrow():
492 with cm():
493 raise GeneratorExit("from with")
494
495 self.assertRaises(GeneratorExit, shouldThrow)
496
497 def testRaisedGeneratorExit2(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000498 # From bug 1462485
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000499 class cm (object):
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000500 def __enter__(self):
501 pass
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000502 def __exit__(self, type, value, traceback):
503 pass
504
505 def shouldThrow():
506 with cm():
507 raise GeneratorExit("from with")
508
509 self.assertRaises(GeneratorExit, shouldThrow)
510
Amaury Forgeot d'Arcad9b5992008-12-10 23:22:49 +0000511 def testErrorsInBool(self):
512 # issue4589: __exit__ return code may raise an exception
513 # when looking at its truth value.
514
515 class cm(object):
516 def __init__(self, bool_conversion):
517 class Bool:
518 def __nonzero__(self):
519 return bool_conversion()
520 self.exit_result = Bool()
521 def __enter__(self):
522 return 3
523 def __exit__(self, a, b, c):
524 return self.exit_result
525
526 def trueAsBool():
527 with cm(lambda: True):
528 self.fail("Should NOT see this")
529 trueAsBool()
530
531 def falseAsBool():
532 with cm(lambda: False):
533 self.fail("Should raise")
534 self.assertRaises(AssertionError, falseAsBool)
535
536 def failAsBool():
Ezio Melottidde5b942010-02-03 05:37:26 +0000537 with cm(lambda: 1 // 0):
Amaury Forgeot d'Arcad9b5992008-12-10 23:22:49 +0000538 self.fail("Should NOT see this")
539 self.assertRaises(ZeroDivisionError, failAsBool)
540
Tim Peters400cbc32006-02-28 18:44:41 +0000541
542class NonLocalFlowControlTestCase(unittest.TestCase):
543
544 def testWithBreak(self):
545 counter = 0
546 while True:
547 counter += 1
548 with mock_contextmanager_generator():
549 counter += 10
550 break
551 counter += 100 # Not reached
552 self.assertEqual(counter, 11)
553
554 def testWithContinue(self):
555 counter = 0
556 while True:
557 counter += 1
558 if counter > 2:
559 break
560 with mock_contextmanager_generator():
561 counter += 10
562 continue
563 counter += 100 # Not reached
564 self.assertEqual(counter, 12)
565
566 def testWithReturn(self):
567 def foo():
568 counter = 0
569 while True:
570 counter += 1
571 with mock_contextmanager_generator():
572 counter += 10
573 return counter
574 counter += 100 # Not reached
575 self.assertEqual(foo(), 11)
576
577 def testWithYield(self):
578 def gen():
579 with mock_contextmanager_generator():
580 yield 12
581 yield 13
582 x = list(gen())
583 self.assertEqual(x, [12, 13])
584
585 def testWithRaise(self):
586 counter = 0
587 try:
588 counter += 1
589 with mock_contextmanager_generator():
590 counter += 10
591 raise RuntimeError
592 counter += 100 # Not reached
593 except RuntimeError:
594 self.assertEqual(counter, 11)
595 else:
596 self.fail("Didn't raise RuntimeError")
597
598
599class AssignmentTargetTestCase(unittest.TestCase):
600
601 def testSingleComplexTarget(self):
602 targets = {1: [0, 1, 2]}
603 with mock_contextmanager_generator() as targets[1][0]:
604 self.assertEqual(targets.keys(), [1])
605 self.assertEqual(targets[1][0].__class__, MockResource)
606 with mock_contextmanager_generator() as targets.values()[0][1]:
607 self.assertEqual(targets.keys(), [1])
608 self.assertEqual(targets[1][1].__class__, MockResource)
609 with mock_contextmanager_generator() as targets[2]:
610 keys = targets.keys()
611 keys.sort()
612 self.assertEqual(keys, [1, 2])
613 class C: pass
614 blah = C()
615 with mock_contextmanager_generator() as blah.foo:
616 self.assertEqual(hasattr(blah, "foo"), True)
617
618 def testMultipleComplexTargets(self):
619 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000620 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000621 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000622 targets = {1: [0, 1, 2]}
623 with C() as (targets[1][0], targets[1][1], targets[1][2]):
624 self.assertEqual(targets, {1: [1, 2, 3]})
625 with C() as (targets.values()[0][2], targets.values()[0][1], targets.values()[0][0]):
626 self.assertEqual(targets, {1: [3, 2, 1]})
627 with C() as (targets[1], targets[2], targets[3]):
628 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
629 class B: pass
630 blah = B()
631 with C() as (blah.one, blah.two, blah.three):
632 self.assertEqual(blah.one, 1)
633 self.assertEqual(blah.two, 2)
634 self.assertEqual(blah.three, 3)
635
636
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000637class ExitSwallowsExceptionTestCase(unittest.TestCase):
638
Guido van Rossumf6694362006-03-10 02:28:35 +0000639 def testExitTrueSwallowsException(self):
640 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000641 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000642 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000643 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000644 with AfricanSwallow():
Ezio Melottidde5b942010-02-03 05:37:26 +0000645 1 // 0
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000646 except ZeroDivisionError:
647 self.fail("ZeroDivisionError should have been swallowed")
648
Guido van Rossumf6694362006-03-10 02:28:35 +0000649 def testExitFalseDoesntSwallowException(self):
650 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000651 def __enter__(self): pass
652 def __exit__(self, t, v, tb): return False
653 try:
654 with EuropeanSwallow():
Ezio Melottidde5b942010-02-03 05:37:26 +0000655 1 // 0
Guido van Rossumf6694362006-03-10 02:28:35 +0000656 except ZeroDivisionError:
657 pass
658 else:
659 self.fail("ZeroDivisionError should have been raised")
660
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000661
Georg Brandl944f6842009-05-25 21:02:56 +0000662class NestedWith(unittest.TestCase):
663
664 class Dummy(object):
665 def __init__(self, value=None, gobble=False):
666 if value is None:
667 value = self
668 self.value = value
669 self.gobble = gobble
670 self.enter_called = False
671 self.exit_called = False
672
673 def __enter__(self):
674 self.enter_called = True
675 return self.value
676
677 def __exit__(self, *exc_info):
678 self.exit_called = True
679 self.exc_info = exc_info
680 if self.gobble:
681 return True
682
Georg Brandl46121e72009-06-04 10:10:41 +0000683 class InitRaises(object):
Georg Brandl944f6842009-05-25 21:02:56 +0000684 def __init__(self): raise RuntimeError()
685
686 class EnterRaises(object):
687 def __enter__(self): raise RuntimeError()
688 def __exit__(self, *exc_info): pass
689
690 class ExitRaises(object):
691 def __enter__(self): pass
692 def __exit__(self, *exc_info): raise RuntimeError()
693
694 def testNoExceptions(self):
695 with self.Dummy() as a, self.Dummy() as b:
696 self.assertTrue(a.enter_called)
697 self.assertTrue(b.enter_called)
698 self.assertTrue(a.exit_called)
699 self.assertTrue(b.exit_called)
700
701 def testExceptionInExprList(self):
702 try:
Georg Brandl46121e72009-06-04 10:10:41 +0000703 with self.Dummy() as a, self.InitRaises():
Georg Brandl944f6842009-05-25 21:02:56 +0000704 pass
705 except:
706 pass
707 self.assertTrue(a.enter_called)
708 self.assertTrue(a.exit_called)
709
710 def testExceptionInEnter(self):
711 try:
712 with self.Dummy() as a, self.EnterRaises():
713 self.fail('body of bad with executed')
714 except RuntimeError:
715 pass
716 else:
717 self.fail('RuntimeError not reraised')
718 self.assertTrue(a.enter_called)
719 self.assertTrue(a.exit_called)
720
721 def testExceptionInExit(self):
722 body_executed = False
723 with self.Dummy(gobble=True) as a, self.ExitRaises():
724 body_executed = True
725 self.assertTrue(a.enter_called)
726 self.assertTrue(a.exit_called)
Benjamin Peterson9c5e4112009-06-19 22:09:17 +0000727 self.assertTrue(body_executed)
Georg Brandl944f6842009-05-25 21:02:56 +0000728 self.assertNotEqual(a.exc_info[0], None)
729
730 def testEnterReturnsTuple(self):
731 with self.Dummy(value=(1,2)) as (a1, a2), \
732 self.Dummy(value=(10, 20)) as (b1, b2):
Ezio Melotti2623a372010-11-21 13:34:58 +0000733 self.assertEqual(1, a1)
734 self.assertEqual(2, a2)
735 self.assertEqual(10, b1)
736 self.assertEqual(20, b2)
Georg Brandl944f6842009-05-25 21:02:56 +0000737
Tim Peters400cbc32006-02-28 18:44:41 +0000738def test_main():
739 run_unittest(FailureTestCase, NonexceptionalTestCase,
740 NestedNonexceptionalTestCase, ExceptionalTestCase,
741 NonLocalFlowControlTestCase,
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000742 AssignmentTargetTestCase,
Georg Brandl944f6842009-05-25 21:02:56 +0000743 ExitSwallowsExceptionTestCase,
744 NestedWith)
Tim Peters400cbc32006-02-28 18:44:41 +0000745
746
747if __name__ == '__main__':
748 test_main()