blob: e247ff6a6171e3044f364900c15b9170e58e0cf1 [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
Tim Peters400cbc32006-02-28 18:44:41 +0000143 def testAssignmentToTupleOnlyContainingNoneError(self):
144 self.assertRaisesSyntaxError('with mock as None,:\n pass')
145 self.assertRaisesSyntaxError(
146 'with mock as (None,):\n'
147 ' pass')
148
149 def testAssignmentToTupleContainingNoneError(self):
150 self.assertRaisesSyntaxError(
151 'with mock as (foo, None, bar):\n'
152 ' pass')
153
Tim Peters400cbc32006-02-28 18:44:41 +0000154 def testEnterThrows(self):
155 class EnterThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000156 def __enter__(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000157 raise RuntimeError("Enter threw")
Tim Peters400cbc32006-02-28 18:44:41 +0000158 def __exit__(self, *args):
159 pass
160
161 def shouldThrow():
162 ct = EnterThrows()
163 self.foo = None
164 with ct as self.foo:
165 pass
166 self.assertRaises(RuntimeError, shouldThrow)
167 self.assertEqual(self.foo, None)
168
169 def testExitThrows(self):
170 class ExitThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000171 def __enter__(self):
172 return
173 def __exit__(self, *args):
174 raise RuntimeError(42)
175 def shouldThrow():
176 with ExitThrows():
177 pass
178 self.assertRaises(RuntimeError, shouldThrow)
179
180class ContextmanagerAssertionMixin(object):
Collin Winterba21f612007-09-01 20:29:04 +0000181
182 def setUp(self):
183 self.TEST_EXCEPTION = RuntimeError("test exception")
Tim Peters400cbc32006-02-28 18:44:41 +0000184
185 def assertInWithManagerInvariants(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000186 self.assertTrue(mock_manager.enter_called)
187 self.assertFalse(mock_manager.exit_called)
188 self.assertEqual(mock_manager.exit_args, None)
189
190 def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
Tim Peters400cbc32006-02-28 18:44:41 +0000191 self.assertTrue(mock_manager.enter_called)
192 self.assertTrue(mock_manager.exit_called)
193 self.assertEqual(mock_manager.exit_args, exit_args)
194
195 def assertAfterWithManagerInvariantsNoError(self, mock_manager):
196 self.assertAfterWithManagerInvariants(mock_manager,
197 (None, None, None))
198
199 def assertInWithGeneratorInvariants(self, mock_generator):
200 self.assertTrue(mock_generator.yielded)
201 self.assertFalse(mock_generator.stopped)
202
203 def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
204 self.assertTrue(mock_generator.yielded)
205 self.assertTrue(mock_generator.stopped)
206
207 def raiseTestException(self):
208 raise self.TEST_EXCEPTION
209
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000210 def assertAfterWithManagerInvariantsWithError(self, mock_manager,
211 exc_type=None):
Tim Peters400cbc32006-02-28 18:44:41 +0000212 self.assertTrue(mock_manager.enter_called)
213 self.assertTrue(mock_manager.exit_called)
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000214 if exc_type is None:
215 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
216 exc_type = type(self.TEST_EXCEPTION)
217 self.assertEqual(mock_manager.exit_args[0], exc_type)
218 # Test the __exit__ arguments. Issue #7853
219 self.assertIsInstance(mock_manager.exit_args[1], exc_type)
220 self.assertIsNot(mock_manager.exit_args[2], None)
Tim Peters400cbc32006-02-28 18:44:41 +0000221
222 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
223 self.assertTrue(mock_generator.yielded)
224 self.assertTrue(mock_generator.stopped)
225
226
227class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
228 def testInlineGeneratorSyntax(self):
229 with mock_contextmanager_generator():
230 pass
231
232 def testUnboundGenerator(self):
233 mock = mock_contextmanager_generator()
234 with mock:
235 pass
236 self.assertAfterWithManagerInvariantsNoError(mock)
237
238 def testInlineGeneratorBoundSyntax(self):
239 with mock_contextmanager_generator() as foo:
240 self.assertInWithGeneratorInvariants(foo)
241 # FIXME: In the future, we'll try to keep the bound names from leaking
242 self.assertAfterWithGeneratorInvariantsNoError(foo)
243
244 def testInlineGeneratorBoundToExistingVariable(self):
245 foo = None
246 with mock_contextmanager_generator() as foo:
247 self.assertInWithGeneratorInvariants(foo)
248 self.assertAfterWithGeneratorInvariantsNoError(foo)
249
250 def testInlineGeneratorBoundToDottedVariable(self):
251 with mock_contextmanager_generator() as self.foo:
252 self.assertInWithGeneratorInvariants(self.foo)
253 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
254
255 def testBoundGenerator(self):
256 mock = mock_contextmanager_generator()
257 with mock as foo:
258 self.assertInWithGeneratorInvariants(foo)
259 self.assertInWithManagerInvariants(mock)
260 self.assertAfterWithGeneratorInvariantsNoError(foo)
261 self.assertAfterWithManagerInvariantsNoError(mock)
262
263 def testNestedSingleStatements(self):
264 mock_a = mock_contextmanager_generator()
265 with mock_a as foo:
266 mock_b = mock_contextmanager_generator()
267 with mock_b as bar:
268 self.assertInWithManagerInvariants(mock_a)
269 self.assertInWithManagerInvariants(mock_b)
270 self.assertInWithGeneratorInvariants(foo)
271 self.assertInWithGeneratorInvariants(bar)
272 self.assertAfterWithManagerInvariantsNoError(mock_b)
273 self.assertAfterWithGeneratorInvariantsNoError(bar)
274 self.assertInWithManagerInvariants(mock_a)
275 self.assertInWithGeneratorInvariants(foo)
276 self.assertAfterWithManagerInvariantsNoError(mock_a)
277 self.assertAfterWithGeneratorInvariantsNoError(foo)
278
279
280class NestedNonexceptionalTestCase(unittest.TestCase,
281 ContextmanagerAssertionMixin):
282 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000283 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000284 pass
285
Tim Peters400cbc32006-02-28 18:44:41 +0000286 def testSingleArgBoundToNonTuple(self):
287 m = mock_contextmanager_generator()
288 # This will bind all the arguments to nested() into a single list
289 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000290 with Nested(m) as foo:
Tim Peters400cbc32006-02-28 18:44:41 +0000291 self.assertInWithManagerInvariants(m)
292 self.assertAfterWithManagerInvariantsNoError(m)
293
294 def testSingleArgBoundToSingleElementParenthesizedList(self):
295 m = mock_contextmanager_generator()
296 # This will bind all the arguments to nested() into a single list
297 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000298 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000299 self.assertInWithManagerInvariants(m)
300 self.assertAfterWithManagerInvariantsNoError(m)
301
302 def testSingleArgBoundToMultipleElementTupleError(self):
303 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000304 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000305 pass
306 self.assertRaises(ValueError, shouldThrowValueError)
307
308 def testSingleArgUnbound(self):
309 mock_contextmanager = mock_contextmanager_generator()
310 mock_nested = MockNested(mock_contextmanager)
311 with mock_nested:
312 self.assertInWithManagerInvariants(mock_contextmanager)
313 self.assertInWithManagerInvariants(mock_nested)
314 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
315 self.assertAfterWithManagerInvariantsNoError(mock_nested)
316
317 def testMultipleArgUnbound(self):
318 m = mock_contextmanager_generator()
319 n = mock_contextmanager_generator()
320 o = mock_contextmanager_generator()
321 mock_nested = MockNested(m, n, o)
322 with mock_nested:
323 self.assertInWithManagerInvariants(m)
324 self.assertInWithManagerInvariants(n)
325 self.assertInWithManagerInvariants(o)
326 self.assertInWithManagerInvariants(mock_nested)
327 self.assertAfterWithManagerInvariantsNoError(m)
328 self.assertAfterWithManagerInvariantsNoError(n)
329 self.assertAfterWithManagerInvariantsNoError(o)
330 self.assertAfterWithManagerInvariantsNoError(mock_nested)
331
332 def testMultipleArgBound(self):
333 mock_nested = MockNested(mock_contextmanager_generator(),
334 mock_contextmanager_generator(), mock_contextmanager_generator())
335 with mock_nested as (m, n, o):
336 self.assertInWithGeneratorInvariants(m)
337 self.assertInWithGeneratorInvariants(n)
338 self.assertInWithGeneratorInvariants(o)
339 self.assertInWithManagerInvariants(mock_nested)
340 self.assertAfterWithGeneratorInvariantsNoError(m)
341 self.assertAfterWithGeneratorInvariantsNoError(n)
342 self.assertAfterWithGeneratorInvariantsNoError(o)
343 self.assertAfterWithManagerInvariantsNoError(mock_nested)
344
345
Collin Winterba21f612007-09-01 20:29:04 +0000346class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
Tim Peters400cbc32006-02-28 18:44:41 +0000347 def testSingleResource(self):
348 cm = mock_contextmanager_generator()
349 def shouldThrow():
350 with cm as self.resource:
351 self.assertInWithManagerInvariants(cm)
352 self.assertInWithGeneratorInvariants(self.resource)
353 self.raiseTestException()
354 self.assertRaises(RuntimeError, shouldThrow)
355 self.assertAfterWithManagerInvariantsWithError(cm)
356 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
357
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000358 def testExceptionNormalized(self):
359 cm = mock_contextmanager_generator()
360 def shouldThrow():
361 with cm as self.resource:
362 # Note this relies on the fact that 1 // 0 produces an exception
363 # that is not normalized immediately.
364 1 // 0
365 self.assertRaises(ZeroDivisionError, shouldThrow)
366 self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
367
Tim Peters400cbc32006-02-28 18:44:41 +0000368 def testNestedSingleStatements(self):
369 mock_a = mock_contextmanager_generator()
370 mock_b = mock_contextmanager_generator()
371 def shouldThrow():
372 with mock_a as self.foo:
373 with mock_b as self.bar:
374 self.assertInWithManagerInvariants(mock_a)
375 self.assertInWithManagerInvariants(mock_b)
376 self.assertInWithGeneratorInvariants(self.foo)
377 self.assertInWithGeneratorInvariants(self.bar)
378 self.raiseTestException()
379 self.assertRaises(RuntimeError, shouldThrow)
380 self.assertAfterWithManagerInvariantsWithError(mock_a)
381 self.assertAfterWithManagerInvariantsWithError(mock_b)
382 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
383 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
384
385 def testMultipleResourcesInSingleStatement(self):
386 cm_a = mock_contextmanager_generator()
387 cm_b = mock_contextmanager_generator()
388 mock_nested = MockNested(cm_a, cm_b)
389 def shouldThrow():
390 with mock_nested as (self.resource_a, self.resource_b):
391 self.assertInWithManagerInvariants(cm_a)
392 self.assertInWithManagerInvariants(cm_b)
393 self.assertInWithManagerInvariants(mock_nested)
394 self.assertInWithGeneratorInvariants(self.resource_a)
395 self.assertInWithGeneratorInvariants(self.resource_b)
396 self.raiseTestException()
397 self.assertRaises(RuntimeError, shouldThrow)
398 self.assertAfterWithManagerInvariantsWithError(cm_a)
399 self.assertAfterWithManagerInvariantsWithError(cm_b)
400 self.assertAfterWithManagerInvariantsWithError(mock_nested)
401 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
402 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
403
404 def testNestedExceptionBeforeInnerStatement(self):
405 mock_a = mock_contextmanager_generator()
406 mock_b = mock_contextmanager_generator()
407 self.bar = None
408 def shouldThrow():
409 with mock_a as self.foo:
410 self.assertInWithManagerInvariants(mock_a)
411 self.assertInWithGeneratorInvariants(self.foo)
412 self.raiseTestException()
413 with mock_b as self.bar:
414 pass
415 self.assertRaises(RuntimeError, shouldThrow)
416 self.assertAfterWithManagerInvariantsWithError(mock_a)
417 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
418
419 # The inner statement stuff should never have been touched
420 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000421 self.assertFalse(mock_b.enter_called)
422 self.assertFalse(mock_b.exit_called)
423 self.assertEqual(mock_b.exit_args, None)
424
425 def testNestedExceptionAfterInnerStatement(self):
426 mock_a = mock_contextmanager_generator()
427 mock_b = mock_contextmanager_generator()
428 def shouldThrow():
429 with mock_a as self.foo:
430 with mock_b as self.bar:
431 self.assertInWithManagerInvariants(mock_a)
432 self.assertInWithManagerInvariants(mock_b)
433 self.assertInWithGeneratorInvariants(self.foo)
434 self.assertInWithGeneratorInvariants(self.bar)
435 self.raiseTestException()
436 self.assertRaises(RuntimeError, shouldThrow)
437 self.assertAfterWithManagerInvariantsWithError(mock_a)
438 self.assertAfterWithManagerInvariantsNoError(mock_b)
439 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
440 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
441
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000442 def testRaisedStopIteration1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000443 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000444 @contextmanager
445 def cm():
446 yield
447
448 def shouldThrow():
449 with cm():
450 raise StopIteration("from with")
451
Martin Panter7e3a91a2016-02-10 04:40:48 +0000452 with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
Yury Selivanov68333392015-05-22 11:16:47 -0400453 self.assertRaises(StopIteration, shouldThrow)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000454
455 def testRaisedStopIteration2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000456 # From bug 1462485
Thomas Wouters477c8d52006-05-27 19:21:47 +0000457 class cm(object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000458 def __enter__(self):
459 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000460 def __exit__(self, type, value, traceback):
461 pass
462
463 def shouldThrow():
464 with cm():
465 raise StopIteration("from with")
466
467 self.assertRaises(StopIteration, shouldThrow)
468
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000469 def testRaisedStopIteration3(self):
470 # Another variant where the exception hasn't been instantiated
471 # From bug 1705170
472 @contextmanager
473 def cm():
474 yield
475
476 def shouldThrow():
477 with cm():
478 raise next(iter([]))
479
Martin Panter7e3a91a2016-02-10 04:40:48 +0000480 with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
Yury Selivanov68333392015-05-22 11:16:47 -0400481 self.assertRaises(StopIteration, shouldThrow)
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000482
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000483 def testRaisedGeneratorExit1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000484 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000485 @contextmanager
486 def cm():
487 yield
488
489 def shouldThrow():
490 with cm():
491 raise GeneratorExit("from with")
492
493 self.assertRaises(GeneratorExit, shouldThrow)
494
495 def testRaisedGeneratorExit2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000496 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000497 class cm (object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000498 def __enter__(self):
499 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000500 def __exit__(self, type, value, traceback):
501 pass
502
503 def shouldThrow():
504 with cm():
505 raise GeneratorExit("from with")
506
507 self.assertRaises(GeneratorExit, shouldThrow)
508
Amaury Forgeot d'Arc10b24e82008-12-10 23:49:33 +0000509 def testErrorsInBool(self):
510 # issue4589: __exit__ return code may raise an exception
511 # when looking at its truth value.
512
513 class cm(object):
514 def __init__(self, bool_conversion):
515 class Bool:
516 def __bool__(self):
517 return bool_conversion()
518 self.exit_result = Bool()
519 def __enter__(self):
520 return 3
521 def __exit__(self, a, b, c):
522 return self.exit_result
523
524 def trueAsBool():
525 with cm(lambda: True):
526 self.fail("Should NOT see this")
527 trueAsBool()
528
529 def falseAsBool():
530 with cm(lambda: False):
531 self.fail("Should raise")
532 self.assertRaises(AssertionError, falseAsBool)
533
534 def failAsBool():
535 with cm(lambda: 1//0):
536 self.fail("Should NOT see this")
537 self.assertRaises(ZeroDivisionError, failAsBool)
538
Tim Peters400cbc32006-02-28 18:44:41 +0000539
540class NonLocalFlowControlTestCase(unittest.TestCase):
541
542 def testWithBreak(self):
543 counter = 0
544 while True:
545 counter += 1
546 with mock_contextmanager_generator():
547 counter += 10
548 break
549 counter += 100 # Not reached
550 self.assertEqual(counter, 11)
551
552 def testWithContinue(self):
553 counter = 0
554 while True:
555 counter += 1
556 if counter > 2:
557 break
558 with mock_contextmanager_generator():
559 counter += 10
560 continue
561 counter += 100 # Not reached
562 self.assertEqual(counter, 12)
563
564 def testWithReturn(self):
565 def foo():
566 counter = 0
567 while True:
568 counter += 1
569 with mock_contextmanager_generator():
570 counter += 10
571 return counter
572 counter += 100 # Not reached
573 self.assertEqual(foo(), 11)
574
575 def testWithYield(self):
576 def gen():
577 with mock_contextmanager_generator():
578 yield 12
579 yield 13
580 x = list(gen())
581 self.assertEqual(x, [12, 13])
582
583 def testWithRaise(self):
584 counter = 0
585 try:
586 counter += 1
587 with mock_contextmanager_generator():
588 counter += 10
589 raise RuntimeError
590 counter += 100 # Not reached
591 except RuntimeError:
592 self.assertEqual(counter, 11)
593 else:
594 self.fail("Didn't raise RuntimeError")
595
596
597class AssignmentTargetTestCase(unittest.TestCase):
598
599 def testSingleComplexTarget(self):
600 targets = {1: [0, 1, 2]}
601 with mock_contextmanager_generator() as targets[1][0]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000602 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000603 self.assertEqual(targets[1][0].__class__, MockResource)
Guido van Rossum87b63952007-02-11 07:05:21 +0000604 with mock_contextmanager_generator() as list(targets.values())[0][1]:
605 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000606 self.assertEqual(targets[1][1].__class__, MockResource)
607 with mock_contextmanager_generator() as targets[2]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000608 keys = list(targets.keys())
Tim Peters400cbc32006-02-28 18:44:41 +0000609 keys.sort()
610 self.assertEqual(keys, [1, 2])
611 class C: pass
612 blah = C()
613 with mock_contextmanager_generator() as blah.foo:
614 self.assertEqual(hasattr(blah, "foo"), True)
615
616 def testMultipleComplexTargets(self):
617 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000618 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000619 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000620 targets = {1: [0, 1, 2]}
621 with C() as (targets[1][0], targets[1][1], targets[1][2]):
622 self.assertEqual(targets, {1: [1, 2, 3]})
Guido van Rossum87b63952007-02-11 07:05:21 +0000623 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 +0000624 self.assertEqual(targets, {1: [3, 2, 1]})
625 with C() as (targets[1], targets[2], targets[3]):
626 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
627 class B: pass
628 blah = B()
629 with C() as (blah.one, blah.two, blah.three):
630 self.assertEqual(blah.one, 1)
631 self.assertEqual(blah.two, 2)
632 self.assertEqual(blah.three, 3)
633
634
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000635class ExitSwallowsExceptionTestCase(unittest.TestCase):
636
Guido van Rossumf6694362006-03-10 02:28:35 +0000637 def testExitTrueSwallowsException(self):
638 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000639 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000640 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000641 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000642 with AfricanSwallow():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000643 1/0
644 except ZeroDivisionError:
645 self.fail("ZeroDivisionError should have been swallowed")
646
Guido van Rossumf6694362006-03-10 02:28:35 +0000647 def testExitFalseDoesntSwallowException(self):
648 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000649 def __enter__(self): pass
650 def __exit__(self, t, v, tb): return False
651 try:
652 with EuropeanSwallow():
653 1/0
654 except ZeroDivisionError:
655 pass
656 else:
657 self.fail("ZeroDivisionError should have been raised")
658
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000659
Georg Brandl0c315622009-05-25 21:10:36 +0000660class NestedWith(unittest.TestCase):
661
662 class Dummy(object):
663 def __init__(self, value=None, gobble=False):
664 if value is None:
665 value = self
666 self.value = value
667 self.gobble = gobble
668 self.enter_called = False
669 self.exit_called = False
670
671 def __enter__(self):
672 self.enter_called = True
673 return self.value
674
675 def __exit__(self, *exc_info):
676 self.exit_called = True
677 self.exc_info = exc_info
678 if self.gobble:
679 return True
680
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000681 class InitRaises(object):
Georg Brandl0c315622009-05-25 21:10:36 +0000682 def __init__(self): raise RuntimeError()
683
684 class EnterRaises(object):
685 def __enter__(self): raise RuntimeError()
686 def __exit__(self, *exc_info): pass
687
688 class ExitRaises(object):
689 def __enter__(self): pass
690 def __exit__(self, *exc_info): raise RuntimeError()
691
692 def testNoExceptions(self):
693 with self.Dummy() as a, self.Dummy() as b:
694 self.assertTrue(a.enter_called)
695 self.assertTrue(b.enter_called)
696 self.assertTrue(a.exit_called)
697 self.assertTrue(b.exit_called)
698
699 def testExceptionInExprList(self):
700 try:
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000701 with self.Dummy() as a, self.InitRaises():
Georg Brandl0c315622009-05-25 21:10:36 +0000702 pass
703 except:
704 pass
705 self.assertTrue(a.enter_called)
706 self.assertTrue(a.exit_called)
707
708 def testExceptionInEnter(self):
709 try:
710 with self.Dummy() as a, self.EnterRaises():
711 self.fail('body of bad with executed')
712 except RuntimeError:
713 pass
714 else:
715 self.fail('RuntimeError not reraised')
716 self.assertTrue(a.enter_called)
717 self.assertTrue(a.exit_called)
718
719 def testExceptionInExit(self):
720 body_executed = False
721 with self.Dummy(gobble=True) as a, self.ExitRaises():
722 body_executed = True
723 self.assertTrue(a.enter_called)
724 self.assertTrue(a.exit_called)
Benjamin Peterson78565b22009-06-28 19:19:51 +0000725 self.assertTrue(body_executed)
Georg Brandl0c315622009-05-25 21:10:36 +0000726 self.assertNotEqual(a.exc_info[0], None)
727
728 def testEnterReturnsTuple(self):
729 with self.Dummy(value=(1,2)) as (a1, a2), \
730 self.Dummy(value=(10, 20)) as (b1, b2):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000731 self.assertEqual(1, a1)
732 self.assertEqual(2, a2)
733 self.assertEqual(10, b1)
734 self.assertEqual(20, b2)
Georg Brandl0c315622009-05-25 21:10:36 +0000735
Tim Peters400cbc32006-02-28 18:44:41 +0000736if __name__ == '__main__':
Zachary Ware38c707e2015-04-13 15:00:43 -0500737 unittest.main()