[Twisted-Python] ldaptor's LDAPClient.send_multiResponse not dealing with chained deferreds, patch

Michael Torrie torriem at gmail.com
Sat May 3 20:22:25 MDT 2008

Jean-Paul Calderone wrote:
>> However, this doesn't work, because the send_multiResponse() method of
>> LDAPClient isn't expecting the handler to return a deferred, even though
>> if I do return a deferred the reactor does handle it properly, chaining
>> the deferreds and their callbacks.
> You don't need to return the Deferred in order for the code and event
> sources associated with it to cause it to eventually fire.  Returning
> it doesn't do anything more than make it available to the caller.  It
> seems this is what you actually want though, so this is just a change
> of perspective not a contradiction of your conclusion.

This stuff is getting kind of confusing for me, I must confess.
Especially because it's hard to explain exactly what I'm doing without
posting a very large code example (with lots of supporting modules).  I
may work on a minimal example, based on the proxy.py that ldaptor ships
with to demonstrate this.

So yes, the handler is just a callback attached to a deferred that has
already fired -- the deferred itself is irrelevant.  This deferred was
originally created by the LDAPClient.send_multiResponse() method, and it
fires when a response to the request comes in (there can be more than
one response, if the request was a search).  This function is a bit
confusing because it creates a deferred object that it returns to me,
but also takes a handler function as an argument.  I've tried to add my
additional processing routines to this particular deferred as a
callback, but that does not work.  I think if I could get this to work,
that might be the better way to go.

In the meantime, in the handler I pass to send_multiResponse(), I need
to generate a new deferred chain that has parts of it deferred to other
threads, etc.  Returning this new deferred from my handler seems ideal,
as the reactor just does the right thing.

> Or, written using the helper function twisted.internet.defer.maybeDeferred,
>     def cbHandler(result):
>         if result:
>             del self.onwire[msg.id]
>     result = maybeDeferred(handler, msg.value, *args, **kwargs)
>     result.addCallback(cbHandler)
> This correctly handles both Deferred and non-Deferred results.  I don't
> have any idea if this change to ldaptor is correct with respect to LDAP
> semantics/requirements or the particular implementation details of the
> code in question here, though.

Yes, this would seem the correct thing to do!  I'll have to work out a
patch that does this and see where we're at.

More information about the Twisted-Python mailing list