1
from __future__ import generators, nested_scopes
5
from twisted.internet import reactor
7
from twisted.trial import unittest, util
9
from twisted.internet.defer import waitForDeferred, deferredGenerator, Deferred
10
from twisted.internet import defer
14
reactor.callLater(0, d.callback, "hi")
20
d.errback(ZeroDivisionError('OMG'))
21
reactor.callLater(0, CRAP)
24
# NOTE: most of the tests in DeferredGeneratorTests are duplicated
25
# with slightly different syntax for the InlineCallbacksTests below.
27
class TerminalException(Exception):
30
class BaseDefgenTests:
32
This class sets up a bunch of test cases which will test both
33
deferredGenerator and inlineCallbacks based generators. The subclasses
34
DeferredGeneratorTests and InlineCallbacksTests each provide the actual
35
generator implementations tested.
40
Test that a normal deferredGenerator works. Tests yielding a
41
deferred which callbacks, as well as a deferred errbacks. Also
42
ensures returning a final value works.
45
return self._genBasics().addCallback(self.assertEqual, 'WOOSH')
49
Ensure that a buggy generator properly signals a Failure
50
condition on result deferred.
52
return self.assertFailure(self._genBuggy(), ZeroDivisionError)
54
def testNothing(self):
55
"""Test that a generator which never yields results in None."""
57
return self._genNothing().addCallback(self.assertEqual, None)
59
def testHandledTerminalFailure(self):
61
Create a Deferred Generator which yields a Deferred which fails and
62
handles the exception which results. Assert that the Deferred
63
Generator does not errback its Deferred.
65
return self._genHandledTerminalFailure().addCallback(self.assertEqual, None)
67
def testHandledTerminalAsyncFailure(self):
69
Just like testHandledTerminalFailure, only with a Deferred which fires
70
asynchronously with an error.
73
deferredGeneratorResultDeferred = self._genHandledTerminalAsyncFailure(d)
74
d.errback(TerminalException("Handled Terminal Failure"))
75
return deferredGeneratorResultDeferred.addCallback(
76
self.assertEqual, None)
78
def testStackUsage(self):
80
Make sure we don't blow the stack when yielding immediately
83
return self._genStackUsage().addCallback(self.assertEqual, 0)
85
def testStackUsage2(self):
87
Make sure we don't blow the stack when yielding immediately
90
return self._genStackUsage2().addCallback(self.assertEqual, 0)
95
class DeferredGeneratorTests(BaseDefgenTests, unittest.TestCase):
97
# First provide all the generator impls necessary for BaseDefgenTests
100
x = waitForDeferred(getThing())
104
self.assertEquals(x, "hi")
106
ow = waitForDeferred(getOwie())
110
except ZeroDivisionError, e:
111
self.assertEquals(str(e), 'OMG')
114
_genBasics = deferredGenerator(_genBasics)
117
yield waitForDeferred(getThing())
119
_genBuggy = deferredGenerator(_genBuggy)
122
def _genNothing(self):
124
_genNothing = deferredGenerator(_genNothing)
126
def _genHandledTerminalFailure(self):
127
x = waitForDeferred(defer.fail(TerminalException("Handled Terminal Failure")))
131
except TerminalException:
133
_genHandledTerminalFailure = deferredGenerator(_genHandledTerminalFailure)
136
def _genHandledTerminalAsyncFailure(self, d):
137
x = waitForDeferred(d)
141
except TerminalException:
143
_genHandledTerminalAsyncFailure = deferredGenerator(_genHandledTerminalAsyncFailure)
146
def _genStackUsage(self):
147
for x in range(5000):
148
# Test with yielding a deferred
149
x = waitForDeferred(defer.succeed(1))
153
_genStackUsage = deferredGenerator(_genStackUsage)
155
def _genStackUsage2(self):
156
for x in range(5000):
157
# Test with yielding a random value
160
_genStackUsage2 = deferredGenerator(_genStackUsage2)
162
# Tests unique to deferredGenerator
164
def testDeferredYielding(self):
166
Ensure that yielding a Deferred directly is trapped as an
169
# See the comment _deferGenerator about d.callback(Deferred).
172
_genDeferred = deferredGenerator(_genDeferred)
174
return self.assertFailure(_genDeferred(), TypeError)
178
## This has to be in a string so the new yield syntax doesn't cause a
179
## syntax error in Python 2.4 and before.
180
inlineCallbacksTestsSource = '''
181
from twisted.internet.defer import inlineCallbacks, returnValue
183
class InlineCallbacksTests(BaseDefgenTests, unittest.TestCase):
184
# First provide all the generator impls necessary for BaseDefgenTests
186
def _genBasics(self):
190
self.assertEquals(x, "hi")
194
except ZeroDivisionError, e:
195
self.assertEquals(str(e), 'OMG')
197
_genBasics = inlineCallbacks(_genBasics)
202
_genBuggy = inlineCallbacks(_genBuggy)
205
def _genNothing(self):
207
_genNothing = inlineCallbacks(_genNothing)
210
def _genHandledTerminalFailure(self):
212
x = yield defer.fail(TerminalException("Handled Terminal Failure"))
213
except TerminalException:
215
_genHandledTerminalFailure = inlineCallbacks(_genHandledTerminalFailure)
218
def _genHandledTerminalAsyncFailure(self, d):
221
except TerminalException:
223
_genHandledTerminalAsyncFailure = inlineCallbacks(
224
_genHandledTerminalAsyncFailure)
227
def _genStackUsage(self):
228
for x in range(5000):
229
# Test with yielding a deferred
230
x = yield defer.succeed(1)
232
_genStackUsage = inlineCallbacks(_genStackUsage)
234
def _genStackUsage2(self):
235
for x in range(5000):
236
# Test with yielding a random value
239
_genStackUsage2 = inlineCallbacks(_genStackUsage2)
241
# Tests unique to inlineCallbacks
243
def testYieldNonDeferrred(self):
245
Ensure that yielding a non-deferred passes it back as the
246
result of the yield expression.
251
_test = inlineCallbacks(_test)
253
return _test().addCallback(self.assertEqual, 5)
255
def testReturnNoValue(self):
256
"""Ensure a standard python return results in a None result."""
260
_noReturn = inlineCallbacks(_noReturn)
262
return _noReturn().addCallback(self.assertEqual, None)
264
def testReturnValue(self):
265
"""Ensure that returnValue works."""
269
_return = inlineCallbacks(_return)
271
return _return().addCallback(self.assertEqual, 6)
275
if sys.version_info > (2, 5):
277
exec inlineCallbacksTestsSource
279
# Make a placeholder test case
280
class InlineCallbacksTests(unittest.TestCase):
281
skip = "defer.defgen doesn't run on python < 2.5."
282
def test_everything(self):