Yeah, it requires a little magic... fortunately, said magic exists in
the Python standard library (functools module).
As far as I can tell, this is the preferred approach when adding
callbacks to the IOLoop (via add_timeout or add_callback), or as
callback arguments to methods on the IOStream or HTTPClient classes.
If you look at async_callback's implementation, it uses
functools.partial() to pickle arguments onto your callback, allowing
the "magic" callable value returned by partial() to be provided to
Tornado.
e.g.,
import functools
def http_callback(http_response_object, bar=None, baz=None):
# does fabulous things based on a tornado HTTPClient response object
pass
foo_param = "some additional state I want to pass to some_callback"
bar_param = "something else..."
...
httpclient_cb = functools.partial(http_callback, bar=bar_param, baz=baz_param)
and then you could use it like so:
import tornado.httpclient
hc = tornado.httpclient.AsyncHTTPClient(server)
hc.fetch("/some/url", httpclient_cb)
httpclient_cb will be called with the httpclient.HTTPResponse class as
the first argument, and functools.partial takes care of the rest of
your arguments.
Though I didn't show it, you can also pass positional args with
functools.partial, see the documentation
(http://docs.python.org/library/functools.html#functools.partial) for
more info.
For another code example, see the docstring on ioloop.py IOLoop class.
(https://github.com/facebook/tornado/blob/v2.0.0/tornado/ioloop.py#L54)
-a
--
Andrew Fort (af...@choqolat.org)
c = brukva.Client()c.connect()
self.set_header('Content-Type', 'text/html')class MainHandler(tornado.web.RequestHandler):@tornado.web.asynchronous@adisp.processdef get(self):foo, bar = yield c.async.get('foo'), c.async.get('bar') # that's it
self.render("template.html", title="Simple demo", foo=foo, bar=bar)
As an example, a problem I've had in a proxy (using IOStream
instances) lately was that of knowing a stream proxy connection was
successful.
In v.1.2.1, at least, an IOStream.connect() will call the callback you
supply even if the connection did not succeed, so to know for sure I
needed to do a write to the stream, as the write callback only occurs
when the write succeeded.
I passed the "header" (the bytes I was going to write) from the method
calling the stream connect to connect callback to the connect callback
to the write callback, by using functools.partial().
Inside the write callback, I set a self._connected = True variable
for the rest of the proxy connection to know it was OK to continue
with operations such as flushing the data which had buffered on the
connection class while the connection - and other asynchronous
operations such as connection authentication - were underway.
Cheers,
Andrew