Ticket #4157 enhancement closed fixed
non-local inlineCallbacks exit from returnValue being called in the wrong function is very confusing
| Reported by: | glyph | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | |
| Component: | core | Keywords: | |
| Cc: | radix, jesstess | Branch: |
branches/nonlocal-4157
(diff, github, buildbot, log) |
| Author: | glyph | Launchpad Bug: |
Description
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!
