1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Python 2.5+ test cases for failures thrown into generators.
11 from twisted.trial.unittest import TestCase
13 from twisted.python.failure import Failure
14 from twisted.internet import defer
16 # Re-implement getDivisionFailure here instead of using the one in
17 # test_failure.py in order to avoid creating a cyclic dependency.
18 def getDivisionFailure():
27 class TwoPointFiveFailureTests(TestCase):
29 def test_inlineCallbacksTracebacks(self):
31 inlineCallbacks that re-raise tracebacks into their deferred
32 should not lose their tracebacsk.
34 f = getDivisionFailure()
42 def collect_error(result):
43 failures.append(result)
47 ic = defer.inlineCallbacks(ic)
48 ic(d).addErrback(collect_error)
50 newFailure, = failures
52 traceback.extract_tb(newFailure.getTracebackObject())[-1][-1],
57 def _throwIntoGenerator(self, f, g):
59 f.throwExceptionIntoGenerator(g)
63 self.fail("throwExceptionIntoGenerator should have raised "
66 def test_throwExceptionIntoGenerator(self):
68 It should be possible to throw the exception that a Failure
69 represents into a generator.
76 stuff.append(sys.exc_info())
78 self.fail("Yield should have yielded exception.")
80 f = getDivisionFailure()
82 self._throwIntoGenerator(f, g)
84 self.assertEqual(stuff[0][0], ZeroDivisionError)
85 self.assertTrue(isinstance(stuff[0][1], ZeroDivisionError))
87 self.assertEqual(traceback.extract_tb(stuff[0][2])[-1][-1], "1/0")
90 def test_findFailureInGenerator(self):
92 Within an exception handler, it should be possible to find the
93 original Failure that caused the current exception (if it was
94 caused by throwExceptionIntoGenerator).
96 f = getDivisionFailure()
104 foundFailures.append(Failure._findFailure())
106 self.fail("No exception sent to generator")
110 self._throwIntoGenerator(f, g)
112 self.assertEqual(foundFailures, [f])
115 def test_failureConstructionFindsOriginalFailure(self):
117 When a Failure is constructed in the context of an exception
118 handler that is handling an exception raised by
119 throwExceptionIntoGenerator, the new Failure should be chained to that
122 f = getDivisionFailure()
131 newFailures.append(Failure())
133 self.fail("No exception sent to generator")
136 self._throwIntoGenerator(f, g)
138 self.assertEqual(len(newFailures), 1)
139 self.assertEqual(newFailures[0].getTraceback(), f.getTraceback())
141 def test_ambiguousFailureInGenerator(self):
143 When a generator reraises a different exception,
144 L{Failure._findFailure} inside the generator should find the reraised
145 exception rather than original one.
154 self.assertIsInstance(Failure().value, IndexError)
157 f = getDivisionFailure()
158 self._throwIntoGenerator(f, g)
160 def test_ambiguousFailureFromGenerator(self):
162 When a generator reraises a different exception,
163 L{Failure._findFailure} above the generator should find the reraised
164 exception rather than original one.
173 f = getDivisionFailure()
175 self._throwIntoGenerator(f, g)
177 self.assertIsInstance(Failure().value, IndexError)