Package Products :: Package ZenUtils :: Module Driver
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenUtils.Driver

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved. 
  4  #  
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  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   
28 -class ShortCircuit:
29 - def __init__(self, value):
30 self.value = value
31
32 -class Driver:
33 "Walk an iterable that returns a deferred." 34
35 - def __init__(self):
36 self.defer = defer.Deferred() 37 self.result = None
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
45 - def _next(self):
46 "Move on to the next iterable value" 47 try: 48 self.iter.next().addBoth(self._finish) 49 except StopIteration: 50 self.defer.callback(self.result) 51 except ShortCircuit, ex: 52 self.result = ex.value 53 self.defer.callback(self.result) 54 except Exception, ex: 55 self.defer.errback(failure.Failure(ex))
56
57 - def result(self):
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 # historical name for result 66
67 - def finish(self, result):
68 raise ShortCircuit(result)
69
70 - def _finish(self, result):
71 "Store the result of the last deferred for use in next()" 72 self.result = result 73 # prevent endless recursion 74 reactor.callLater(0, self._next)
75
76 -def drive(callable):
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
95 -def driveLater(secs, callable):
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
104 -def test():
105 lst = [] 106 def loop(d): 107 for i in range(10): 108 yield defer.succeed(i) 109 lst.append(d.next())
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