InlineCallback Friendly ? Re: [Twisted-Python] Question about Using in ServerProtocol request Handler

Jean-Paul Calderone exarkun at divmod.com
Wed Feb 20 15:25:14 EST 2008


On Wed, 20 Feb 2008 11:50:08 -0800 (PST), Andrew Francis <andrewfr_ice at yahoo.com> wrote:
>Hi Jean-Paul:
>
>>However, how is this done with just deferreds and
>>callbacks without Stackless or inlineCallbacks?
>
>Thanks for the response. And thanks for the
>explanation of inlineCallbacks. Annotating your
>example, I get  the following:
>
> def process(self):
>        def callback(result):
>            print "second"
>            self.setHeader('Content-Type', 'text/html')
>            self.write(result)
>            self.finish()
>        def errback(err):
>            err.trap(Exception)
>            log.err(err, "process getPage call failed")
>        try:
>            d = client.getPage("http://www.google.com")
>        except Exception:
>            d = failure.Failure()
>        d.addCallbacks(callback, errback)
>        print "first"
>
>running this I get what I expected
>
>"first"
>"second"
>
>This example I can follow. The server protocol handler
>terminates. The callback eventually fires. Since the
>callback has a reference to the request, it can write
>back the response.
>
>Bear with me, I am just starting to read up on
>protocols...
>
>What I am unclear on, is why some Server Protocols
>depend on 'return' and others don't (I assume with
>HTTP, you can stream a response). What is the right
>way to design a ServerProtocol? Is there an
>'inclineCallback' friendly protocol

Depending on the value returned by a method is an API decision made
by whoever implemented the protocol.  They came to the decision, at
some point, that the convenient way for applications to specify the
result is to return it from a method.  Or, they didn't and provided
some other API for specifying results.

Basically, we're talking about how protocol actions get dispatched
and how the result of dispatching them is handled.  You can have a
dispatcher which calls a method and ignores the result, requiring
that the result be handed back through some explicit API.  An example
of this is twisted.web's Request class.  The process method of the
request is called.  The result is specified by calling the write
method (possibly more than once) and then the finish method.  The
return value from process is ignored.  Another kind of dispatcher
might take the return value of the function dispatched to and treat
it as the result.  It might support Deferreds or it might not. An
example of this is twisted.mail's POP3 server implementation (which
happens to support Deferreds in most places, but not all).

The only kind of dispatcher which is really hostile towards
inlineCallbacks is the kind which is hostile towards Deferreds in
general - ie, one which requires a return value and does not support
Deferreds.

>
>Unless I am fundamentally missing something it seems
>that there are advantages to designing a Server
>Protocol not to depend on 'return'

Not really.  It's just an API.  Unless the return value isn't allowed
to be a Deferred, there's little difference between using the return
value and ignoring it.

>
>As I alluded to in other posts, I get confused over
>this variation.
>
>This is pyAMF
>
>class pyAMFTest(TwistedGateway):
>    def __init__(self):
>        super(TubeTest, self).__init__()
>        return
>
>    def echo(self, x):
>        print x
>        return x
>
>pretend I wish to do a callRemote(...)
>
>def echo(self, x):
>    def callback(result):
>        print "second"
>        """
>        How do I return x?
>        """

You return x by returning x.  That is, `return x´. ;)  But see
below.

>
>    def errback(err):
>        err.trap(Exception)
>        log.err(err, "process getPage call failed")
>    try:
>        proxy = ....
>        d = proxy.callRemote(...)
>    except Exception:
>        d = failure.Failure()
>    d.addCallbacks(callback, errback)
>    print "first"

The function ends here, and the Deferred which will ultimately have
the result you're interested in has *not* been returned.  It should
have been so that the dispatcher (which, near as I can tell, does
support Deferreds) can get it.  So, `return d´ after the print.

>
>In this case, how is 'x' transmitted back to the
>reactor and the client? What is the proper way of
>structuring this code.

The reactor doesn't care.  This is all pyAMF stuff.  pyAMF accepts
Deferreds (again, near as I can tell) and treats their eventual
result as the response to the request, sending it off in whatever
way is appropriate for AMF.

Hope this helps,

Jean-Paul




More information about the Twisted-Python mailing list