]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/python/contrib/Lib/test/test_with.py
Inital import
[l4.git] / l4 / pkg / python / contrib / Lib / test / test_with.py
1 #!/usr/bin/env python
2
3 """Unit tests for the with statement specified in PEP 343."""
4
5
6 __author__ = "Mike Bland"
7 __email__ = "mbland at acm dot org"
8
9 import sys
10 import unittest
11 from collections import deque
12 from contextlib import GeneratorContextManager, contextmanager
13 from test.test_support import run_unittest
14
15
16 class MockContextManager(GeneratorContextManager):
17     def __init__(self, gen):
18         GeneratorContextManager.__init__(self, gen)
19         self.enter_called = False
20         self.exit_called = False
21         self.exit_args = None
22
23     def __enter__(self):
24         self.enter_called = True
25         return GeneratorContextManager.__enter__(self)
26
27     def __exit__(self, type, value, traceback):
28         self.exit_called = True
29         self.exit_args = (type, value, traceback)
30         return GeneratorContextManager.__exit__(self, type,
31                                                 value, traceback)
32
33
34 def mock_contextmanager(func):
35     def helper(*args, **kwds):
36         return MockContextManager(func(*args, **kwds))
37     return helper
38
39
40 class MockResource(object):
41     def __init__(self):
42         self.yielded = False
43         self.stopped = False
44
45
46 @mock_contextmanager
47 def mock_contextmanager_generator():
48     mock = MockResource()
49     try:
50         mock.yielded = True
51         yield mock
52     finally:
53         mock.stopped = True
54
55
56 class Nested(object):
57
58     def __init__(self, *managers):
59         self.managers = managers
60         self.entered = None
61
62     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:
68             for mgr in self.managers:
69                 vars.append(mgr.__enter__())
70                 self.entered.appendleft(mgr)
71         except:
72             if not self.__exit__(*sys.exc_info()):
73                 raise
74         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:
83                 if mgr.__exit__(*ex):
84                     ex = (None, None, None)
85             except:
86                 ex = sys.exc_info()
87         self.entered = None
88         if ex is not exc_info:
89             raise ex[0], ex[1], ex[2]
90
91
92 class MockNested(Nested):
93     def __init__(self, *managers):
94         Nested.__init__(self, *managers)
95         self.enter_called = False
96         self.exit_called = False
97         self.exit_args = None
98
99     def __enter__(self):
100         self.enter_called = True
101         return Nested.__enter__(self)
102
103     def __exit__(self, *exc_info):
104         self.exit_called = True
105         self.exit_args = exc_info
106         return Nested.__exit__(self, *exc_info)
107
108
109 class FailureTestCase(unittest.TestCase):
110     def testNameError(self):
111         def fooNotDeclared():
112             with foo: pass
113         self.assertRaises(NameError, fooNotDeclared)
114
115     def testEnterAttributeError(self):
116         class LacksEnter(object):
117             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):
127             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
162     def testEnterThrows(self):
163         class EnterThrows(object):
164             def __enter__(self):
165                 raise RuntimeError("Enter threw")
166             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):
179             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
188 class ContextmanagerAssertionMixin(object):
189     TEST_EXCEPTION = RuntimeError("test exception")
190
191     def assertInWithManagerInvariants(self, mock_manager):
192         self.assertTrue(mock_manager.enter_called)
193         self.assertFalse(mock_manager.exit_called)
194         self.assertEqual(mock_manager.exit_args, None)
195
196     def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
197         self.assertTrue(mock_manager.enter_called)
198         self.assertTrue(mock_manager.exit_called)
199         self.assertEqual(mock_manager.exit_args, exit_args)
200
201     def assertAfterWithManagerInvariantsNoError(self, mock_manager):
202         self.assertAfterWithManagerInvariants(mock_manager,
203             (None, None, None))
204
205     def assertInWithGeneratorInvariants(self, mock_generator):
206         self.assertTrue(mock_generator.yielded)
207         self.assertFalse(mock_generator.stopped)
208
209     def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
210         self.assertTrue(mock_generator.yielded)
211         self.assertTrue(mock_generator.stopped)
212
213     def raiseTestException(self):
214         raise self.TEST_EXCEPTION
215
216     def assertAfterWithManagerInvariantsWithError(self, mock_manager):
217         self.assertTrue(mock_manager.enter_called)
218         self.assertTrue(mock_manager.exit_called)
219         self.assertEqual(mock_manager.exit_args[0], RuntimeError)
220         self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
221
222     def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
223         self.assertTrue(mock_generator.yielded)
224         self.assertTrue(mock_generator.stopped)
225
226
227 class 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
280 class NestedNonexceptionalTestCase(unittest.TestCase,
281     ContextmanagerAssertionMixin):
282     def testSingleArgInlineGeneratorSyntax(self):
283         with Nested(mock_contextmanager_generator()):
284             pass
285
286     def testSingleArgUnbound(self):
287         mock_contextmanager = mock_contextmanager_generator()
288         mock_nested = MockNested(mock_contextmanager)
289         with mock_nested:
290             self.assertInWithManagerInvariants(mock_contextmanager)
291             self.assertInWithManagerInvariants(mock_nested)
292         self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
293         self.assertAfterWithManagerInvariantsNoError(mock_nested)
294
295     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.
299         with Nested(m) as foo:
300             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.
307         with Nested(m) as (foo):
308             self.assertInWithManagerInvariants(m)
309         self.assertAfterWithManagerInvariantsNoError(m)
310
311     def testSingleArgBoundToMultipleElementTupleError(self):
312         def shouldThrowValueError():
313             with Nested(mock_contextmanager_generator()) as (foo, bar):
314                 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
355 class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
356     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
367     def testNestedSingleStatements(self):
368         mock_a = mock_contextmanager_generator()
369         mock_b = mock_contextmanager_generator()
370         def shouldThrow():
371             with mock_a as self.foo:
372                 with mock_b as self.bar:
373                     self.assertInWithManagerInvariants(mock_a)
374                     self.assertInWithManagerInvariants(mock_b)
375                     self.assertInWithGeneratorInvariants(self.foo)
376                     self.assertInWithGeneratorInvariants(self.bar)
377                     self.raiseTestException()
378         self.assertRaises(RuntimeError, shouldThrow)
379         self.assertAfterWithManagerInvariantsWithError(mock_a)
380         self.assertAfterWithManagerInvariantsWithError(mock_b)
381         self.assertAfterWithGeneratorInvariantsWithError(self.foo)
382         self.assertAfterWithGeneratorInvariantsWithError(self.bar)
383
384     def testMultipleResourcesInSingleStatement(self):
385         cm_a = mock_contextmanager_generator()
386         cm_b = mock_contextmanager_generator()
387         mock_nested = MockNested(cm_a, cm_b)
388         def shouldThrow():
389             with mock_nested as (self.resource_a, self.resource_b):
390                 self.assertInWithManagerInvariants(cm_a)
391                 self.assertInWithManagerInvariants(cm_b)
392                 self.assertInWithManagerInvariants(mock_nested)
393                 self.assertInWithGeneratorInvariants(self.resource_a)
394                 self.assertInWithGeneratorInvariants(self.resource_b)
395                 self.raiseTestException()
396         self.assertRaises(RuntimeError, shouldThrow)
397         self.assertAfterWithManagerInvariantsWithError(cm_a)
398         self.assertAfterWithManagerInvariantsWithError(cm_b)
399         self.assertAfterWithManagerInvariantsWithError(mock_nested)
400         self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
401         self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
402
403     def testNestedExceptionBeforeInnerStatement(self):
404         mock_a = mock_contextmanager_generator()
405         mock_b = mock_contextmanager_generator()
406         self.bar = None
407         def shouldThrow():
408             with mock_a as self.foo:
409                 self.assertInWithManagerInvariants(mock_a)
410                 self.assertInWithGeneratorInvariants(self.foo)
411                 self.raiseTestException()
412                 with mock_b as self.bar:
413                     pass
414         self.assertRaises(RuntimeError, shouldThrow)
415         self.assertAfterWithManagerInvariantsWithError(mock_a)
416         self.assertAfterWithGeneratorInvariantsWithError(self.foo)
417
418         # The inner statement stuff should never have been touched
419         self.assertEqual(self.bar, None)
420         self.assertFalse(mock_b.enter_called)
421         self.assertFalse(mock_b.exit_called)
422         self.assertEqual(mock_b.exit_args, None)
423
424     def testNestedExceptionAfterInnerStatement(self):
425         mock_a = mock_contextmanager_generator()
426         mock_b = mock_contextmanager_generator()
427         def shouldThrow():
428             with mock_a as self.foo:
429                 with mock_b as self.bar:
430                     self.assertInWithManagerInvariants(mock_a)
431                     self.assertInWithManagerInvariants(mock_b)
432                     self.assertInWithGeneratorInvariants(self.foo)
433                     self.assertInWithGeneratorInvariants(self.bar)
434                 self.raiseTestException()
435         self.assertRaises(RuntimeError, shouldThrow)
436         self.assertAfterWithManagerInvariantsWithError(mock_a)
437         self.assertAfterWithManagerInvariantsNoError(mock_b)
438         self.assertAfterWithGeneratorInvariantsWithError(self.foo)
439         self.assertAfterWithGeneratorInvariantsNoError(self.bar)
440
441     def testRaisedStopIteration1(self):
442         # From bug 1462485
443         @contextmanager
444         def cm():
445             yield
446
447         def shouldThrow():
448             with cm():
449                 raise StopIteration("from with")
450
451         self.assertRaises(StopIteration, shouldThrow)
452
453     def testRaisedStopIteration2(self):
454         # From bug 1462485
455         class cm(object):
456             def __enter__(self):
457                 pass
458             def __exit__(self, type, value, traceback):
459                 pass
460
461         def shouldThrow():
462             with cm():
463                 raise StopIteration("from with")
464
465         self.assertRaises(StopIteration, shouldThrow)
466
467     def testRaisedStopIteration3(self):
468         # Another variant where the exception hasn't been instantiated
469         # From bug 1705170
470         @contextmanager
471         def cm():
472             yield
473
474         def shouldThrow():
475             with cm():
476                 raise iter([]).next()
477
478         self.assertRaises(StopIteration, shouldThrow)
479
480     def testRaisedGeneratorExit1(self):
481         # From bug 1462485
482         @contextmanager
483         def cm():
484             yield
485
486         def shouldThrow():
487             with cm():
488                 raise GeneratorExit("from with")
489
490         self.assertRaises(GeneratorExit, shouldThrow)
491
492     def testRaisedGeneratorExit2(self):
493         # From bug 1462485
494         class cm (object):
495             def __enter__(self):
496                 pass
497             def __exit__(self, type, value, traceback):
498                 pass
499
500         def shouldThrow():
501             with cm():
502                 raise GeneratorExit("from with")
503
504         self.assertRaises(GeneratorExit, shouldThrow)
505
506     def testErrorsInBool(self):
507         # issue4589: __exit__ return code may raise an exception
508         # when looking at its truth value.
509
510         class cm(object):
511             def __init__(self, bool_conversion):
512                 class Bool:
513                     def __nonzero__(self):
514                         return bool_conversion()
515                 self.exit_result = Bool()
516             def __enter__(self):
517                 return 3
518             def __exit__(self, a, b, c):
519                 return self.exit_result
520
521         def trueAsBool():
522             with cm(lambda: True):
523                 self.fail("Should NOT see this")
524         trueAsBool()
525
526         def falseAsBool():
527             with cm(lambda: False):
528                 self.fail("Should raise")
529         self.assertRaises(AssertionError, falseAsBool)
530
531         def failAsBool():
532             with cm(lambda: 1//0):
533                 self.fail("Should NOT see this")
534         self.assertRaises(ZeroDivisionError, failAsBool)
535
536
537 class NonLocalFlowControlTestCase(unittest.TestCase):
538
539     def testWithBreak(self):
540         counter = 0
541         while True:
542             counter += 1
543             with mock_contextmanager_generator():
544                 counter += 10
545                 break
546             counter += 100 # Not reached
547         self.assertEqual(counter, 11)
548
549     def testWithContinue(self):
550         counter = 0
551         while True:
552             counter += 1
553             if counter > 2:
554                 break
555             with mock_contextmanager_generator():
556                 counter += 10
557                 continue
558             counter += 100 # Not reached
559         self.assertEqual(counter, 12)
560
561     def testWithReturn(self):
562         def foo():
563             counter = 0
564             while True:
565                 counter += 1
566                 with mock_contextmanager_generator():
567                     counter += 10
568                     return counter
569                 counter += 100 # Not reached
570         self.assertEqual(foo(), 11)
571
572     def testWithYield(self):
573         def gen():
574             with mock_contextmanager_generator():
575                 yield 12
576                 yield 13
577         x = list(gen())
578         self.assertEqual(x, [12, 13])
579
580     def testWithRaise(self):
581         counter = 0
582         try:
583             counter += 1
584             with mock_contextmanager_generator():
585                 counter += 10
586                 raise RuntimeError
587             counter += 100 # Not reached
588         except RuntimeError:
589             self.assertEqual(counter, 11)
590         else:
591             self.fail("Didn't raise RuntimeError")
592
593
594 class AssignmentTargetTestCase(unittest.TestCase):
595
596     def testSingleComplexTarget(self):
597         targets = {1: [0, 1, 2]}
598         with mock_contextmanager_generator() as targets[1][0]:
599             self.assertEqual(targets.keys(), [1])
600             self.assertEqual(targets[1][0].__class__, MockResource)
601         with mock_contextmanager_generator() as targets.values()[0][1]:
602             self.assertEqual(targets.keys(), [1])
603             self.assertEqual(targets[1][1].__class__, MockResource)
604         with mock_contextmanager_generator() as targets[2]:
605             keys = targets.keys()
606             keys.sort()
607             self.assertEqual(keys, [1, 2])
608         class C: pass
609         blah = C()
610         with mock_contextmanager_generator() as blah.foo:
611             self.assertEqual(hasattr(blah, "foo"), True)
612
613     def testMultipleComplexTargets(self):
614         class C:
615             def __enter__(self): return 1, 2, 3
616             def __exit__(self, t, v, tb): pass
617         targets = {1: [0, 1, 2]}
618         with C() as (targets[1][0], targets[1][1], targets[1][2]):
619             self.assertEqual(targets, {1: [1, 2, 3]})
620         with C() as (targets.values()[0][2], targets.values()[0][1], targets.values()[0][0]):
621             self.assertEqual(targets, {1: [3, 2, 1]})
622         with C() as (targets[1], targets[2], targets[3]):
623             self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
624         class B: pass
625         blah = B()
626         with C() as (blah.one, blah.two, blah.three):
627             self.assertEqual(blah.one, 1)
628             self.assertEqual(blah.two, 2)
629             self.assertEqual(blah.three, 3)
630
631
632 class ExitSwallowsExceptionTestCase(unittest.TestCase):
633
634     def testExitTrueSwallowsException(self):
635         class AfricanSwallow:
636             def __enter__(self): pass
637             def __exit__(self, t, v, tb): return True
638         try:
639             with AfricanSwallow():
640                 1/0
641         except ZeroDivisionError:
642             self.fail("ZeroDivisionError should have been swallowed")
643
644     def testExitFalseDoesntSwallowException(self):
645         class EuropeanSwallow:
646             def __enter__(self): pass
647             def __exit__(self, t, v, tb): return False
648         try:
649             with EuropeanSwallow():
650                 1/0
651         except ZeroDivisionError:
652             pass
653         else:
654             self.fail("ZeroDivisionError should have been raised")
655
656
657 def test_main():
658     run_unittest(FailureTestCase, NonexceptionalTestCase,
659                  NestedNonexceptionalTestCase, ExceptionalTestCase,
660                  NonLocalFlowControlTestCase,
661                  AssignmentTargetTestCase,
662                  ExitSwallowsExceptionTestCase)
663
664
665 if __name__ == '__main__':
666     test_main()