blob: b1d7a15b5e4ee3ae9083d846fcbb57c6d1e9e999 [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
Yury Selivanov43c47fe2018-01-26 15:24:24 -0500461 with self.assertRaisesRegex(StopIteration, 'from with'):
462 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
Yury Selivanov43c47fe2018-01-26 15:24:24 -0500476 with self.assertRaisesRegex(StopIteration, 'from with'):
477 shouldThrow()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000478
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000479 def testRaisedStopIteration3(self):
480 # Another variant where the exception hasn't been instantiated
481 # From bug 1705170
482 @contextmanager
483 def cm():
484 yield
485
486 def shouldThrow():
487 with cm():
488 raise next(iter([]))
489
Yury Selivanov43c47fe2018-01-26 15:24:24 -0500490 with self.assertRaises(StopIteration):
491 shouldThrow()
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000492
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000493 def testRaisedGeneratorExit1(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000494 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000495 @contextmanager
496 def cm():
497 yield
498
499 def shouldThrow():
500 with cm():
501 raise GeneratorExit("from with")
502
503 self.assertRaises(GeneratorExit, shouldThrow)
504
505 def testRaisedGeneratorExit2(self):
Guido van Rossum2cc30da2007-11-02 23:46:40 +0000506 # From bug 1462485
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000507 class cm (object):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000508 def __enter__(self):
509 pass
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000510 def __exit__(self, type, value, traceback):
511 pass
512
513 def shouldThrow():
514 with cm():
515 raise GeneratorExit("from with")
516
517 self.assertRaises(GeneratorExit, shouldThrow)
518
Amaury Forgeot d'Arc10b24e82008-12-10 23:49:33 +0000519 def testErrorsInBool(self):
520 # issue4589: __exit__ return code may raise an exception
521 # when looking at its truth value.
522
523 class cm(object):
524 def __init__(self, bool_conversion):
525 class Bool:
526 def __bool__(self):
527 return bool_conversion()
528 self.exit_result = Bool()
529 def __enter__(self):
530 return 3
531 def __exit__(self, a, b, c):
532 return self.exit_result
533
534 def trueAsBool():
535 with cm(lambda: True):
536 self.fail("Should NOT see this")
537 trueAsBool()
538
539 def falseAsBool():
540 with cm(lambda: False):
541 self.fail("Should raise")
542 self.assertRaises(AssertionError, falseAsBool)
543
544 def failAsBool():
545 with cm(lambda: 1//0):
546 self.fail("Should NOT see this")
547 self.assertRaises(ZeroDivisionError, failAsBool)
548
Tim Peters400cbc32006-02-28 18:44:41 +0000549
550class NonLocalFlowControlTestCase(unittest.TestCase):
551
552 def testWithBreak(self):
553 counter = 0
554 while True:
555 counter += 1
556 with mock_contextmanager_generator():
557 counter += 10
558 break
559 counter += 100 # Not reached
560 self.assertEqual(counter, 11)
561
562 def testWithContinue(self):
563 counter = 0
564 while True:
565 counter += 1
566 if counter > 2:
567 break
568 with mock_contextmanager_generator():
569 counter += 10
570 continue
571 counter += 100 # Not reached
572 self.assertEqual(counter, 12)
573
574 def testWithReturn(self):
575 def foo():
576 counter = 0
577 while True:
578 counter += 1
579 with mock_contextmanager_generator():
580 counter += 10
581 return counter
582 counter += 100 # Not reached
583 self.assertEqual(foo(), 11)
584
585 def testWithYield(self):
586 def gen():
587 with mock_contextmanager_generator():
588 yield 12
589 yield 13
590 x = list(gen())
591 self.assertEqual(x, [12, 13])
592
593 def testWithRaise(self):
594 counter = 0
595 try:
596 counter += 1
597 with mock_contextmanager_generator():
598 counter += 10
599 raise RuntimeError
600 counter += 100 # Not reached
601 except RuntimeError:
602 self.assertEqual(counter, 11)
603 else:
604 self.fail("Didn't raise RuntimeError")
605
606
607class AssignmentTargetTestCase(unittest.TestCase):
608
609 def testSingleComplexTarget(self):
610 targets = {1: [0, 1, 2]}
611 with mock_contextmanager_generator() as targets[1][0]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000612 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000613 self.assertEqual(targets[1][0].__class__, MockResource)
Guido van Rossum87b63952007-02-11 07:05:21 +0000614 with mock_contextmanager_generator() as list(targets.values())[0][1]:
615 self.assertEqual(list(targets.keys()), [1])
Tim Peters400cbc32006-02-28 18:44:41 +0000616 self.assertEqual(targets[1][1].__class__, MockResource)
617 with mock_contextmanager_generator() as targets[2]:
Guido van Rossum87b63952007-02-11 07:05:21 +0000618 keys = list(targets.keys())
Tim Peters400cbc32006-02-28 18:44:41 +0000619 keys.sort()
620 self.assertEqual(keys, [1, 2])
621 class C: pass
622 blah = C()
623 with mock_contextmanager_generator() as blah.foo:
624 self.assertEqual(hasattr(blah, "foo"), True)
625
626 def testMultipleComplexTargets(self):
627 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000628 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000629 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000630 targets = {1: [0, 1, 2]}
631 with C() as (targets[1][0], targets[1][1], targets[1][2]):
632 self.assertEqual(targets, {1: [1, 2, 3]})
Guido van Rossum87b63952007-02-11 07:05:21 +0000633 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 +0000634 self.assertEqual(targets, {1: [3, 2, 1]})
635 with C() as (targets[1], targets[2], targets[3]):
636 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
637 class B: pass
638 blah = B()
639 with C() as (blah.one, blah.two, blah.three):
640 self.assertEqual(blah.one, 1)
641 self.assertEqual(blah.two, 2)
642 self.assertEqual(blah.three, 3)
643
644
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000645class ExitSwallowsExceptionTestCase(unittest.TestCase):
646
Guido van Rossumf6694362006-03-10 02:28:35 +0000647 def testExitTrueSwallowsException(self):
648 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000649 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000650 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000651 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000652 with AfricanSwallow():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000653 1/0
654 except ZeroDivisionError:
655 self.fail("ZeroDivisionError should have been swallowed")
656
Guido van Rossumf6694362006-03-10 02:28:35 +0000657 def testExitFalseDoesntSwallowException(self):
658 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000659 def __enter__(self): pass
660 def __exit__(self, t, v, tb): return False
661 try:
662 with EuropeanSwallow():
663 1/0
664 except ZeroDivisionError:
665 pass
666 else:
667 self.fail("ZeroDivisionError should have been raised")
668
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000669
Georg Brandl0c315622009-05-25 21:10:36 +0000670class NestedWith(unittest.TestCase):
671
672 class Dummy(object):
673 def __init__(self, value=None, gobble=False):
674 if value is None:
675 value = self
676 self.value = value
677 self.gobble = gobble
678 self.enter_called = False
679 self.exit_called = False
680
681 def __enter__(self):
682 self.enter_called = True
683 return self.value
684
685 def __exit__(self, *exc_info):
686 self.exit_called = True
687 self.exc_info = exc_info
688 if self.gobble:
689 return True
690
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000691 class InitRaises(object):
Georg Brandl0c315622009-05-25 21:10:36 +0000692 def __init__(self): raise RuntimeError()
693
694 class EnterRaises(object):
695 def __enter__(self): raise RuntimeError()
696 def __exit__(self, *exc_info): pass
697
698 class ExitRaises(object):
699 def __enter__(self): pass
700 def __exit__(self, *exc_info): raise RuntimeError()
701
702 def testNoExceptions(self):
703 with self.Dummy() as a, self.Dummy() as b:
704 self.assertTrue(a.enter_called)
705 self.assertTrue(b.enter_called)
706 self.assertTrue(a.exit_called)
707 self.assertTrue(b.exit_called)
708
709 def testExceptionInExprList(self):
710 try:
Georg Brandl3cfdd9c2009-06-04 10:21:10 +0000711 with self.Dummy() as a, self.InitRaises():
Georg Brandl0c315622009-05-25 21:10:36 +0000712 pass
713 except:
714 pass
715 self.assertTrue(a.enter_called)
716 self.assertTrue(a.exit_called)
717
718 def testExceptionInEnter(self):
719 try:
720 with self.Dummy() as a, self.EnterRaises():
721 self.fail('body of bad with executed')
722 except RuntimeError:
723 pass
724 else:
725 self.fail('RuntimeError not reraised')
726 self.assertTrue(a.enter_called)
727 self.assertTrue(a.exit_called)
728
729 def testExceptionInExit(self):
730 body_executed = False
731 with self.Dummy(gobble=True) as a, self.ExitRaises():
732 body_executed = True
733 self.assertTrue(a.enter_called)
734 self.assertTrue(a.exit_called)
Benjamin Peterson78565b22009-06-28 19:19:51 +0000735 self.assertTrue(body_executed)
Georg Brandl0c315622009-05-25 21:10:36 +0000736 self.assertNotEqual(a.exc_info[0], None)
737
738 def testEnterReturnsTuple(self):
739 with self.Dummy(value=(1,2)) as (a1, a2), \
740 self.Dummy(value=(10, 20)) as (b1, b2):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000741 self.assertEqual(1, a1)
742 self.assertEqual(2, a2)
743 self.assertEqual(10, b1)
744 self.assertEqual(20, b2)
Georg Brandl0c315622009-05-25 21:10:36 +0000745
Tim Peters400cbc32006-02-28 18:44:41 +0000746if __name__ == '__main__':
Zachary Ware38c707e2015-04-13 15:00:43 -0500747 unittest.main()