summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio/futures.py
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2014-06-27 11:52:20 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2014-06-27 11:52:20 (GMT)
commit80f53aa9a0b2af28c9d8052c46b452cccb8e0b41 (patch)
tree2f1714ab75a7d22f9c719a5890459278d4d581fa /Lib/asyncio/futures.py
parentbbd96c6f47046e11f47de06550dcd1c816aad71c (diff)
downloadcpython-80f53aa9a0b2af28c9d8052c46b452cccb8e0b41.zip
cpython-80f53aa9a0b2af28c9d8052c46b452cccb8e0b41.tar.gz
cpython-80f53aa9a0b2af28c9d8052c46b452cccb8e0b41.tar.bz2
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/futures.py')
-rw-r--r--Lib/asyncio/futures.py29
1 files changed, 19 insertions, 10 deletions
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 3103fe1..fcc90d1 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -82,10 +82,11 @@ class _TracebackLogger:
in a discussion about closing files when they are collected.
"""
- __slots__ = ['exc', 'tb', 'loop']
+ __slots__ = ('loop', 'source_traceback', 'exc', 'tb')
- def __init__(self, exc, loop):
- self.loop = loop
+ def __init__(self, future, exc):
+ self.loop = future._loop
+ self.source_traceback = future._source_traceback
self.exc = exc
self.tb = None
@@ -102,11 +103,12 @@ class _TracebackLogger:
def __del__(self):
if self.tb:
- msg = 'Future/Task exception was never retrieved:\n{tb}'
- context = {
- 'message': msg.format(tb=''.join(self.tb)),
- }
- self.loop.call_exception_handler(context)
+ msg = 'Future/Task exception was never retrieved'
+ if self.source_traceback:
+ msg += '\nFuture/Task created at (most recent call last):\n'
+ msg += ''.join(traceback.format_list(self.source_traceback))
+ msg += ''.join(self.tb).rstrip()
+ self.loop.call_exception_handler({'message': msg})
class Future:
@@ -149,6 +151,10 @@ class Future:
else:
self._loop = loop
self._callbacks = []
+ if self._loop.get_debug():
+ self._source_traceback = traceback.extract_stack(sys._getframe(1))
+ else:
+ self._source_traceback = None
def _format_callbacks(self):
cb = self._callbacks
@@ -196,10 +202,13 @@ class Future:
return
exc = self._exception
context = {
- 'message': 'Future/Task exception was never retrieved',
+ 'message': ('%s exception was never retrieved'
+ % self.__class__.__name__),
'exception': exc,
'future': self,
}
+ if self._source_traceback:
+ context['source_traceback'] = self._source_traceback
self._loop.call_exception_handler(context)
def cancel(self):
@@ -335,7 +344,7 @@ class Future:
if _PY34:
self._log_traceback = True
else:
- self._tb_logger = _TracebackLogger(exception, self._loop)
+ self._tb_logger = _TracebackLogger(self, exception)
# Arrange for the logger to be activated after all callbacks
# have had a chance to call result() or exception().
self._loop.call_soon(self._tb_logger.activate)