From 694a5a9c4c1b77b01b904608f45d69f70265f6d3 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 4 Jun 2017 20:27:30 -0400 Subject: [PATCH] concurrent: Introduce future_set_exc_info function This function is equivalent to future.set_exc_info for TracebackFuture but also falls back to set_exception for other Futures. --- tornado/auth.py | 4 ++-- tornado/concurrent.py | 25 ++++++++++++++++++++----- tornado/gen.py | 26 +++++++++++++------------- tornado/ioloop.py | 4 ++-- tornado/platform/twisted.py | 4 ++-- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/tornado/auth.py b/tornado/auth.py index f02d28980..93f771bc4 100644 --- a/tornado/auth.py +++ b/tornado/auth.py @@ -75,7 +75,7 @@ import hmac import time import uuid -from tornado.concurrent import TracebackFuture, return_future, chain_future +from tornado.concurrent import TracebackFuture, return_future, chain_future, future_set_exc_info from tornado import gen from tornado import httpclient from tornado import escape @@ -127,7 +127,7 @@ def _auth_return_future(f): if future.done(): return False else: - future.set_exc_info((typ, value, tb)) + future_set_exc_info(future, (typ, value, tb)) return True with ExceptionStackContext(handle_exception): f(*args, **kwargs) diff --git a/tornado/concurrent.py b/tornado/concurrent.py index b1bcc56e2..08c0e0b75 100644 --- a/tornado/concurrent.py +++ b/tornado/concurrent.py @@ -362,7 +362,7 @@ class DummyExecutor(object): try: future.set_result(fn(*args, **kwargs)) except Exception: - future.set_exc_info(sys.exc_info()) + future_set_exc_info(future, sys.exc_info()) return future def shutdown(self, wait=True): @@ -466,7 +466,7 @@ def return_future(f): args, kwargs) def handle_error(typ, value, tb): - future.set_exc_info((typ, value, tb)) + future_set_exc_info(future, (typ, value, tb)) return True exc_info = None with ExceptionStackContext(handle_error): @@ -513,12 +513,27 @@ def chain_future(a, b): assert future is a if b.done(): return - if (isinstance(a, TracebackFuture) and - isinstance(b, TracebackFuture) and + if (hasattr(a, 'exc_info') and a.exc_info() is not None): - b.set_exc_info(a.exc_info()) + future_set_exc_info(b, a.exc_info()) elif a.exception() is not None: b.set_exception(a.exception()) else: b.set_result(a.result()) a.add_done_callback(copy) + + +def future_set_exc_info(future, exc_info): + """Set the given ``exc_info`` as the `Future`'s exception. + + Understands both `asyncio.Future` and Tornado's extensions to + enable better tracebacks on Python 2. + + .. versionadded:: 5.0 + """ + if hasattr(future, 'set_exc_info'): + # Tornado's Future + future.set_exc_info(exc_info) + else: + # asyncio.Future + future.set_exception(exc_info[1]) diff --git a/tornado/gen.py b/tornado/gen.py index 62fea303b..7368cb67c 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -85,7 +85,7 @@ import textwrap import types import weakref -from tornado.concurrent import Future, TracebackFuture, is_future, chain_future +from tornado.concurrent import Future, TracebackFuture, is_future, chain_future, future_set_exc_info from tornado.ioloop import IOLoop from tornado.log import app_log from tornado import stack_context @@ -289,7 +289,7 @@ def _make_coroutine_wrapper(func, replace_callback): except (Return, StopIteration) as e: result = _value_from_stopiteration(e) except Exception: - future.set_exc_info(sys.exc_info()) + future_set_exc_info(future, sys.exc_info()) return future else: if isinstance(result, GeneratorType): @@ -310,7 +310,7 @@ def _make_coroutine_wrapper(func, replace_callback): except (StopIteration, Return) as e: future.set_result(_value_from_stopiteration(e)) except Exception: - future.set_exc_info(sys.exc_info()) + future_set_exc_info(future, sys.exc_info()) else: _futures_to_runners[future] = Runner(result, future, yielded) yielded = None @@ -606,7 +606,7 @@ def Task(func, *args, **kwargs): def handle_exception(typ, value, tb): if future.done(): return False - future.set_exc_info((typ, value, tb)) + future_set_exc_info(future, (typ, value, tb)) return True def set_result(result): @@ -827,7 +827,7 @@ def multi_future(children, quiet_exceptions=()): app_log.error("Multiple exceptions in yield list", exc_info=True) else: - future.set_exc_info(sys.exc_info()) + future_set_exc_info(future, sys.exc_info()) if not future.done(): if keys is not None: future.set_result(dict(zip(keys, result_list))) @@ -1019,7 +1019,7 @@ class Runner(object): try: self.future.set_result(self.yield_point.get_result()) except: - self.future.set_exc_info(sys.exc_info()) + future_set_exc_info(self.future, sys.exc_info()) self.yield_point = None self.run() @@ -1085,7 +1085,7 @@ class Runner(object): except Exception: self.finished = True self.future = _null_future - self.result_future.set_exc_info(sys.exc_info()) + future_set_exc_info(self.result_future, sys.exc_info()) self.result_future = None self._deactivate_stack_context() return @@ -1115,8 +1115,8 @@ class Runner(object): else: self.yield_point = yielded except Exception: - self.future = TracebackFuture() - self.future.set_exc_info(sys.exc_info()) + self.future = Future() + future_set_exc_info(self.future, sys.exc_info()) if self.stack_context_deactivate is None: # Start a stack context if this is the first @@ -1136,8 +1136,8 @@ class Runner(object): try: self.future = convert_yielded(yielded) except BadYieldError: - self.future = TracebackFuture() - self.future.set_exc_info(sys.exc_info()) + self.future = Future() + future_set_exc_info(self.future, sys.exc_info()) if not self.future.done() or self.future is moment: def inner(f): @@ -1155,8 +1155,8 @@ class Runner(object): def handle_exception(self, typ, value, tb): if not self.running and not self.finished: - self.future = TracebackFuture() - self.future.set_exc_info((typ, value, tb)) + self.future = Future() + future_set_exc_info(self.future, (typ, value, tb)) self.run() return True else: diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 481daeeb3..e64009df6 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -44,7 +44,7 @@ import time import traceback import math -from tornado.concurrent import TracebackFuture, is_future, chain_future +from tornado.concurrent import TracebackFuture, is_future, chain_future, future_set_exc_info from tornado.log import app_log, gen_log from tornado.platform.auto import set_close_exec, Waker from tornado import stack_context @@ -482,7 +482,7 @@ class IOLoop(Configurable): result = convert_yielded(result) except Exception: future_cell[0] = TracebackFuture() - future_cell[0].set_exc_info(sys.exc_info()) + future_set_exc_info(future_cell[0], sys.exc_info()) else: if is_future(result): future_cell[0] = result diff --git a/tornado/platform/twisted.py b/tornado/platform/twisted.py index 7c337e8a5..613e7b6dc 100644 --- a/tornado/platform/twisted.py +++ b/tornado/platform/twisted.py @@ -42,7 +42,7 @@ import twisted.names.resolve # type: ignore from zope.interface import implementer # type: ignore -from tornado.concurrent import Future +from tornado.concurrent import Future, future_set_exc_info from tornado.escape import utf8 from tornado import gen import tornado.ioloop @@ -585,6 +585,6 @@ if hasattr(gen.convert_yielded, 'register'): # Should never happen, but just in case raise Exception("errback called without error") except: - f.set_exc_info(sys.exc_info()) + future_set_exc_info(f, sys.exc_info()) d.addCallbacks(f.set_result, errback) return f -- 2.47.2