1
2
3
4
5
6
7
8
9
10
11 __doc__='''Driver.py
12
13 Run generators that produce Deferreds.
14
15 twisted.flow has something like this, except I cannot understand it.
16
17 $Id$
18 '''
19
20 __version__ = "$Revision$"[11:-2]
21
22
23 from twisted.internet import defer, reactor
24 from twisted.python import failure
25 from Products.ZenUtils.Exceptions import resolveException
26
27
31
33 "Walk an iterable that returns a deferred."
34
38
39 - def drive(self, iterable):
40 "Call the iterable and set up callbacks to finish"
41 self.iter = iterable
42 self._next()
43 return self.defer
44
56
58 "Provide the result of the iterable as a value or exception"
59 ex = self.result
60 if isinstance(self.result, failure.Failure):
61 ex = resolveException(self.result)
62 if isinstance(ex, Exception):
63 raise ex
64 return self.result
65 next = result
66
69
75
77 '''Typical use of Driver class:
78
79 def walk(driver):
80 yield thing1()
81 a = driver.next()
82 print "Thing 1 is",
83 yield thing2()
84 b = driver.next()
85 print "Thing 2 is",
86 driver.finish(a + b)
87
88 drive(walk)
89
90 '''
91 d = Driver()
92 return d.drive(callable(d))
93
94
96 "Drive the callable at a later time"
97 d = defer.Deferred()
98 def driveAgain():
99 drive(callable).chainDeferred(d)
100 reactor.callLater(secs, driveAgain)
101 return d
102
103
110 def final(v):
111 assert lst[-1] == v
112 assert lst == range(10)
113 def unloop(d):
114 yield defer.fail(ZeroDivisionError('hahaha'))
115 d.next()
116 def checkError(err):
117 assert isinstance(err.value, ZeroDivisionError)
118 reactor.stop()
119 drive(unloop).addErrback(checkError)
120 drive(loop).addCallback(final)
121
122
123 if __name__ == '__main__':
124 test()
125 reactor.run()
126