[Twisted-Python] synchronous/asynchronous api: possible interface

Hi all, I'd like to get some comments on the code below (including, "don't be a bonehead!" <g>). I'm trying to write a API library for database access that can be used by both synchronous (non-twisted, no reactor) code and asynchronous (twisted, with reactor) code where the methods of the library can called in either environment. What I'd like is the method to return the results of the call (database query results) when in synchronous mode, and a deferred that is a result of the database call in asynchronous mode. What I've done below is create a decorator class called CallerMode that is used to decorate a function/method that normally returns a deferred. If the CallerMode class is in synchronous mode it starts a reactor to get the default callbacks to get called, which gets the results or exceptions, and stops the reactor. Am I being a dunce doing this kind of thing? Any suggestions, comments, etc. are welcome. Thanks! Doug import sys from functools import wraps from twisted.internet import reactor from twisted.python import log from twisted.web.client import getPage class CallerMode(object): '''This is a decorator class to make calls to an api play nice in synchronous or asynchronous mode''' ASYNCH = 'asynch' SYNCH = 'synch' STATE = SYNCH def __init__(self): self.retval = None def __call__(self, f): '''This provides the decorator function wrapper, which will return a deferred for asynchronous mode and the results of the wrapped function in synchronous mode''' def CB(result): self.retval = result reactor.stop() def EB(failure): reactor.stop() failure.raiseException() @wraps(f) def func(*args, **kwargs): d = f(*args, **kwargs) if CallerMode.STATE == CallerMode.SYNCH: d.addCallback(CB).addErrback(EB) reactor.run() return self.retval if CallerMode.STATE == CallerMode.SYNCH else d return func class Library(object): '''This is just a class to provide an API to call for data, in this case just using getPage() to get a deferred that gets some data, vs. having to set up a database for this test program ''' def __init__(self): log.msg('MyLib has been initialized') self._retval = None @CallerMode() def page(self): return getPage('http://www.google.com') def doSomethingWithData(data): log.msg(data) log.FileLogObserver.timeFormat = '%Y-%m-%d %H:%M:%S' log.startLogging(sys.stdout) lib = Library() #CallerMode.STATE = CallerMode.ASYNCH CallerMode.STATE = CallerMode.SYNCH # call the library API method result = lib.page() # depending on the CallerMode, handle the results differently if CallerMode.STATE == CallerMode.SYNCH: doSomethingWithData(result) elif CallerMode.STATE == CallerMode.ASYNCH: result.addCallback(doSomethingWithData) reactor.run()

On 02:32 pm, doug.farrell@gmail.com wrote:
If you add a second call to your example function in synchronous mode, I think you'll notice there's a problem - you can only start and stop the reactor once. Jean-Paul

On 02:32 pm, doug.farrell@gmail.com wrote:
If you add a second call to your example function in synchronous mode, I think you'll notice there's a problem - you can only start and stop the reactor once. Jean-Paul
participants (2)
-
Doug Farrell
-
exarkun@twistedmatrix.com