gen.Runner now communicates back to the decorator via a Future instead of a callback.

This allows for failures to be reported without relying on stack_context.
This commit is contained in:
Ben Darnell 2014-01-26 15:25:10 -05:00
parent b2ee332165
commit 0ea4de346d
1 changed files with 11 additions and 12 deletions

View File

@ -195,23 +195,19 @@ def _make_coroutine_wrapper(func, replace_callback):
future.set_exc_info((typ, value, tb)) future.set_exc_info((typ, value, tb))
return True return True
with ExceptionStackContext(handle_exception) as deactivate: with ExceptionStackContext(handle_exception) as deactivate:
future.add_done_callback(lambda f: deactivate())
try: try:
result = func(*args, **kwargs) result = func(*args, **kwargs)
except (Return, StopIteration) as e: except (Return, StopIteration) as e:
result = getattr(e, 'value', None) result = getattr(e, 'value', None)
except Exception: except Exception:
deactivate()
future.set_exc_info(sys.exc_info()) future.set_exc_info(sys.exc_info())
return future return future
else: else:
if isinstance(result, types.GeneratorType): if isinstance(result, types.GeneratorType):
def final_callback(value): runner = Runner(result, future)
deactivate()
future.set_result(value)
runner = Runner(result, final_callback)
runner.run() runner.run()
return future return future
deactivate()
future.set_result(result) future.set_result(result)
return future return future
return wrapper return wrapper
@ -444,11 +440,12 @@ class Runner(object):
Maintains information about pending callbacks and their results. Maintains information about pending callbacks and their results.
``final_callback`` is run after the generator exits. The results of the generator are stored in ``result_future`` (a
`.TracebackFuture`)
""" """
def __init__(self, gen, final_callback): def __init__(self, gen, result_future):
self.gen = gen self.gen = gen
self.final_callback = final_callback self.result_future = result_future
self.future = _null_future self.future = _null_future
self.yield_point = None self.yield_point = None
self.pending_callbacks = set() self.pending_callbacks = set()
@ -523,13 +520,15 @@ class Runner(object):
raise LeakedCallbackError( raise LeakedCallbackError(
"finished without waiting for callbacks %r" % "finished without waiting for callbacks %r" %
self.pending_callbacks) self.pending_callbacks)
self.final_callback(getattr(e, 'value', None)) self.result_future.set_result(getattr(e, 'value', None))
self.final_callback = None self.result_future = None
return return
except Exception: except Exception:
self.finished = True self.finished = True
self.future = _null_future self.future = _null_future
raise self.result_future.set_exc_info(sys.exc_info())
self.result_future = None
return
if isinstance(yielded, (list, dict)): if isinstance(yielded, (list, dict)):
yielded = Multi(yielded) yielded = Multi(yielded)
if isinstance(yielded, YieldPoint): if isinstance(yielded, YieldPoint):