[Twisted-Python] why can't a callback be called with a deferred?

Glyph glyph at twistedmatrix.com
Thu Feb 21 00:32:54 MST 2019



> On Feb 20, 2019, at 11:03 PM, Chris Withers <chris at withers.org> wrote:
> 
> On 21/02/2019 06:55, Glyph wrote:
>>> The methods being hooked don't necessarily return deferreds.
> 
> Glyph, this bit ^^^
> 
>>> I'd like it to be an explicit choice of the caller, ie:
>>> 
>>> result = yield SomeProtocol.onMessage.called()
>>> # okay, we got here, we know onMessage was called,
>>> # now we might want to tick a clock, or otherwise simulate
>>> # async state manipulation.
>>> # now I want to make sure the deferred chain on the onMessage result has been completed:
>>> yield result
>> I'm not sure I understand your example here. 
> 
> Yeah, this is part of carly, that I posted earlier. It stems from the need to get the results of method calls when you have no reference to the object being calls, or sometimes a result that's a deferred you need to wait on, particularly in a test, but have no way of doing so.

I just can't parse this sentence.

Breaking it down:

> you have no reference to the object being calls,

How do you have no reference to the object being called? Aren't you calling it?

> or sometimes a result that's a deferred you need to wait on, particularly in a test, but have no way of doing so

But... you do have a way of doing so.  You yield it from inlineCallbacks or you add a callback to it.

In any case you either have a Deferred or you don't; if you do, then it's clear you should wait on it, if you don't, then it's clear you should not wait on it.  If you want an API that allows some user code to do either, that's what 'maybeDeferred' is for.

> If you're feeling brave, have a read of:
> https://github.com/cjw296/carly/blob/master/carly/hook.py
> 
>> The assertion in question only happens if you call returnValue or do a return with a Deferred directly; this example doesn't do either of those things.
> 
> This is the test situation where I hit this issue:
> https://github.com/cjw296/carly/blob/master/tests/test_untracked_deferred.py#L28-L35
> 
> I'd originally wanted to have that read:
> 
>    @inlineCallbacks
>    def test1(self):
>        ...
>        result = yield pita.asyncMethod.called()
>        with ShouldRaise(Exception(1)):
>            yield result
> 
> Now, which I'm actually happier with the end result here, I think the above it legit, if unusual, and that assert trips it up.

Some type annotations might make it a bit clearer what the two states here are :).  As it is, it looks to me you want a Deferred to come *out* of a 'yield', which should definitely never happen.  If this assert were to be removed, it would be done in such a way that would implicitly wait for the Deferred in question to fire: you should never receive a Deferred as an argument to a function, or as the result of an (inlineCallbacks) 'yield' or (async def) 'await'.  It breaks the whole model of what 'awaiting' means.

-g
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20190220/56ad0744/attachment-0002.html>


More information about the Twisted-Python mailing list