diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2014-06-27 13:55:28 +0200 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2014-06-27 13:55:28 +0200 |
commit | eb39199f3def654b502bc8362d241bcbcc2891c7 (patch) | |
tree | a6a8f6a1645b130c8d725ed8e804d4e3640e9b44 /Lib/asyncio/events.py | |
parent | fe4a979099300e502eff8a1fd6f6d6a596771dda (diff) | |
parent | 80f53aa9a0b2af28c9d8052c46b452cccb8e0b41 (diff) | |
download | cpython-git-eb39199f3def654b502bc8362d241bcbcc2891c7.tar.gz |
(Merge 3.4) asyncio, Tulip issue 137: In debug mode, save traceback where
Future, Task and Handle objects are created. Pass the traceback to
call_exception_handler() in the 'source_traceback' key.
The traceback is truncated to hide internal calls in asyncio, show only the
traceback from user code.
Add tests for the new source_traceback, and a test for the 'Future/Task
exception was never retrieved' log.
Diffstat (limited to 'Lib/asyncio/events.py')
-rw-r--r-- | Lib/asyncio/events.py | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 58c6bd5320..b389cfb088 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -11,6 +11,7 @@ __all__ = ['AbstractEventLoopPolicy', import functools import inspect import subprocess +import traceback import threading import socket import sys @@ -66,7 +67,8 @@ def _format_callback(func, args, suffix=''): class Handle: """Object returned by callback registration methods.""" - __slots__ = ['_callback', '_args', '_cancelled', '_loop', '__weakref__'] + __slots__ = ('_callback', '_args', '_cancelled', '_loop', + '_source_traceback', '__weakref__') def __init__(self, callback, args, loop): assert not isinstance(callback, Handle), 'A Handle is not a callback' @@ -74,6 +76,10 @@ class Handle: self._callback = callback self._args = args self._cancelled = False + if self._loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + else: + self._source_traceback = None def __repr__(self): info = [] @@ -91,11 +97,14 @@ class Handle: except Exception as exc: cb = _format_callback(self._callback, self._args) msg = 'Exception in callback {}'.format(cb) - self._loop.call_exception_handler({ + context = { 'message': msg, 'exception': exc, 'handle': self, - }) + } + if self._source_traceback: + context['source_traceback'] = self._source_traceback + self._loop.call_exception_handler(context) self = None # Needed to break cycles when an exception occurs. @@ -107,7 +116,8 @@ class TimerHandle(Handle): def __init__(self, when, callback, args, loop): assert when is not None super().__init__(callback, args, loop) - + if self._source_traceback: + del self._source_traceback[-1] self._when = when def __repr__(self): |