blob: e8cc8c056ec6c53d447bf0ad0c130fc7950049aa [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Tim Peters400cbc32006-02-28 18:44:41 +00002
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
Antoine Pitrou67b212e2011-01-08 09:55:31 +000012from 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
Antoine Pitrou67b212e2011-01-08 09:55:31 +000016class MockContextManager(_GeneratorContextManager):
Nick Coghlan0ded3e32011-05-05 23:49:25 +100017 def __init__(self, func, *args, **kwds):
18 super().__init__(func, *args, **kwds)
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
Antoine Pitrou67b212e2011-01-08 09:55:31 +000025 return _GeneratorContextManager.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +000026
27 def __exit__(self, type, value, traceback):
28 self.exit_called = True
29 self.exit_args = (type, value, traceback)
Antoine Pitrou67b212e2011-01-08 09:55:31 +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):
Nick Coghlan0ded3e32011-05-05 23:49:25 +100036 return MockContextManager(func, *args, **kwds)
Tim Peters400cbc32006-02-28 18:44:41 +000037 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
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000218 def assertAfterWithManagerInvariantsWithError(self, mock_manager,
219 exc_type=None):
Tim Peters400cbc32006-02-28 18:44:41 +0000220 self.assertTrue(mock_manager.enter_called)
221 self.assertTrue(mock_manager.exit_called)
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000222 if exc_type is None:
223 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
224 exc_type = type(self.TEST_EXCEPTION)
225 self.assertEqual(mock_manager.exit_args[0], exc_type)
226 # Test the __exit__ arguments. Issue #7853
227 self.assertIsInstance(mock_manager.exit_args[1], exc_type)
228 self.assertIsNot(mock_manager.exit_args[2], None)
Tim Peters400cbc32006-02-28 18:44:41 +0000229
230 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
231 self.assertTrue(mock_generator.yielded)
232 self.assertTrue(mock_generator.stopped)
233
234
235class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
236 def testInlineGeneratorSyntax(self):
237 with mock_contextmanager_generator():
238 pass
239
240 def testUnboundGenerator(self):
241 mock = mock_contextmanager_generator()
242 with mock:
243 pass
244 self.assertAfterWithManagerInvariantsNoError(mock)
245
246 def testInlineGeneratorBoundSyntax(self):
247 with mock_contextmanager_generator() as foo:
248 self.assertInWithGeneratorInvariants(foo)
249 # FIXME: In the future, we'll try to keep the bound names from leaking
250 self.assertAfterWithGeneratorInvariantsNoError(foo)
251
252 def testInlineGeneratorBoundToExistingVariable(self):
253 foo = None
254 with mock_contextmanager_generator() as foo:
255 self.assertInWithGeneratorInvariants(foo)
256 self.assertAfterWithGeneratorInvariantsNoError(foo)
257
258 def testInlineGeneratorBoundToDottedVariable(self):
259 with mock_contextmanager_generator() as self.foo:
260 self.assertInWithGeneratorInvariants(self.foo)
261 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
262
263 def testBoundGenerator(self):
264 mock = mock_contextmanager_generator()
265 with mock as foo:
266 self.assertInWithGeneratorInvariants(foo)
267 self.assertInWithManagerInvariants(mock)
268 self.assertAfterWithGeneratorInvariantsNoError(foo)
269 self.assertAfterWithManagerInvariantsNoError(mock)
270
271 def testNestedSingleStatements(self):
272 mock_a = mock_contextmanager_generator()
273 with mock_a as foo:
274 mock_b = mock_contextmanager_generator()
275 with mock_b as bar:
276 self.assertInWithManagerInvariants(mock_a)
277 self.assertInWithManagerInvariants(mock_b)
278 self.assertInWithGeneratorInvariants(foo)
279 self.assertInWithGeneratorInvariants(bar)
280 self.assertAfterWithManagerInvariantsNoError(mock_b)
281 self.assertAfterWithGeneratorInvariantsNoError(bar)
282 self.assertInWithManagerInvariants(mock_a)
283 self.assertInWithGeneratorInvariants(foo)
284 self.assertAfterWithManagerInvariantsNoError(mock_a)
285 self.assertAfterWithGeneratorInvariantsNoError(foo)
286
287
288class NestedNonexceptionalTestCase(unittest.TestCase,
289 ContextmanagerAssertionMixin):
290 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000291 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000292 pass
293
Tim Peters400cbc32006-02-28 18:44:41 +0000294 def testSingleArgBoundToNonTuple(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 testSingleArgBoundToSingleElementParenthesizedList(self):
303 m = mock_contextmanager_generator()
304 # This will bind all the arguments to nested() into a single list
305 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000306 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000307 self.assertInWithManagerInvariants(m)
308 self.assertAfterWithManagerInvariantsNoError(m)
309
310 def testSingleArgBoundToMultipleElementTupleError(self):
311 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000312 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000313 pass
314 self.assertRaises(ValueError, shouldThrowValueError)
315
316 def testSingleArgUnbound(self):
317 mock_contextmanager = mock_contextmanager_generator()
318 mock_nested = MockNested(mock_contextmanager)
319 with mock_nested:
320 self.assertInWithManagerInvariants(mock_contextmanager)
321 self.assertInWithManagerInvariants(mock_nested)
322 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
323 self.assertAfterWithManagerInvariantsNoError(mock_nested)
324
325 def testMultipleArgUnbound(self):
326 m = mock_contextmanager_generator()
327 n = mock_contextmanager_generator()
328 o = mock_contextmanager_generator()
329 mock_nested = MockNested(m, n, o)
330 with mock_nested:
331 self.assertInWithManagerInvariants(m)
332 self.assertInWithManagerInvariants(n)
333 self.assertInWithManagerInvariants(o)
334 self.assertInWithManagerInvariants(mock_nested)
335 self.assertAfterWithManagerInvariantsNoError(m)
336 self.assertAfterWithManagerInvariantsNoError(n)
337 self.assertAfterWithManagerInvariantsNoError(o)
338 self.assertAfterWithManagerInvariantsNoError(mock_nested)
339
340 def testMultipleArgBound(self):
341 mock_nested = MockNested(mock_contextmanager_generator(),
342 mock_contextmanager_generator(), mock_contextmanager_generator())
343 with mock_nested as (m, n, o):
344 self.assertInWithGeneratorInvariants(m)
345 self.assertInWithGeneratorInvariants(n)
346 self.assertInWithGeneratorInvariants(o)
347 self.assertInWithManagerInvariants(mock_nested)
348 self.assertAfterWithGeneratorInvariantsNoError(m)
349 self.assertAfterWithGeneratorInvariantsNoError(n)
350 self.assertAfterWithGeneratorInvariantsNoError(o)
351 self.assertAfterWithManagerInvariantsNoError(mock_nested)
352
353
Collin Winterba21f612007-09-01 20:29:04 +0000354class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
Tim Peters400cbc32006-02-28 18:44:41 +0000355 def testSingleResource(self):
356 cm = mock_contextmanager_generator()
357 def shouldThrow():
358 with cm as self.resource:
359 self.assertInWithManagerInvariants(cm)
360 self.assertInWithGeneratorInvariants(self.resource)
361 self.raiseTestException()
362 self.assertRaises(RuntimeError, shouldThrow)
363 self.assertAfterWithManagerInvariantsWithError(cm)
364 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
365
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000366 def testExceptionNormalized(self):
367 cm = mock_contextmanager_generator()
368 def shouldThrow():
369 with cm as self.resource:
370 # Note this relies on the fact that 1 // 0 produces an exception
371 # that is not normalized immediately.
372 1 // 0
373 self.assertRaises(ZeroDivisionError, shouldThrow)
374 self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
375
Tim Peters400cbc32006-02-28 18:44:41 +0000376 def testNestedSingleStatements(self):
377 mock_a = mock_contextmanager_generator()
378 mock_b = mock_contextmanager_generator()
379 def shouldThrow():
380 with mock_a as self.foo:
381 with mock_b as self.bar:
382 self.assertInWithManagerInvariants(mock_a)
383 self.assertInWithManagerInvariants(mock_b)
384 self.assertInWithGeneratorInvariants(self.foo)
385 self.assertInWithGeneratorInvariants(self.bar)
386 self.raiseTestException()
387 self.assertRaises(RuntimeError, shouldThrow)
388 self.assertAfterWithManagerInvariantsWithError(mock_a)
389 self.assertAfterWithManagerInvariantsWithError(mock_b)
390 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
391 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
392
393 def testMultipleResourcesInSingleStatement(self):
394 cm_a = mock_contextmanager_generator()
395 cm_b = mock_contextmanager_generator()
396 mock_nested = MockNested(cm_a, cm_b)
397 def shouldThrow():
398 with mock_nested as (self.resource_a, self.resource_b):
399 self.assertInWithManagerInvariants(cm_a)
400 self.assertInWithManagerInvariants(cm_b)
401 self.assertInWithManagerInvariants(mock_nested)
402 self.assertInWithGeneratorInvariants(self.resource_a)
403 self.assertInWithGeneratorInvariants(self.resource_b)
404 self.raiseTestException()
405 self.assertRaises(RuntimeError, shouldThrow)
406 self.assertAfterWithManagerInvariantsWithError(cm_a)
407 self.assertAfterWithManagerInvariantsWithError(cm_b)
408 self.assertAfterWithManagerInvariantsWithError(mock_nested)
409 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
410 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
411
412 def testNestedExceptionBeforeInnerStatement(self):
413 mock_a = mock_contextmanager_generator()
414 mock_b = mock_contextmanager_generator()
415 self.bar = None
416 def shouldThrow():
417 with mock_a as self.foo:
418 self.assertInWithManagerInvariants(mock_a)
419 self.assertInWithGeneratorInvariants(self.foo)
420 self.raiseTestException()
421 with mock_b as self.bar:
422 pass
423 self.assertRaises(RuntimeError, shouldThrow)
424 self.assertAfterWithManagerInvariantsWithError(mock_a)
425 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
426
427 # The inner statement stuff should never have been touched
428 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000429 self.assertFalse(mock_b.enter_called)
430 self.assertFalse(mock_b.exit_called)
431 self.assertEqual(mock_b.exit_args, None)
432
433 def testNestedExceptionAfterInnerStatement(self):
434 mock_a = mock_contextmanager_generator()
435 mock_b = mock_contextmanager_generator()
436 def shouldThrow():
437 with mock_a as self.foo:
438 with mock_b as self.bar:
439 self.assertInWithManagerInvariants(mock_a)
440 self.assertInWithManagerInvariants(mock_b)
441 self.assertInWithGeneratorInvariants(self.foo)
442 self.assertInWithGeneratorInvariants(self.bar)
443 self.raiseTestException()
444 self.assertRaises(RuntimeError, shouldThrow)
445 self.assertAfterWithManagerInvariantsWithError(mock_a)
446 self.assertAfterWithManagerInvariantsNoError(mock_b)
447 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
448 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
449
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000450 def testRaisedStopIteration1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000451 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000452 @contextmanager
453 def cm():
454 yield
455
456 def shouldThrow():
457 with cm():
458 raise StopIteration("from with")
459
460 self.assertRaises(StopIteration, shouldThrow)
461
462 def testRaisedStopIteration2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000463 # From bug 1462485
Thomas Wouters477c8d52006-05-27 19:21:47 +0000464 class cm(object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000465 def __enter__(self):
466 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000467 def __exit__(self, type, value, traceback):
468 pass
469
470 def shouldThrow():
471 with cm():
472 raise StopIteration("from with")
473
474 self.assertRaises(StopIteration, shouldThrow)
475
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000476 def testRaisedStopIteration3(self):
477 # Another variant where the exception hasn't been instantiated
478 # From bug 1705170
479 @contextmanager
480 def cm():
481 yield
482
483 def shouldThrow():
484 with cm():
485 raise next(iter([]))
486
487 self.assertRaises(StopIteration, shouldThrow)
488
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000489 def testRaisedGeneratorExit1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000490 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000491 @contextmanager
492 def cm():
493 yield
494
495 def shouldThrow():
496 with cm():
497 raise GeneratorExit("from with")
498
499 self.assertRaises(GeneratorExit, shouldThrow)
500
501 def testRaisedGeneratorExit2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000502 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000503 class cm (object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000504 def __enter__(self):
505 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000506 def __exit__(self, type, value, traceback):
507 pass
508
509 def shouldThrow():
510 with cm():
511 raise GeneratorExit("from with")
512
513 self.assertRaises(GeneratorExit, shouldThrow)
514
Amaury Forgeot d'Arc10b24e82008-12-10 23:49:33 +0000515 def testErrorsInBool(self):
516 # issue4589: __exit__ return code may raise an exception
517 # when looking at its truth value.
518
519 class cm(object):
520 def __init__(self, bool_conversion):
521 class Bool:
522 def __bool__(self):
523 return bool_conversion()
524 self.exit_result = Bool()
525 def __enter__(self):
526 return 3
527 def __exit__(self, a, b, c):
528 return self.exit_result
529
530 def trueAsBool():
531 with cm(lambda: True):
532 self.fail("Should NOT see this")
533 trueAsBool()
534
535 def falseAsBool():
536 with cm(lambda: False):
537 self.fail("Should raise")
538 self.assertRaises(AssertionError, falseAsBool)
539
540 def failAsBool():
541 with cm(lambda: 1//0):
542 self.fail("Should NOT see this")
543 self.assertRaises(ZeroDivisionError, failAsBool)
544
Tim Peters400cbc32006-02-28 18:44:41 +0000545
546class NonLocalFlowControlTestCase(unittest.TestCase):
547
548 def testWithBreak(self):
549 counter = 0
550 while True:
551 counter += 1
552 with mock_contextmanager_generator():
553 counter += 10
554 break
555 counter += 100 # Not reached
556 self.assertEqual(counter, 11)
557
558 def testWithContinue(self):
559 counter = 0
560 while True:
561 counter += 1
562 if counter > 2:
563 break
564 with mock_contextmanager_generator():
565 counter += 10
566 continue
567 counter += 100 # Not reached
568 self.assertEqual(counter, 12)
569
570 def testWithReturn(self):
571 def foo():
572 counter = 0
573 while True:
574 counter += 1
575 with mock_contextmanager_generator():
576 counter += 10
577 return counter
578 counter += 100 # Not reached
579 self.assertEqual(foo(), 11)
580
581 def testWithYield(self):
582 def gen():
583 with mock_contextmanager_generator():
584 yield 12
585 yield 13
586 x = list(gen())
587 self.assertEqual(x, [12, 13])
588
589 def testWithRaise(self):
590 counter = 0
591 try:
592 counter += 1
593 with mock_contextmanager_generator():
594 counter += 10
595 raise RuntimeError
596 counter += 100 # Not reached
597 except RuntimeError:
598 self.assertEqual(counter, 11)
599 else:
600 self.fail("Didn't raise RuntimeError")
601
602
603class AssignmentTargetTestCase(unittest.TestCase):
604
605 def testSingleComplexTarget(self):
606 targets = {1: [0, 1, 2]}
607 with mock_contextmanager_generator() as targets[1][0]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000608 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000609 self.assertEqual(targets[1][0].__class__, MockResource)
Guido van Rossum87b63952007-02-11 07:05:21 +0000610 with mock_contextmanager_generator() as list(targets.values())[0][1]:
611 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000612 self.assertEqual(targets[1][1].__class__, MockResource)
613 with mock_contextmanager_generator() as targets[2]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000614 keys = list(targets.keys())
Tim Peters400cbc32006-02-28 18:44:41 +0000615 keys.sort()
616 self.assertEqual(keys, [1, 2])
617 class C: pass
618 blah = C()
619 with mock_contextmanager_generator() as blah.foo:
620 self.assertEqual(hasattr(blah, "foo"), True)
621
622 def testMultipleComplexTargets(self):
623 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000624 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000625 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000626 targets = {1: [0, 1, 2]}
627 with C() as (targets[1][0], targets[1][1], targets[1][2]):
628 self.assertEqual(targets, {1: [1, 2, 3]})
Guido van Rossum87b63952007-02-11 07:05:21 +0000629 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 +0000630 self.assertEqual(targets, {1: [3, 2, 1]})
631 with C() as (targets[1], targets[2], targets[3]):
632 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
633 class B: pass
634 blah = B()
635 with C() as (blah.one, blah.two, blah.three):
636 self.assertEqual(blah.one, 1)
637 self.assertEqual(blah.two, 2)
638 self.assertEqual(blah.three, 3)
639
640
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000641class ExitSwallowsExceptionTestCase(unittest.TestCase):
642
Guido van Rossumf6694362006-03-10 02:28:35 +0000643 def testExitTrueSwallowsException(self):
644 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000645 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000646 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000647 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000648 with AfricanSwallow():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000649 1/0
650 except ZeroDivisionError:
651 self.fail("ZeroDivisionError should have been swallowed")
652
Guido van Rossumf6694362006-03-10 02:28:35 +0000653 def testExitFalseDoesntSwallowException(self):
654 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000655 def __enter__(self): pass
656 def __exit__(self, t, v, tb): return False
657 try:
658 with EuropeanSwallow():
659 1/0
660 except ZeroDivisionError:
661 pass
662 else:
663 self.fail("ZeroDivisionError should have been raised")
664
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000665
Georg Brandl0c315622009-05-25 21:10:36 +0000666class NestedWith(unittest.TestCase):
667
668 class Dummy(object):
669 def __init__(self, value=None, gobble=False):
670 if value is None:
671 value = self
672 self.value = value
673 self.gobble = gobble
674 self.enter_called = False
675 self.exit_called = False
676
677 def __enter__(self):
678 self.enter_called = True
679 return self.value
680
681 def __exit__(self, *exc_info):
682 self.exit_called = True
683 self.exc_info = exc_info
684 if self.gobble:
685 return True
686
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000687 class InitRaises(object):
Georg Brandl0c315622009-05-25 21:10:36 +0000688 def __init__(self): raise RuntimeError()
689
690 class EnterRaises(object):
691 def __enter__(self): raise RuntimeError()
692 def __exit__(self, *exc_info): pass
693
694 class ExitRaises(object):
695 def __enter__(self): pass
696 def __exit__(self, *exc_info): raise RuntimeError()
697
698 def testNoExceptions(self):
699 with self.Dummy() as a, self.Dummy() as b:
700 self.assertTrue(a.enter_called)
701 self.assertTrue(b.enter_called)
702 self.assertTrue(a.exit_called)
703 self.assertTrue(b.exit_called)
704
705 def testExceptionInExprList(self):
706 try:
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000707 with self.Dummy() as a, self.InitRaises():
Georg Brandl0c315622009-05-25 21:10:36 +0000708 pass
709 except:
710 pass
711 self.assertTrue(a.enter_called)
712 self.assertTrue(a.exit_called)
713
714 def testExceptionInEnter(self):
715 try:
716 with self.Dummy() as a, self.EnterRaises():
717 self.fail('body of bad with executed')
718 except RuntimeError:
719 pass
720 else:
721 self.fail('RuntimeError not reraised')
722 self.assertTrue(a.enter_called)
723 self.assertTrue(a.exit_called)
724
725 def testExceptionInExit(self):
726 body_executed = False
727 with self.Dummy(gobble=True) as a, self.ExitRaises():
728 body_executed = True
729 self.assertTrue(a.enter_called)
730 self.assertTrue(a.exit_called)
Benjamin Peterson78565b22009-06-28 19:19:51 +0000731 self.assertTrue(body_executed)
Georg Brandl0c315622009-05-25 21:10:36 +0000732 self.assertNotEqual(a.exc_info[0], None)
733
734 def testEnterReturnsTuple(self):
735 with self.Dummy(value=(1,2)) as (a1, a2), \
736 self.Dummy(value=(10, 20)) as (b1, b2):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000737 self.assertEqual(1, a1)
738 self.assertEqual(2, a2)
739 self.assertEqual(10, b1)
740 self.assertEqual(20, b2)
Georg Brandl0c315622009-05-25 21:10:36 +0000741
Tim Peters400cbc32006-02-28 18:44:41 +0000742def test_main():
743 run_unittest(FailureTestCase, NonexceptionalTestCase,
744 NestedNonexceptionalTestCase, ExceptionalTestCase,
745 NonLocalFlowControlTestCase,
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000746 AssignmentTargetTestCase,
Georg Brandl0c315622009-05-25 21:10:36 +0000747 ExitSwallowsExceptionTestCase,
748 NestedWith)
Tim Peters400cbc32006-02-28 18:44:41 +0000749
750
751if __name__ == '__main__':
752 test_main()