[Twisted-Python] synchronous/asynchronous api: possible interface
Doug Farrell
doug.farrell at gmail.com
Fri Nov 13 07:32:25 MST 2009
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()
More information about the Twisted-Python
mailing list