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

Source Code for Module ZenUtils.Driver

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 as published by 
  8  # the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13  #! /usr/bin/env python  
 14   
 15  __doc__='''Driver.py 
 16   
 17  Run generators that produce Deferreds. 
 18   
 19  twisted.flow has something like this, except I cannot understand it. 
 20   
 21  $Id$ 
 22  ''' 
 23   
 24  __version__ = "$Revision$"[11:-2] 
 25   
 26   
 27  from twisted.internet import defer, reactor 
 28  from twisted.python import failure 
 29   
30 -class Driver:
31 "Walk an iterable that returns a deferred." 32
33 - def __init__(self):
34 self.defer = defer.Deferred() 35 self.result = None
36
37 - def drive(self, iterable):
38 "Call the iterable and set up callbacks to finish" 39 self.iter = iterable 40 self._next() 41 return self.defer
42
43 - def _next(self):
44 "Move on to the next iterable value" 45 try: 46 self.iter.next().addBoth(self._finish) 47 except StopIteration: 48 self.defer.callback(self.result) 49 except Exception, ex: 50 self.defer.errback(failure.Failure(ex))
51
52 - def next(self):
53 "Provide the result of the iterable as a value or exception" 54 ex = self.result 55 if isinstance(self.result, failure.Failure): 56 ex = self.result.value 57 if isinstance(ex, Exception): 58 raise ex 59 return self.result
60
61 - def _finish(self, result):
62 "Store the result of the last deferred for use in next()" 63 self.result = result 64 self._next()
65
66 -def drive(callable):
67 '''Typical use of Driver class: 68 69 def walk(driver): 70 yield thing1() 71 print "Thing 1 is", driver.next() 72 yeild thing2() 73 print "Thing 2 is", driver.next() 74 75 drive(walk) 76 77 ''' 78 d = Driver() 79 return d.drive(callable(d))
80 81
82 -def driveLater(secs, callable):
83 "Drive the callable at a later time" 84 d = defer.Deferred() 85 def driveAgain(): 86 drive(callable).chainDeferred(d)
87 reactor.callLater(secs, driveAgain) 88 return d 89 90
91 -def test():
92 lst = [] 93 def loop(d): 94 for i in range(10): 95 yield defer.succeed(i) 96 lst.append(d.next())
97 def final(v): 98 assert lst[-1] == v 99 drive(loop).addCallback(final) 100 assert lst == range(10) 101 def unloop(d): 102 yield defer.fail(ZeroDivisionError('hahaha')) 103 d.next() 104 def checkError(err): 105 assert isinstance(err.value, ZeroDivisionError) 106 drive(unloop).addErrback(checkError) 107 108 109 if __name__ == '__main__': 110 test() 111