non-local inlineCallbacks exit from returnValue being called in the wrong function is very confusing

[email protected] Mon, 07 Dec 2009 18:09:24 -0000
Newsgroups gmane.comp.python.twisted.bugs
Message-ID <[email protected]>
New submission from glyph <[email protected]>:

Let's say we have a chunk of code like this:
{{{
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
def asyncOperation():
    return succeed(1)
@inlineCallbacks
def thunk():
    value = yield asyncOperation()
    if value:
        returnValue(value)
@inlineCallbacks
def main():
    print "Result:", (yield thunk())
main()
}}}
This is reasonably straightforward.  However, let's say we wanted to refactor it, and we end up with this definition of 'thunk':
{{{
def thunk2(value):
    if value:
        returnValue(value)
@inlineCallbacks
def thunk():
    value = yield asyncOperation()
    returnValue((yield thunk2(value)) + 1)
}}}
(I realize that at such a small scale, a copy/paste error of this type seems ludicrous, but in a larger function, especially if it's spread across many functions and methods decorated with @inlineCallbacks, it's quite feasible.)

The second version exits immediately with the "wrong" value, and it's very difficult to tell why.  Worse yet, it fails even if remember to decorate `thunk2` with `inlineCallbacks`; it only starts to give us the "right" value when `thunk2` is properly a generator ''and'' decorated.  Debugging this is tricky, because it looks like returnValue is causing `thunk` to exist, just with the wrong value!

----------
Type     : enhancement
Component: core
Keywords : 
Priority : normal
Nosy     : 
----------
http://twistedmatrix.com/trac/ticket/4157