blob: e8d789bc2cdf86740012f9be0726a2a9842c77c3 [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
Antoine Pitrou67b212e2011-01-08 09:55:31 +000010from contextlib import _GeneratorContextManager, contextmanager
Tim Peters400cbc32006-02-28 18:44:41 +000011
12
Antoine Pitrou67b212e2011-01-08 09:55:31 +000013class MockContextManager(_GeneratorContextManager):
Serhiy Storchaka101ff352015-06-28 17:06:07 +030014 def __init__(self, *args):
15 super().__init__(*args)
Tim Peters400cbc32006-02-28 18:44:41 +000016 self.enter_called = False
17 self.exit_called = False
18 self.exit_args = None
19
Tim Peters400cbc32006-02-28 18:44:41 +000020 def __enter__(self):
21 self.enter_called = True
Antoine Pitrou67b212e2011-01-08 09:55:31 +000022 return _GeneratorContextManager.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +000023
24 def __exit__(self, type, value, traceback):
25 self.exit_called = True
26 self.exit_args = (type, value, traceback)
Antoine Pitrou67b212e2011-01-08 09:55:31 +000027 return _GeneratorContextManager.__exit__(self, type,
28 value, traceback)
Tim Peters400cbc32006-02-28 18:44:41 +000029
30
31def mock_contextmanager(func):
32 def helper(*args, **kwds):
Serhiy Storchaka101ff352015-06-28 17:06:07 +030033 return MockContextManager(func, args, kwds)
Tim Peters400cbc32006-02-28 18:44:41 +000034 return helper
35
36
37class MockResource(object):
38 def __init__(self):
39 self.yielded = False
40 self.stopped = False
41
42
43@mock_contextmanager
44def mock_contextmanager_generator():
45 mock = MockResource()
46 try:
47 mock.yielded = True
48 yield mock
49 finally:
50 mock.stopped = True
51
52
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000053class Nested(object):
54
Thomas Wouters477c8d52006-05-27 19:21:47 +000055 def __init__(self, *managers):
56 self.managers = managers
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000057 self.entered = None
58
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000059 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:
Thomas Wouters477c8d52006-05-27 19:21:47 +000065 for mgr in self.managers:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000066 vars.append(mgr.__enter__())
67 self.entered.appendleft(mgr)
68 except:
Guido van Rossumf6694362006-03-10 02:28:35 +000069 if not self.__exit__(*sys.exc_info()):
70 raise
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000071 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:
Guido van Rossumf6694362006-03-10 02:28:35 +000080 if mgr.__exit__(*ex):
81 ex = (None, None, None)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000082 except:
83 ex = sys.exc_info()
84 self.entered = None
85 if ex is not exc_info:
Collin Winter828f04a2007-08-31 00:04:24 +000086 raise ex[0](ex[1]).with_traceback(ex[2])
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000087
88
89class MockNested(Nested):
Thomas Wouters477c8d52006-05-27 19:21:47 +000090 def __init__(self, *managers):
91 Nested.__init__(self, *managers)
Tim Peters400cbc32006-02-28 18:44:41 +000092 self.enter_called = False
93 self.exit_called = False
94 self.exit_args = None
95
Tim Peters400cbc32006-02-28 18:44:41 +000096 def __enter__(self):
97 self.enter_called = True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000098 return Nested.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +000099
100 def __exit__(self, *exc_info):
101 self.exit_called = True
102 self.exit_args = exc_info
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000103 return Nested.__exit__(self, *exc_info)
Tim Peters400cbc32006-02-28 18:44:41 +0000104
105
106class FailureTestCase(unittest.TestCase):
107 def testNameError(self):
108 def fooNotDeclared():
109 with foo: pass
110 self.assertRaises(NameError, fooNotDeclared)
111
Tim Peters400cbc32006-02-28 18:44:41 +0000112 def testEnterAttributeError(self):
113 class LacksEnter(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000114 def __exit__(self, type, value, traceback):
115 pass
116
117 def fooLacksEnter():
118 foo = LacksEnter()
119 with foo: pass
120 self.assertRaises(AttributeError, fooLacksEnter)
121
122 def testExitAttributeError(self):
123 class LacksExit(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000124 def __enter__(self):
125 pass
126
127 def fooLacksExit():
128 foo = LacksExit()
129 with foo: pass
130 self.assertRaises(AttributeError, fooLacksExit)
131
132 def assertRaisesSyntaxError(self, codestr):
133 def shouldRaiseSyntaxError(s):
134 compile(s, '', 'single')
135 self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr)
136
137 def testAssignmentToNoneError(self):
138 self.assertRaisesSyntaxError('with mock as None:\n pass')
139 self.assertRaisesSyntaxError(
140 'with mock as (None):\n'
141 ' pass')
142
143 def testAssignmentToEmptyTupleError(self):
144 self.assertRaisesSyntaxError(
145 'with mock as ():\n'
146 ' pass')
147
148 def testAssignmentToTupleOnlyContainingNoneError(self):
149 self.assertRaisesSyntaxError('with mock as None,:\n pass')
150 self.assertRaisesSyntaxError(
151 'with mock as (None,):\n'
152 ' pass')
153
154 def testAssignmentToTupleContainingNoneError(self):
155 self.assertRaisesSyntaxError(
156 'with mock as (foo, None, bar):\n'
157 ' pass')
158
Tim Peters400cbc32006-02-28 18:44:41 +0000159 def testEnterThrows(self):
160 class EnterThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000161 def __enter__(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000162 raise RuntimeError("Enter threw")
Tim Peters400cbc32006-02-28 18:44:41 +0000163 def __exit__(self, *args):
164 pass
165
166 def shouldThrow():
167 ct = EnterThrows()
168 self.foo = None
169 with ct as self.foo:
170 pass
171 self.assertRaises(RuntimeError, shouldThrow)
172 self.assertEqual(self.foo, None)
173
174 def testExitThrows(self):
175 class ExitThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000176 def __enter__(self):
177 return
178 def __exit__(self, *args):
179 raise RuntimeError(42)
180 def shouldThrow():
181 with ExitThrows():
182 pass
183 self.assertRaises(RuntimeError, shouldThrow)
184
185class ContextmanagerAssertionMixin(object):
Collin Winterba21f612007-09-01 20:29:04 +0000186
187 def setUp(self):
188 self.TEST_EXCEPTION = RuntimeError("test exception")
Tim Peters400cbc32006-02-28 18:44:41 +0000189
190 def assertInWithManagerInvariants(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000191 self.assertTrue(mock_manager.enter_called)
192 self.assertFalse(mock_manager.exit_called)
193 self.assertEqual(mock_manager.exit_args, None)
194
195 def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
Tim Peters400cbc32006-02-28 18:44:41 +0000196 self.assertTrue(mock_manager.enter_called)
197 self.assertTrue(mock_manager.exit_called)
198 self.assertEqual(mock_manager.exit_args, exit_args)
199
200 def assertAfterWithManagerInvariantsNoError(self, mock_manager):
201 self.assertAfterWithManagerInvariants(mock_manager,
202 (None, None, None))
203
204 def assertInWithGeneratorInvariants(self, mock_generator):
205 self.assertTrue(mock_generator.yielded)
206 self.assertFalse(mock_generator.stopped)
207
208 def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
209 self.assertTrue(mock_generator.yielded)
210 self.assertTrue(mock_generator.stopped)
211
212 def raiseTestException(self):
213 raise self.TEST_EXCEPTION
214
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000215 def assertAfterWithManagerInvariantsWithError(self, mock_manager,
216 exc_type=None):
Tim Peters400cbc32006-02-28 18:44:41 +0000217 self.assertTrue(mock_manager.enter_called)
218 self.assertTrue(mock_manager.exit_called)
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000219 if exc_type is None:
220 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
221 exc_type = type(self.TEST_EXCEPTION)
222 self.assertEqual(mock_manager.exit_args[0], exc_type)
223 # Test the __exit__ arguments. Issue #7853
224 self.assertIsInstance(mock_manager.exit_args[1], exc_type)
225 self.assertIsNot(mock_manager.exit_args[2], None)
Tim Peters400cbc32006-02-28 18:44:41 +0000226
227 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
228 self.assertTrue(mock_generator.yielded)
229 self.assertTrue(mock_generator.stopped)
230
231
232class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
233 def testInlineGeneratorSyntax(self):
234 with mock_contextmanager_generator():
235 pass
236
237 def testUnboundGenerator(self):
238 mock = mock_contextmanager_generator()
239 with mock:
240 pass
241 self.assertAfterWithManagerInvariantsNoError(mock)
242
243 def testInlineGeneratorBoundSyntax(self):
244 with mock_contextmanager_generator() as foo:
245 self.assertInWithGeneratorInvariants(foo)
246 # FIXME: In the future, we'll try to keep the bound names from leaking
247 self.assertAfterWithGeneratorInvariantsNoError(foo)
248
249 def testInlineGeneratorBoundToExistingVariable(self):
250 foo = None
251 with mock_contextmanager_generator() as foo:
252 self.assertInWithGeneratorInvariants(foo)
253 self.assertAfterWithGeneratorInvariantsNoError(foo)
254
255 def testInlineGeneratorBoundToDottedVariable(self):
256 with mock_contextmanager_generator() as self.foo:
257 self.assertInWithGeneratorInvariants(self.foo)
258 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
259
260 def testBoundGenerator(self):
261 mock = mock_contextmanager_generator()
262 with mock as foo:
263 self.assertInWithGeneratorInvariants(foo)
264 self.assertInWithManagerInvariants(mock)
265 self.assertAfterWithGeneratorInvariantsNoError(foo)
266 self.assertAfterWithManagerInvariantsNoError(mock)
267
268 def testNestedSingleStatements(self):
269 mock_a = mock_contextmanager_generator()
270 with mock_a as foo:
271 mock_b = mock_contextmanager_generator()
272 with mock_b as bar:
273 self.assertInWithManagerInvariants(mock_a)
274 self.assertInWithManagerInvariants(mock_b)
275 self.assertInWithGeneratorInvariants(foo)
276 self.assertInWithGeneratorInvariants(bar)
277 self.assertAfterWithManagerInvariantsNoError(mock_b)
278 self.assertAfterWithGeneratorInvariantsNoError(bar)
279 self.assertInWithManagerInvariants(mock_a)
280 self.assertInWithGeneratorInvariants(foo)
281 self.assertAfterWithManagerInvariantsNoError(mock_a)
282 self.assertAfterWithGeneratorInvariantsNoError(foo)
283
284
285class NestedNonexceptionalTestCase(unittest.TestCase,
286 ContextmanagerAssertionMixin):
287 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000288 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000289 pass
290
Tim Peters400cbc32006-02-28 18:44:41 +0000291 def testSingleArgBoundToNonTuple(self):
292 m = mock_contextmanager_generator()
293 # This will bind all the arguments to nested() into a single list
294 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000295 with Nested(m) as foo:
Tim Peters400cbc32006-02-28 18:44:41 +0000296 self.assertInWithManagerInvariants(m)
297 self.assertAfterWithManagerInvariantsNoError(m)
298
299 def testSingleArgBoundToSingleElementParenthesizedList(self):
300 m = mock_contextmanager_generator()
301 # This will bind all the arguments to nested() into a single list
302 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000303 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000304 self.assertInWithManagerInvariants(m)
305 self.assertAfterWithManagerInvariantsNoError(m)
306
307 def testSingleArgBoundToMultipleElementTupleError(self):
308 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000309 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000310 pass
311 self.assertRaises(ValueError, shouldThrowValueError)
312
313 def testSingleArgUnbound(self):
314 mock_contextmanager = mock_contextmanager_generator()
315 mock_nested = MockNested(mock_contextmanager)
316 with mock_nested:
317 self.assertInWithManagerInvariants(mock_contextmanager)
318 self.assertInWithManagerInvariants(mock_nested)
319 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
320 self.assertAfterWithManagerInvariantsNoError(mock_nested)
321
322 def testMultipleArgUnbound(self):
323 m = mock_contextmanager_generator()
324 n = mock_contextmanager_generator()
325 o = mock_contextmanager_generator()
326 mock_nested = MockNested(m, n, o)
327 with mock_nested:
328 self.assertInWithManagerInvariants(m)
329 self.assertInWithManagerInvariants(n)
330 self.assertInWithManagerInvariants(o)
331 self.assertInWithManagerInvariants(mock_nested)
332 self.assertAfterWithManagerInvariantsNoError(m)
333 self.assertAfterWithManagerInvariantsNoError(n)
334 self.assertAfterWithManagerInvariantsNoError(o)
335 self.assertAfterWithManagerInvariantsNoError(mock_nested)
336
337 def testMultipleArgBound(self):
338 mock_nested = MockNested(mock_contextmanager_generator(),
339 mock_contextmanager_generator(), mock_contextmanager_generator())
340 with mock_nested as (m, n, o):
341 self.assertInWithGeneratorInvariants(m)
342 self.assertInWithGeneratorInvariants(n)
343 self.assertInWithGeneratorInvariants(o)
344 self.assertInWithManagerInvariants(mock_nested)
345 self.assertAfterWithGeneratorInvariantsNoError(m)
346 self.assertAfterWithGeneratorInvariantsNoError(n)
347 self.assertAfterWithGeneratorInvariantsNoError(o)
348 self.assertAfterWithManagerInvariantsNoError(mock_nested)
349
350
Collin Winterba21f612007-09-01 20:29:04 +0000351class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
Tim Peters400cbc32006-02-28 18:44:41 +0000352 def testSingleResource(self):
353 cm = mock_contextmanager_generator()
354 def shouldThrow():
355 with cm as self.resource:
356 self.assertInWithManagerInvariants(cm)
357 self.assertInWithGeneratorInvariants(self.resource)
358 self.raiseTestException()
359 self.assertRaises(RuntimeError, shouldThrow)
360 self.assertAfterWithManagerInvariantsWithError(cm)
361 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
362
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000363 def testExceptionNormalized(self):
364 cm = mock_contextmanager_generator()
365 def shouldThrow():
366 with cm as self.resource:
367 # Note this relies on the fact that 1 // 0 produces an exception
368 # that is not normalized immediately.
369 1 // 0
370 self.assertRaises(ZeroDivisionError, shouldThrow)
371 self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
372
Tim Peters400cbc32006-02-28 18:44:41 +0000373 def testNestedSingleStatements(self):
374 mock_a = mock_contextmanager_generator()
375 mock_b = mock_contextmanager_generator()
376 def shouldThrow():
377 with mock_a as self.foo:
378 with mock_b as self.bar:
379 self.assertInWithManagerInvariants(mock_a)
380 self.assertInWithManagerInvariants(mock_b)
381 self.assertInWithGeneratorInvariants(self.foo)
382 self.assertInWithGeneratorInvariants(self.bar)
383 self.raiseTestException()
384 self.assertRaises(RuntimeError, shouldThrow)
385 self.assertAfterWithManagerInvariantsWithError(mock_a)
386 self.assertAfterWithManagerInvariantsWithError(mock_b)
387 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
388 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
389
390 def testMultipleResourcesInSingleStatement(self):
391 cm_a = mock_contextmanager_generator()
392 cm_b = mock_contextmanager_generator()
393 mock_nested = MockNested(cm_a, cm_b)
394 def shouldThrow():
395 with mock_nested as (self.resource_a, self.resource_b):
396 self.assertInWithManagerInvariants(cm_a)
397 self.assertInWithManagerInvariants(cm_b)
398 self.assertInWithManagerInvariants(mock_nested)
399 self.assertInWithGeneratorInvariants(self.resource_a)
400 self.assertInWithGeneratorInvariants(self.resource_b)
401 self.raiseTestException()
402 self.assertRaises(RuntimeError, shouldThrow)
403 self.assertAfterWithManagerInvariantsWithError(cm_a)
404 self.assertAfterWithManagerInvariantsWithError(cm_b)
405 self.assertAfterWithManagerInvariantsWithError(mock_nested)
406 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
407 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
408
409 def testNestedExceptionBeforeInnerStatement(self):
410 mock_a = mock_contextmanager_generator()
411 mock_b = mock_contextmanager_generator()
412 self.bar = None
413 def shouldThrow():
414 with mock_a as self.foo:
415 self.assertInWithManagerInvariants(mock_a)
416 self.assertInWithGeneratorInvariants(self.foo)
417 self.raiseTestException()
418 with mock_b as self.bar:
419 pass
420 self.assertRaises(RuntimeError, shouldThrow)
421 self.assertAfterWithManagerInvariantsWithError(mock_a)
422 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
423
424 # The inner statement stuff should never have been touched
425 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000426 self.assertFalse(mock_b.enter_called)
427 self.assertFalse(mock_b.exit_called)
428 self.assertEqual(mock_b.exit_args, None)
429
430 def testNestedExceptionAfterInnerStatement(self):
431 mock_a = mock_contextmanager_generator()
432 mock_b = mock_contextmanager_generator()
433 def shouldThrow():
434 with mock_a as self.foo:
435 with mock_b as self.bar:
436 self.assertInWithManagerInvariants(mock_a)
437 self.assertInWithManagerInvariants(mock_b)
438 self.assertInWithGeneratorInvariants(self.foo)
439 self.assertInWithGeneratorInvariants(self.bar)
440 self.raiseTestException()
441 self.assertRaises(RuntimeError, shouldThrow)
442 self.assertAfterWithManagerInvariantsWithError(mock_a)
443 self.assertAfterWithManagerInvariantsNoError(mock_b)
444 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
445 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
446
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000447 def testRaisedStopIteration1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000448 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000449 @contextmanager
450 def cm():
451 yield
452
453 def shouldThrow():
454 with cm():
455 raise StopIteration("from with")
456
Yury Selivanov68333392015-05-22 11:16:47 -0400457 with self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"):
458 self.assertRaises(StopIteration, shouldThrow)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000459
460 def testRaisedStopIteration2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000461 # From bug 1462485
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462 class cm(object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000463 def __enter__(self):
464 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000465 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
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000474 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 next(iter([]))
484
Yury Selivanov68333392015-05-22 11:16:47 -0400485 with self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"):
486 self.assertRaises(StopIteration, shouldThrow)
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000487
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000488 def testRaisedGeneratorExit1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000489 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000490 @contextmanager
491 def cm():
492 yield
493
494 def shouldThrow():
495 with cm():
496 raise GeneratorExit("from with")
497
498 self.assertRaises(GeneratorExit, shouldThrow)
499
500 def testRaisedGeneratorExit2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000501 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000502 class cm (object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000503 def __enter__(self):
504 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000505 def __exit__(self, type, value, traceback):
506 pass
507
508 def shouldThrow():
509 with cm():
510 raise GeneratorExit("from with")
511
512 self.assertRaises(GeneratorExit, shouldThrow)
513
Amaury Forgeot d'Arc10b24e82008-12-10 23:49:33 +0000514 def testErrorsInBool(self):
515 # issue4589: __exit__ return code may raise an exception
516 # when looking at its truth value.
517
518 class cm(object):
519 def __init__(self, bool_conversion):
520 class Bool:
521 def __bool__(self):
522 return bool_conversion()
523 self.exit_result = Bool()
524 def __enter__(self):
525 return 3
526 def __exit__(self, a, b, c):
527 return self.exit_result
528
529 def trueAsBool():
530 with cm(lambda: True):
531 self.fail("Should NOT see this")
532 trueAsBool()
533
534 def falseAsBool():
535 with cm(lambda: False):
536 self.fail("Should raise")
537 self.assertRaises(AssertionError, falseAsBool)
538
539 def failAsBool():
540 with cm(lambda: 1//0):
541 self.fail("Should NOT see this")
542 self.assertRaises(ZeroDivisionError, failAsBool)
543
Tim Peters400cbc32006-02-28 18:44:41 +0000544
545class NonLocalFlowControlTestCase(unittest.TestCase):
546
547 def testWithBreak(self):
548 counter = 0
549 while True:
550 counter += 1
551 with mock_contextmanager_generator():
552 counter += 10
553 break
554 counter += 100 # Not reached
555 self.assertEqual(counter, 11)
556
557 def testWithContinue(self):
558 counter = 0
559 while True:
560 counter += 1
561 if counter > 2:
562 break
563 with mock_contextmanager_generator():
564 counter += 10
565 continue
566 counter += 100 # Not reached
567 self.assertEqual(counter, 12)
568
569 def testWithReturn(self):
570 def foo():
571 counter = 0
572 while True:
573 counter += 1
574 with mock_contextmanager_generator():
575 counter += 10
576 return counter
577 counter += 100 # Not reached
578 self.assertEqual(foo(), 11)
579
580 def testWithYield(self):
581 def gen():
582 with mock_contextmanager_generator():
583 yield 12
584 yield 13
585 x = list(gen())
586 self.assertEqual(x, [12, 13])
587
588 def testWithRaise(self):
589 counter = 0
590 try:
591 counter += 1
592 with mock_contextmanager_generator():
593 counter += 10
594 raise RuntimeError
595 counter += 100 # Not reached
596 except RuntimeError:
597 self.assertEqual(counter, 11)
598 else:
599 self.fail("Didn't raise RuntimeError")
600
601
602class AssignmentTargetTestCase(unittest.TestCase):
603
604 def testSingleComplexTarget(self):
605 targets = {1: [0, 1, 2]}
606 with mock_contextmanager_generator() as targets[1][0]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000607 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000608 self.assertEqual(targets[1][0].__class__, MockResource)
Guido van Rossum87b63952007-02-11 07:05:21 +0000609 with mock_contextmanager_generator() as list(targets.values())[0][1]:
610 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000611 self.assertEqual(targets[1][1].__class__, MockResource)
612 with mock_contextmanager_generator() as targets[2]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000613 keys = list(targets.keys())
Tim Peters400cbc32006-02-28 18:44:41 +0000614 keys.sort()
615 self.assertEqual(keys, [1, 2])
616 class C: pass
617 blah = C()
618 with mock_contextmanager_generator() as blah.foo:
619 self.assertEqual(hasattr(blah, "foo"), True)
620
621 def testMultipleComplexTargets(self):
622 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000623 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000624 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000625 targets = {1: [0, 1, 2]}
626 with C() as (targets[1][0], targets[1][1], targets[1][2]):
627 self.assertEqual(targets, {1: [1, 2, 3]})
Guido van Rossum87b63952007-02-11 07:05:21 +0000628 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 +0000629 self.assertEqual(targets, {1: [3, 2, 1]})
630 with C() as (targets[1], targets[2], targets[3]):
631 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
632 class B: pass
633 blah = B()
634 with C() as (blah.one, blah.two, blah.three):
635 self.assertEqual(blah.one, 1)
636 self.assertEqual(blah.two, 2)
637 self.assertEqual(blah.three, 3)
638
639
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000640class ExitSwallowsExceptionTestCase(unittest.TestCase):
641
Guido van Rossumf6694362006-03-10 02:28:35 +0000642 def testExitTrueSwallowsException(self):
643 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000644 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000645 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000646 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000647 with AfricanSwallow():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000648 1/0
649 except ZeroDivisionError:
650 self.fail("ZeroDivisionError should have been swallowed")
651
Guido van Rossumf6694362006-03-10 02:28:35 +0000652 def testExitFalseDoesntSwallowException(self):
653 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000654 def __enter__(self): pass
655 def __exit__(self, t, v, tb): return False
656 try:
657 with EuropeanSwallow():
658 1/0
659 except ZeroDivisionError:
660 pass
661 else:
662 self.fail("ZeroDivisionError should have been raised")
663
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000664
Georg Brandl0c315622009-05-25 21:10:36 +0000665class NestedWith(unittest.TestCase):
666
667 class Dummy(object):
668 def __init__(self, value=None, gobble=False):
669 if value is None:
670 value = self
671 self.value = value
672 self.gobble = gobble
673 self.enter_called = False
674 self.exit_called = False
675
676 def __enter__(self):
677 self.enter_called = True
678 return self.value
679
680 def __exit__(self, *exc_info):
681 self.exit_called = True
682 self.exc_info = exc_info
683 if self.gobble:
684 return True
685
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000686 class InitRaises(object):
Georg Brandl0c315622009-05-25 21:10:36 +0000687 def __init__(self): raise RuntimeError()
688
689 class EnterRaises(object):
690 def __enter__(self): raise RuntimeError()
691 def __exit__(self, *exc_info): pass
692
693 class ExitRaises(object):
694 def __enter__(self): pass
695 def __exit__(self, *exc_info): raise RuntimeError()
696
697 def testNoExceptions(self):
698 with self.Dummy() as a, self.Dummy() as b:
699 self.assertTrue(a.enter_called)
700 self.assertTrue(b.enter_called)
701 self.assertTrue(a.exit_called)
702 self.assertTrue(b.exit_called)
703
704 def testExceptionInExprList(self):
705 try:
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000706 with self.Dummy() as a, self.InitRaises():
Georg Brandl0c315622009-05-25 21:10:36 +0000707 pass
708 except:
709 pass
710 self.assertTrue(a.enter_called)
711 self.assertTrue(a.exit_called)
712
713 def testExceptionInEnter(self):
714 try:
715 with self.Dummy() as a, self.EnterRaises():
716 self.fail('body of bad with executed')
717 except RuntimeError:
718 pass
719 else:
720 self.fail('RuntimeError not reraised')
721 self.assertTrue(a.enter_called)
722 self.assertTrue(a.exit_called)
723
724 def testExceptionInExit(self):
725 body_executed = False
726 with self.Dummy(gobble=True) as a, self.ExitRaises():
727 body_executed = True
728 self.assertTrue(a.enter_called)
729 self.assertTrue(a.exit_called)
Benjamin Peterson78565b22009-06-28 19:19:51 +0000730 self.assertTrue(body_executed)
Georg Brandl0c315622009-05-25 21:10:36 +0000731 self.assertNotEqual(a.exc_info[0], None)
732
733 def testEnterReturnsTuple(self):
734 with self.Dummy(value=(1,2)) as (a1, a2), \
735 self.Dummy(value=(10, 20)) as (b1, b2):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000736 self.assertEqual(1, a1)
737 self.assertEqual(2, a2)
738 self.assertEqual(10, b1)
739 self.assertEqual(20, b2)
Georg Brandl0c315622009-05-25 21:10:36 +0000740
Tim Peters400cbc32006-02-28 18:44:41 +0000741if __name__ == '__main__':
Zachary Ware38c707e2015-04-13 15:00:43 -0500742 unittest.main()