mirror of
https://github.com/python/cpython.git
synced 2025-08-28 04:35:02 +00:00
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.
This commit is contained in:
parent
bbd96c6f47
commit
80f53aa9a0
8 changed files with 180 additions and 26 deletions
|
@ -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):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue