[Twisted-Python] how to get the result of a callLater-scheduled func?

Hi, I am scheduling a function with `callLater`. The function happens to return a Deferred (but it might return anything), and I was searching for an easy way to add a callback in order to get the result. I know a workaround by creating a Deferred first, adding the call as callback and another callback to get the result, but this seems overly complicated (see below). Am I missing something? So I set up some function to be scheduled (happens to be an inlineCallbacks-generator for testing, but I think this should not be relevant here):: >>> from twisted.internet import defer, reactor >>> @defer.inlineCallbacks ... def test(name): ... print name, 'start' ... yield # yielding a non-Deferred does nothing ... print name, 'end' ... yield defer.returnValue('uiuiui') I know this works:: >>> deftest = defer.Deferred().addCallback(test) >>> jamesdelcall = reactor.callLater(0, deftest.callback, 'James') >>> def stopverbose(whatever): ... print 'stopping, result:', whatever ... reactor.stop() >>> deftest.addCallback(stopverbose) >>> reactor.run() James start James end stopping, result: uiuiui What I expected to be able to do:: >>> jamesdelcall = reactor.callLater(0, test, 'James') >>> def stopverbose(whatever): ... print 'stopping, result:', whatever ... reactor.stop() >>> jamesdelcal.gethisdeferred.addCallback(stopverbose) # <- MAGIC >>> reactor.run() James start James end stopping, result: uiuiui I looked at the code of `ReactorBase.callLater` and `ReactorBase.runUntilCurrent`: Would it be possible to add a `Deferred` to `DelayedCall` (possibly created lazily, or maybe even make DelayedCall a subclass of Deferred), so that such code is possible, or would this somehow destroy the mainloop logic? cheers, stefan

On Thu, 08 Mar 2007 19:39:21 +0100, Stefan Rank <list-ener@strank.info> wrote:
Hi,
I am scheduling a function with `callLater`. The function happens to return a Deferred (but it might return anything), and I was searching for an easy way to add a callback in order to get the result. I know a workaround by creating a Deferred first, adding the call as callback and another callback to get the result, but this seems overly complicated (see below). Am I missing something?
So I set up some function to be scheduled (happens to be an inlineCallbacks- generator for testing, but I think this should not be relevant here)::
>>> from twisted.internet import defer, reactor >>> @defer.inlineCallbacks ... def test(name): ... print name, 'start' ... yield # yielding a non-Deferred does nothing ... print name, 'end' ... yield defer.returnValue('uiuiui')
I know this works::
>>> deftest = defer.Deferred().addCallback(test) >>> jamesdelcall = reactor.callLater(0, deftest.callback, 'James') >>> def stopverbose(whatever): ... print 'stopping, result:', whatever ... reactor.stop() >>> deftest.addCallback(stopverbose) >>> reactor.run() James start James end stopping, result: uiuiui
What I expected to be able to do::
>>> jamesdelcall = reactor.callLater(0, test, 'James') >>> def stopverbose(whatever): ... print 'stopping, result:', whatever ... reactor.stop() >>> jamesdelcal.gethisdeferred.addCallback(stopverbose) # <- MAGIC >>> reactor.run() James start James end stopping, result: uiuiui
I looked at the code of `ReactorBase.callLater` and `ReactorBase.runUntilCurrent`: Would it be possible to add a `Deferred` to `DelayedCall` (possibly created lazily, or maybe even make DelayedCall a subclass of Deferred), so that such code is possible, or would this somehow destroy the mainloop logic?
It's probably possible, but I'm not sure it's ideal. It sounds like you have a use-case for the `deferLater' function which has been proposed for inclusion: http://twistedmatrix.com/trac/ticket/1875 With it, your example would look like either: d = deferLater(0) d.addCallback(lambda ignored: test('James')) d.addCallback(stopVerbose) Or: d = deferLater(0, test, 'James') d.addCallback(stopVerbose) Would that save enough typing to satisfy your use case? Jean-Paul

on 08.03.2007 20:37 Jean-Paul Calderone said the following:
On Thu, 08 Mar 2007 19:39:21 +0100, Stefan Rank <list-ener@strank.info> wrote:
Hi,
I am scheduling a function with `callLater`. The function happens to return a Deferred (but it might return anything), and I was searching for an easy way to add a callback in order to get the result. <snip>
It's probably possible, but I'm not sure it's ideal. It sounds like you have a use-case for the `deferLater' function which has been proposed for inclusion:
http://twistedmatrix.com/trac/ticket/1875
With it, your example would look like either:
d = deferLater(0) d.addCallback(lambda ignored: test('James')) d.addCallback(stopVerbose)
Or:
d = deferLater(0, test, 'James') d.addCallback(stopVerbose)
Would that save enough typing to satisfy your use case?
Jean-Paul
Thanks, that's almost what I was looking for. :) What is lost is the access to the DelayedCall, i.e. you cannot cancel or reschedule anymore. The discussion at the ticket page revolves around which of the two variants above is preferable. I very much prefer the second one, but if the callable argument would default to None, then a simple:: if callable_ is not None: ... # only now use addCallback inside deferLater would allow both versions without any overhead. If the DelayedCall functionality could be integrated somehow than I think this could simply replace reactor.callLater. I'll post at the ticket page. thanks again, stefan
participants (2)
-
Jean-Paul Calderone
-
Stefan Rank