[Twisted-Python] DeferredList.addDeferred behaviour
I have been playing with DeferredList if found that his behaviour was not what I expected,
dfl = DeferredList([]) print dfl.called True dfl.addDeferred(d) d.called 0 print dfl.called True
The workaround it to first create the list of deferred instance and then instanciate with it the DeferredList. But what sense does have the addDeferred method then ? I this behaviour what is supposed to be ? rodrigob.
On Wed, Feb 18, 2004 at 09:37:53PM -0300, RITA Y/O RODRIGO DIAZ Y/O BENENSON wrote:
I have been playing with DeferredList if found that his behaviour was not what I expected,
dfl = DeferredList([]) print dfl.called True dfl.addDeferred(d) d.called 0 print dfl.called True
The workaround it to first create the list of deferred instance and then instanciate with it the DeferredList. But what sense does have the addDeferred method then ? I this behaviour what is supposed to be ?
It's not clear to me what the right behaviour here is -- if a DeferredList has some number of Deferreds that have all been called, then of course the DeferredList should be marked as called, too. But if you then add an uncalled Deferred to it, that sounds like a bug. I'd be inclined to make DeferredList.addDeferred raise an exception in this case -- "In the face of ambiguity, refuse the temptation to guess." (although perhaps a warning would be better for a release or two, for backwards compatibility) I'm tempted to go even further and just deprecate addDeferred. I can't see a good use-case for it, and grep of the entire Twisted code base finds no uses outside of the test suite. It's not obvious or intuitive exactly what addDeferred should do in at least this situation, and probably others. I can't think of any situation where addDeferred is required, and I think calling it with the final list upfront is more readable, anyway. Can anyone offer reasons why addDeferred should stay? Donovan -- CVS says you added it, can you remember why? Is anyone using it? -Andrew.
Andrew Bennetts wrote:
On Wed, Feb 18, 2004 at 09:37:53PM -0300, RITA Y/O RODRIGO DIAZ Y/O BENENSON wrote:
The workaround it to first create the list of deferred instance and then instanciate with it the DeferredList. But what sense does have the addDeferred method then ? I this behaviour what is supposed to be ?
It's not clear to me what the right behaviour here is -- if a DeferredList has some number of Deferreds that have all been called, then of course the DeferredList should be marked as called, too. But if you then add an uncalled Deferred to it, that sounds like a bug.
Similar to d.result, IMO, d.called is an "invite-only attribute", in the words of Glyph. If you want to touch it, don't whine about its semantics. :-)
Can anyone offer reasons why addDeferred should stay? Donovan -- CVS says you added it, can you remember why? Is anyone using it?
And addDeferred looks like it should really be _addDeferred. -- Twisted | Christopher Armstrong: International Man of Twistery Radix | Release Manager, Twisted Project ---------+ http://radix.twistedmatrix.com/
On Wed, Feb 18, 2004 at 10:19:43PM -0500, Christopher Armstrong wrote:
Andrew Bennetts wrote:
It's not clear to me what the right behaviour here is -- if a DeferredList has some number of Deferreds that have all been called, then of course the DeferredList should be marked as called, too. But if you then add an uncalled Deferred to it, that sounds like a bug.
Similar to d.result, IMO, d.called is an "invite-only attribute", in the words of Glyph. If you want to touch it, don't whine about its semantics. :-)
It probably should be _called, then... if nothing else, the API docs should point this out. I might fix that when I update the code to deprecate addDeferred.
Can anyone offer reasons why addDeferred should stay? Donovan -- CVS says you added it, can you remember why? Is anyone using it?
And addDeferred looks like it should really be _addDeferred.
Why not just remove it entirely? I found Donovan on IRC, his opinion was "remove it" :) -Andrew.
Andrew Bennetts <andrew-twisted@puzzling.org> writes:
It's not clear to me what the right behaviour here is -- if a DeferredList has some number of Deferreds that have all been called, then of course the DeferredList should be marked as called, too. But if you then add an uncalled Deferred to it, that sounds like a bug. I'd be inclined to make DeferredList.addDeferred raise an exception in this case -- "In the face of ambiguity, refuse the temptation to guess." (although perhaps a warning would be better for a release or two, for backwards compatibility)
Well, it's not clear to me that having a mixture of called and uncalled in a DeferredList is necessarily inconsistent - at least not until after the DeferredList has actually has had its first callback assigned. After all, even if you insert just uncalled Deferreds initially, during the course of normal events you'll end up with a mixture as some of the Deferreds fire and others haven't yet. I do agree that adding an uncalled Deferred to a DeferredList after that DeferredList has really fired (called actual callbacks) is a problem. I think the HowTo warns against this case though, but it says to check via the called attribute, which of course this thread seems to point out as potentially a problem.
Can anyone offer reasons why addDeferred should stay? Donovan -- CVS says you added it, can you remember why? Is anyone using it?
I was until I saw this thread and figured out it probably wasn't going to hold up the way I expected. It was working for me now but that's because the existing deferrable objects were returning Deferreds already called (mostly through defer.succeed and defer.fail) as placeholders for eventual remote versions, and thus when I was finally adding the callbacks/errbacks to the DeferredList they were running synchronously just fine. But it looks like the problem that started this thread would break that code when I started having uncalled results as part of the DeferredList since the callbacks would still get called as soon as they were added. As a use case, my scenario is an upper level package function (that itself returns a deferrable interface) that performs a function across several target objects as part of its operation - sort of a deferrable version of map. I want to use the DeferredList to aggregate/process the results into a single result, so I want to completely absorb the individual deferreds. It seemed to me that this should have been a good fit for DeferredList. Because DeferredList itself is just a callback and won't terminate the original deferred chain (in particular, it doesn't stop the errback), I also need to add a specific errback to each individual Deferred to absorb any errors. Without addDeferred I can't do this in a single loop. For example, assuming that "func" is a deferrable method on a number of objects held in an iterable "objs": With addDeferred (the code I used to have): dl = defer.DeferredList([]) for obj in objs: d = obj.func() dl.addDeferred(d) d.addErrback(lambda _:None) dl.addCallback(processResults) return dl without addDeferred (the code I have now): deferreds = [] for obj in objs: d = obj.func() deferreds.append(d) dl = defer.DeferredList([]) for d in deferreds: d.addErrback(lambda _:None) dl.addCallback(processResults) return dl Without addDeferred I need to aggregate the underlying deferreds separately, but more importantly, I need a completely separate loop to install the suppression errbacks, because that has to be done _after_ the Deferreds are stuck into the DeferredList or else that suppression will stop the DeferredList from seeing the error. Maybe not an extreme case, but at the time of writing it I thought that this was specifically the sort of case that addDeferred was perfect for. Although if DeferredList were to grow a way to specify that it should suppress errors once it has gathered them, I'd probably be just as happy as having addDeferred fixed, since the separate loop for error suppression bugs me more than the need to separately aggregate the Deferreds together before creating the DeferredList. Actually suppressing errors might make me even happier, since needing to suppress the errors separately (noted in the API documentation, but not the HowTo), while making perfect sense to me now, took a while to catch on to initially. -- David
On Thu, Feb 26, 2004 at 10:48:12AM -0500, David Bolen wrote: [...]
Without addDeferred I need to aggregate the underlying deferreds separately, but more importantly, I need a completely separate loop to install the suppression errbacks, because that has to be done _after_ the Deferreds are stuck into the DeferredList or else that suppression will stop the DeferredList from seeing the error.
Interesting. I think I'd still rather the two loops than the confusing semantics of addDeferred. [...]
Although if DeferredList were to grow a way to specify that it should suppress errors once it has gathered them, I'd probably be just as happy as having addDeferred fixed, since the separate loop for error suppression bugs me more than the need to separately aggregate the Deferreds together before creating the DeferredList. Actually suppressing errors might make me even happier, since needing to suppress the errors separately (noted in the API documentation, but not the HowTo), while making perfect sense to me now, took a while to catch on to initially.
I think adding a 'consumeErrors' or 'suppressErrors' flag might be a good idea... I've put a patch up at http://twistedmatrix.com/bugs/issue528 -- let's continue discussion there. In the meantime, I've checked in the change to deprecate addDeferred, and removed it from the howto. -Andrew.
participants (4)
-
Andrew Bennetts
-
Christopher Armstrong
-
David Bolen
-
RITA Y/O RODRIGO DIAZ Y/O BENENSON