blob: c70f6859b4b29d983daf13debec84fbffc9be11d [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
Raymond Hettingera3fec152016-11-21 17:24:23 -0800112 def testEnterAttributeError1(self):
Tim Peters400cbc32006-02-28 18:44:41 +0000113 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
Raymond Hettinger7e45b5c2016-11-24 10:50:34 -0800120 self.assertRaisesRegex(AttributeError, '__enter__', fooLacksEnter)
Raymond Hettingera3fec152016-11-21 17:24:23 -0800121
122 def testEnterAttributeError2(self):
123 class LacksEnterAndExit(object):
124 pass
125
126 def fooLacksEnterAndExit():
127 foo = LacksEnterAndExit()
128 with foo: pass
Raymond Hettinger7e45b5c2016-11-24 10:50:34 -0800129 self.assertRaisesRegex(AttributeError, '__enter__', fooLacksEnterAndExit)
Tim Peters400cbc32006-02-28 18:44:41 +0000130
131 def testExitAttributeError(self):
132 class LacksExit(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000133 def __enter__(self):
134 pass
135
136 def fooLacksExit():
137 foo = LacksExit()
138 with foo: pass
Raymond Hettinger7e45b5c2016-11-24 10:50:34 -0800139 self.assertRaisesRegex(AttributeError, '__exit__', fooLacksExit)
Tim Peters400cbc32006-02-28 18:44:41 +0000140
141 def assertRaisesSyntaxError(self, codestr):
142 def shouldRaiseSyntaxError(s):
143 compile(s, '', 'single')
144 self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr)
145
146 def testAssignmentToNoneError(self):
147 self.assertRaisesSyntaxError('with mock as None:\n pass')
148 self.assertRaisesSyntaxError(
149 'with mock as (None):\n'
150 ' pass')
151
Tim Peters400cbc32006-02-28 18:44:41 +0000152 def testAssignmentToTupleOnlyContainingNoneError(self):
153 self.assertRaisesSyntaxError('with mock as None,:\n pass')
154 self.assertRaisesSyntaxError(
155 'with mock as (None,):\n'
156 ' pass')
157
158 def testAssignmentToTupleContainingNoneError(self):
159 self.assertRaisesSyntaxError(
160 'with mock as (foo, None, bar):\n'
161 ' pass')
162
Tim Peters400cbc32006-02-28 18:44:41 +0000163 def testEnterThrows(self):
164 class EnterThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000165 def __enter__(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000166 raise RuntimeError("Enter threw")
Tim Peters400cbc32006-02-28 18:44:41 +0000167 def __exit__(self, *args):
168 pass
169
170 def shouldThrow():
171 ct = EnterThrows()
172 self.foo = None
173 with ct as self.foo:
174 pass
175 self.assertRaises(RuntimeError, shouldThrow)
176 self.assertEqual(self.foo, None)
177
178 def testExitThrows(self):
179 class ExitThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000180 def __enter__(self):
181 return
182 def __exit__(self, *args):
183 raise RuntimeError(42)
184 def shouldThrow():
185 with ExitThrows():
186 pass
187 self.assertRaises(RuntimeError, shouldThrow)
188
189class ContextmanagerAssertionMixin(object):
Collin Winterba21f612007-09-01 20:29:04 +0000190
191 def setUp(self):
192 self.TEST_EXCEPTION = RuntimeError("test exception")
Tim Peters400cbc32006-02-28 18:44:41 +0000193
194 def assertInWithManagerInvariants(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000195 self.assertTrue(mock_manager.enter_called)
196 self.assertFalse(mock_manager.exit_called)
197 self.assertEqual(mock_manager.exit_args, None)
198
199 def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
Tim Peters400cbc32006-02-28 18:44:41 +0000200 self.assertTrue(mock_manager.enter_called)
201 self.assertTrue(mock_manager.exit_called)
202 self.assertEqual(mock_manager.exit_args, exit_args)
203
204 def assertAfterWithManagerInvariantsNoError(self, mock_manager):
205 self.assertAfterWithManagerInvariants(mock_manager,
206 (None, None, None))
207
208 def assertInWithGeneratorInvariants(self, mock_generator):
209 self.assertTrue(mock_generator.yielded)
210 self.assertFalse(mock_generator.stopped)
211
212 def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
213 self.assertTrue(mock_generator.yielded)
214 self.assertTrue(mock_generator.stopped)
215
216 def raiseTestException(self):
217 raise self.TEST_EXCEPTION
218
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000219 def assertAfterWithManagerInvariantsWithError(self, mock_manager,
220 exc_type=None):
Tim Peters400cbc32006-02-28 18:44:41 +0000221 self.assertTrue(mock_manager.enter_called)
222 self.assertTrue(mock_manager.exit_called)
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000223 if exc_type is None:
224 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
225 exc_type = type(self.TEST_EXCEPTION)
226 self.assertEqual(mock_manager.exit_args[0], exc_type)
227 # Test the __exit__ arguments. Issue #7853
228 self.assertIsInstance(mock_manager.exit_args[1], exc_type)
229 self.assertIsNot(mock_manager.exit_args[2], None)
Tim Peters400cbc32006-02-28 18:44:41 +0000230
231 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
232 self.assertTrue(mock_generator.yielded)
233 self.assertTrue(mock_generator.stopped)
234
235
236class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
237 def testInlineGeneratorSyntax(self):
238 with mock_contextmanager_generator():
239 pass
240
241 def testUnboundGenerator(self):
242 mock = mock_contextmanager_generator()
243 with mock:
244 pass
245 self.assertAfterWithManagerInvariantsNoError(mock)
246
247 def testInlineGeneratorBoundSyntax(self):
248 with mock_contextmanager_generator() as foo:
249 self.assertInWithGeneratorInvariants(foo)
250 # FIXME: In the future, we'll try to keep the bound names from leaking
251 self.assertAfterWithGeneratorInvariantsNoError(foo)
252
253 def testInlineGeneratorBoundToExistingVariable(self):
254 foo = None
255 with mock_contextmanager_generator() as foo:
256 self.assertInWithGeneratorInvariants(foo)
257 self.assertAfterWithGeneratorInvariantsNoError(foo)
258
259 def testInlineGeneratorBoundToDottedVariable(self):
260 with mock_contextmanager_generator() as self.foo:
261 self.assertInWithGeneratorInvariants(self.foo)
262 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
263
264 def testBoundGenerator(self):
265 mock = mock_contextmanager_generator()
266 with mock as foo:
267 self.assertInWithGeneratorInvariants(foo)
268 self.assertInWithManagerInvariants(mock)
269 self.assertAfterWithGeneratorInvariantsNoError(foo)
270 self.assertAfterWithManagerInvariantsNoError(mock)
271
272 def testNestedSingleStatements(self):
273 mock_a = mock_contextmanager_generator()
274 with mock_a as foo:
275 mock_b = mock_contextmanager_generator()
276 with mock_b as bar:
277 self.assertInWithManagerInvariants(mock_a)
278 self.assertInWithManagerInvariants(mock_b)
279 self.assertInWithGeneratorInvariants(foo)
280 self.assertInWithGeneratorInvariants(bar)
281 self.assertAfterWithManagerInvariantsNoError(mock_b)
282 self.assertAfterWithGeneratorInvariantsNoError(bar)
283 self.assertInWithManagerInvariants(mock_a)
284 self.assertInWithGeneratorInvariants(foo)
285 self.assertAfterWithManagerInvariantsNoError(mock_a)
286 self.assertAfterWithGeneratorInvariantsNoError(foo)
287
288
289class NestedNonexceptionalTestCase(unittest.TestCase,
290 ContextmanagerAssertionMixin):
291 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000292 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000293 pass
294
Tim Peters400cbc32006-02-28 18:44:41 +0000295 def testSingleArgBoundToNonTuple(self):
296 m = mock_contextmanager_generator()
297 # This will bind all the arguments to nested() into a single list
298 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000299 with Nested(m) as foo:
Tim Peters400cbc32006-02-28 18:44:41 +0000300 self.assertInWithManagerInvariants(m)
301 self.assertAfterWithManagerInvariantsNoError(m)
302
303 def testSingleArgBoundToSingleElementParenthesizedList(self):
304 m = mock_contextmanager_generator()
305 # This will bind all the arguments to nested() into a single list
306 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000307 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000308 self.assertInWithManagerInvariants(m)
309 self.assertAfterWithManagerInvariantsNoError(m)
310
311 def testSingleArgBoundToMultipleElementTupleError(self):
312 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000313 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000314 pass
315 self.assertRaises(ValueError, shouldThrowValueError)
316
317 def testSingleArgUnbound(self):
318 mock_contextmanager = mock_contextmanager_generator()
319 mock_nested = MockNested(mock_contextmanager)
320 with mock_nested:
321 self.assertInWithManagerInvariants(mock_contextmanager)
322 self.assertInWithManagerInvariants(mock_nested)
323 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
324 self.assertAfterWithManagerInvariantsNoError(mock_nested)
325
326 def testMultipleArgUnbound(self):
327 m = mock_contextmanager_generator()
328 n = mock_contextmanager_generator()
329 o = mock_contextmanager_generator()
330 mock_nested = MockNested(m, n, o)
331 with mock_nested:
332 self.assertInWithManagerInvariants(m)
333 self.assertInWithManagerInvariants(n)
334 self.assertInWithManagerInvariants(o)
335 self.assertInWithManagerInvariants(mock_nested)
336 self.assertAfterWithManagerInvariantsNoError(m)
337 self.assertAfterWithManagerInvariantsNoError(n)
338 self.assertAfterWithManagerInvariantsNoError(o)
339 self.assertAfterWithManagerInvariantsNoError(mock_nested)
340
341 def testMultipleArgBound(self):
342 mock_nested = MockNested(mock_contextmanager_generator(),
343 mock_contextmanager_generator(), mock_contextmanager_generator())
344 with mock_nested as (m, n, o):
345 self.assertInWithGeneratorInvariants(m)
346 self.assertInWithGeneratorInvariants(n)
347 self.assertInWithGeneratorInvariants(o)
348 self.assertInWithManagerInvariants(mock_nested)
349 self.assertAfterWithGeneratorInvariantsNoError(m)
350 self.assertAfterWithGeneratorInvariantsNoError(n)
351 self.assertAfterWithGeneratorInvariantsNoError(o)
352 self.assertAfterWithManagerInvariantsNoError(mock_nested)
353
354
Collin Winterba21f612007-09-01 20:29:04 +0000355class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
Tim Peters400cbc32006-02-28 18:44:41 +0000356 def testSingleResource(self):
357 cm = mock_contextmanager_generator()
358 def shouldThrow():
359 with cm as self.resource:
360 self.assertInWithManagerInvariants(cm)
361 self.assertInWithGeneratorInvariants(self.resource)
362 self.raiseTestException()
363 self.assertRaises(RuntimeError, shouldThrow)
364 self.assertAfterWithManagerInvariantsWithError(cm)
365 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
366
Benjamin Peterson77aa6a72010-02-05 02:07:05 +0000367 def testExceptionNormalized(self):
368 cm = mock_contextmanager_generator()
369 def shouldThrow():
370 with cm as self.resource:
371 # Note this relies on the fact that 1 // 0 produces an exception
372 # that is not normalized immediately.
373 1 // 0
374 self.assertRaises(ZeroDivisionError, shouldThrow)
375 self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
376
Tim Peters400cbc32006-02-28 18:44:41 +0000377 def testNestedSingleStatements(self):
378 mock_a = mock_contextmanager_generator()
379 mock_b = mock_contextmanager_generator()
380 def shouldThrow():
381 with mock_a as self.foo:
382 with mock_b as self.bar:
383 self.assertInWithManagerInvariants(mock_a)
384 self.assertInWithManagerInvariants(mock_b)
385 self.assertInWithGeneratorInvariants(self.foo)
386 self.assertInWithGeneratorInvariants(self.bar)
387 self.raiseTestException()
388 self.assertRaises(RuntimeError, shouldThrow)
389 self.assertAfterWithManagerInvariantsWithError(mock_a)
390 self.assertAfterWithManagerInvariantsWithError(mock_b)
391 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
392 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
393
394 def testMultipleResourcesInSingleStatement(self):
395 cm_a = mock_contextmanager_generator()
396 cm_b = mock_contextmanager_generator()
397 mock_nested = MockNested(cm_a, cm_b)
398 def shouldThrow():
399 with mock_nested as (self.resource_a, self.resource_b):
400 self.assertInWithManagerInvariants(cm_a)
401 self.assertInWithManagerInvariants(cm_b)
402 self.assertInWithManagerInvariants(mock_nested)
403 self.assertInWithGeneratorInvariants(self.resource_a)
404 self.assertInWithGeneratorInvariants(self.resource_b)
405 self.raiseTestException()
406 self.assertRaises(RuntimeError, shouldThrow)
407 self.assertAfterWithManagerInvariantsWithError(cm_a)
408 self.assertAfterWithManagerInvariantsWithError(cm_b)
409 self.assertAfterWithManagerInvariantsWithError(mock_nested)
410 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
411 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
412
413 def testNestedExceptionBeforeInnerStatement(self):
414 mock_a = mock_contextmanager_generator()
415 mock_b = mock_contextmanager_generator()
416 self.bar = None
417 def shouldThrow():
418 with mock_a as self.foo:
419 self.assertInWithManagerInvariants(mock_a)
420 self.assertInWithGeneratorInvariants(self.foo)
421 self.raiseTestException()
422 with mock_b as self.bar:
423 pass
424 self.assertRaises(RuntimeError, shouldThrow)
425 self.assertAfterWithManagerInvariantsWithError(mock_a)
426 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
427
428 # The inner statement stuff should never have been touched
429 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000430 self.assertFalse(mock_b.enter_called)
431 self.assertFalse(mock_b.exit_called)
432 self.assertEqual(mock_b.exit_args, None)
433
434 def testNestedExceptionAfterInnerStatement(self):
435 mock_a = mock_contextmanager_generator()
436 mock_b = mock_contextmanager_generator()
437 def shouldThrow():
438 with mock_a as self.foo:
439 with mock_b as self.bar:
440 self.assertInWithManagerInvariants(mock_a)
441 self.assertInWithManagerInvariants(mock_b)
442 self.assertInWithGeneratorInvariants(self.foo)
443 self.assertInWithGeneratorInvariants(self.bar)
444 self.raiseTestException()
445 self.assertRaises(RuntimeError, shouldThrow)
446 self.assertAfterWithManagerInvariantsWithError(mock_a)
447 self.assertAfterWithManagerInvariantsNoError(mock_b)
448 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
449 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
450
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000451 def testRaisedStopIteration1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000452 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000453 @contextmanager
454 def cm():
455 yield
456
457 def shouldThrow():
458 with cm():
459 raise StopIteration("from with")
460
Martin Panter7e3a91a2016-02-10 04:40:48 +0000461 with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
Yury Selivanov68333392015-05-22 11:16:47 -0400462 self.assertRaises(StopIteration, shouldThrow)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000463
464 def testRaisedStopIteration2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000465 # From bug 1462485
Thomas Wouters477c8d52006-05-27 19:21:47 +0000466 class cm(object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000467 def __enter__(self):
468 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000469 def __exit__(self, type, value, traceback):
470 pass
471
472 def shouldThrow():
473 with cm():
474 raise StopIteration("from with")
475
476 self.assertRaises(StopIteration, shouldThrow)
477
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000478 def testRaisedStopIteration3(self):
479 # Another variant where the exception hasn't been instantiated
480 # From bug 1705170
481 @contextmanager
482 def cm():
483 yield
484
485 def shouldThrow():
486 with cm():
487 raise next(iter([]))
488
Martin Panter7e3a91a2016-02-10 04:40:48 +0000489 with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
Yury Selivanov68333392015-05-22 11:16:47 -0400490 self.assertRaises(StopIteration, shouldThrow)
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000491
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000492 def testRaisedGeneratorExit1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000493 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000494 @contextmanager
495 def cm():
496 yield
497
498 def shouldThrow():
499 with cm():
500 raise GeneratorExit("from with")
501
502 self.assertRaises(GeneratorExit, shouldThrow)
503
504 def testRaisedGeneratorExit2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000505 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000506 class cm (object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000507 def __enter__(self):
508 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000509 def __exit__(self, type, value, traceback):
510 pass
511
512 def shouldThrow():
513 with cm():
514 raise GeneratorExit("from with")
515
516 self.assertRaises(GeneratorExit, shouldThrow)
517
Amaury Forgeot d'Arc10b24e82008-12-10 23:49:33 +0000518 def testErrorsInBool(self):
519 # issue4589: __exit__ return code may raise an exception
520 # when looking at its truth value.
521
522 class cm(object):
523 def __init__(self, bool_conversion):
524 class Bool:
525 def __bool__(self):
526 return bool_conversion()
527 self.exit_result = Bool()
528 def __enter__(self):
529 return 3
530 def __exit__(self, a, b, c):
531 return self.exit_result
532
533 def trueAsBool():
534 with cm(lambda: True):
535 self.fail("Should NOT see this")
536 trueAsBool()
537
538 def falseAsBool():
539 with cm(lambda: False):
540 self.fail("Should raise")
541 self.assertRaises(AssertionError, falseAsBool)
542
543 def failAsBool():
544 with cm(lambda: 1//0):
545 self.fail("Should NOT see this")
546 self.assertRaises(ZeroDivisionError, failAsBool)
547
Tim Peters400cbc32006-02-28 18:44:41 +0000548
549class NonLocalFlowControlTestCase(unittest.TestCase):
550
551 def testWithBreak(self):
552 counter = 0
553 while True:
554 counter += 1
555 with mock_contextmanager_generator():
556 counter += 10
557 break
558 counter += 100 # Not reached
559 self.assertEqual(counter, 11)
560
561 def testWithContinue(self):
562 counter = 0
563 while True:
564 counter += 1
565 if counter > 2:
566 break
567 with mock_contextmanager_generator():
568 counter += 10
569 continue
570 counter += 100 # Not reached
571 self.assertEqual(counter, 12)
572
573 def testWithReturn(self):
574 def foo():
575 counter = 0
576 while True:
577 counter += 1
578 with mock_contextmanager_generator():
579 counter += 10
580 return counter
581 counter += 100 # Not reached
582 self.assertEqual(foo(), 11)
583
584 def testWithYield(self):
585 def gen():
586 with mock_contextmanager_generator():
587 yield 12
588 yield 13
589 x = list(gen())
590 self.assertEqual(x, [12, 13])
591
592 def testWithRaise(self):
593 counter = 0
594 try:
595 counter += 1
596 with mock_contextmanager_generator():
597 counter += 10
598 raise RuntimeError
599 counter += 100 # Not reached
600 except RuntimeError:
601 self.assertEqual(counter, 11)
602 else:
603 self.fail("Didn't raise RuntimeError")
604
605
606class AssignmentTargetTestCase(unittest.TestCase):
607
608 def testSingleComplexTarget(self):
609 targets = {1: [0, 1, 2]}
610 with mock_contextmanager_generator() as targets[1][0]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000611 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000612 self.assertEqual(targets[1][0].__class__, MockResource)
Guido van Rossum87b63952007-02-11 07:05:21 +0000613 with mock_contextmanager_generator() as list(targets.values())[0][1]:
614 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000615 self.assertEqual(targets[1][1].__class__, MockResource)
616 with mock_contextmanager_generator() as targets[2]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000617 keys = list(targets.keys())
Tim Peters400cbc32006-02-28 18:44:41 +0000618 keys.sort()
619 self.assertEqual(keys, [1, 2])
620 class C: pass
621 blah = C()
622 with mock_contextmanager_generator() as blah.foo:
623 self.assertEqual(hasattr(blah, "foo"), True)
624
625 def testMultipleComplexTargets(self):
626 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000627 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000628 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000629 targets = {1: [0, 1, 2]}
630 with C() as (targets[1][0], targets[1][1], targets[1][2]):
631 self.assertEqual(targets, {1: [1, 2, 3]})
Guido van Rossum87b63952007-02-11 07:05:21 +0000632 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 +0000633 self.assertEqual(targets, {1: [3, 2, 1]})
634 with C() as (targets[1], targets[2], targets[3]):
635 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
636 class B: pass
637 blah = B()
638 with C() as (blah.one, blah.two, blah.three):
639 self.assertEqual(blah.one, 1)
640 self.assertEqual(blah.two, 2)
641 self.assertEqual(blah.three, 3)
642
643
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000644class ExitSwallowsExceptionTestCase(unittest.TestCase):
645
Guido van Rossumf6694362006-03-10 02:28:35 +0000646 def testExitTrueSwallowsException(self):
647 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000648 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000649 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000650 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000651 with AfricanSwallow():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000652 1/0
653 except ZeroDivisionError:
654 self.fail("ZeroDivisionError should have been swallowed")
655
Guido van Rossumf6694362006-03-10 02:28:35 +0000656 def testExitFalseDoesntSwallowException(self):
657 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000658 def __enter__(self): pass
659 def __exit__(self, t, v, tb): return False
660 try:
661 with EuropeanSwallow():
662 1/0
663 except ZeroDivisionError:
664 pass
665 else:
666 self.fail("ZeroDivisionError should have been raised")
667
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000668
Georg Brandl0c315622009-05-25 21:10:36 +0000669class NestedWith(unittest.TestCase):
670
671 class Dummy(object):
672 def __init__(self, value=None, gobble=False):
673 if value is None:
674 value = self
675 self.value = value
676 self.gobble = gobble
677 self.enter_called = False
678 self.exit_called = False
679
680 def __enter__(self):
681 self.enter_called = True
682 return self.value
683
684 def __exit__(self, *exc_info):
685 self.exit_called = True
686 self.exc_info = exc_info
687 if self.gobble:
688 return True
689
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000690 class InitRaises(object):
Georg Brandl0c315622009-05-25 21:10:36 +0000691 def __init__(self): raise RuntimeError()
692
693 class EnterRaises(object):
694 def __enter__(self): raise RuntimeError()
695 def __exit__(self, *exc_info): pass
696
697 class ExitRaises(object):
698 def __enter__(self): pass
699 def __exit__(self, *exc_info): raise RuntimeError()
700
701 def testNoExceptions(self):
702 with self.Dummy() as a, self.Dummy() as b:
703 self.assertTrue(a.enter_called)
704 self.assertTrue(b.enter_called)
705 self.assertTrue(a.exit_called)
706 self.assertTrue(b.exit_called)
707
708 def testExceptionInExprList(self):
709 try:
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000710 with self.Dummy() as a, self.InitRaises():
Georg Brandl0c315622009-05-25 21:10:36 +0000711 pass
712 except:
713 pass
714 self.assertTrue(a.enter_called)
715 self.assertTrue(a.exit_called)
716
717 def testExceptionInEnter(self):
718 try:
719 with self.Dummy() as a, self.EnterRaises():
720 self.fail('body of bad with executed')
721 except RuntimeError:
722 pass
723 else:
724 self.fail('RuntimeError not reraised')
725 self.assertTrue(a.enter_called)
726 self.assertTrue(a.exit_called)
727
728 def testExceptionInExit(self):
729 body_executed = False
730 with self.Dummy(gobble=True) as a, self.ExitRaises():
731 body_executed = True
732 self.assertTrue(a.enter_called)
733 self.assertTrue(a.exit_called)
Benjamin Peterson78565b22009-06-28 19:19:51 +0000734 self.assertTrue(body_executed)
Georg Brandl0c315622009-05-25 21:10:36 +0000735 self.assertNotEqual(a.exc_info[0], None)
736
737 def testEnterReturnsTuple(self):
738 with self.Dummy(value=(1,2)) as (a1, a2), \
739 self.Dummy(value=(10, 20)) as (b1, b2):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000740 self.assertEqual(1, a1)
741 self.assertEqual(2, a2)
742 self.assertEqual(10, b1)
743 self.assertEqual(20, b2)
Georg Brandl0c315622009-05-25 21:10:36 +0000744
Tim Peters400cbc32006-02-28 18:44:41 +0000745if __name__ == '__main__':
Zachary Ware38c707e2015-04-13 15:00:43 -0500746 unittest.main()