[Python-checkins] cpython: Close #19967: Thanks to the PEP 442, asyncio.Future can use a destructor in

victor.stinner python-checkins at python.org
Thu Dec 19 22:43:22 CET 2013


http://hg.python.org/cpython/rev/5e9728ebb1d3
changeset: 88081:5e9728ebb1d3
user: Victor Stinner <victor.stinner at gmail.com>
date: Thu Dec 19 22:42:40 2013 +0100
summary:
 Close #19967: Thanks to the PEP 442, asyncio.Future can use a destructor in
Python 3.4 to log "uncatched" exceptions, instead of the dedicated
_TracebackLogger class.
files:
 Lib/asyncio/futures.py | 32 +++++++++++++---
 Lib/test/test_asyncio/test_tasks.py | 2 +
 2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -7,6 +7,7 @@
 
 import concurrent.futures._base
 import logging
+import sys
 import traceback
 
 from . import events
@@ -17,6 +18,8 @@
 _CANCELLED = 'CANCELLED'
 _FINISHED = 'FINISHED'
 
+_PY34 = sys.version_info >= (3, 4)
+
 # TODO: Do we really want to depend on concurrent.futures internals?
 Error = concurrent.futures._base.Error
 CancelledError = concurrent.futures.CancelledError
@@ -128,7 +131,8 @@
 
 _blocking = False # proper use of future (yield vs yield from)
 
- _tb_logger = None
+ _traceback = None # Used for Python 3.4 and later
+ _tb_logger = None # Used for Python 3.3 only
 
 def __init__(self, *, loop=None):
 """Initialize the future.
@@ -162,6 +166,12 @@
 res += '<{}>'.format(self._state)
 return res
 
+ if _PY34:
+ def __del__(self):
+ if self._traceback is not None:
+ logger.error('Future/Task exception was never retrieved:\n%s',
+ ''.join(self._traceback))
+
 def cancel(self):
 """Cancel the future and schedule callbacks.
 
@@ -214,9 +224,10 @@
 raise CancelledError
 if self._state != _FINISHED:
 raise InvalidStateError('Result is not ready.')
+ self._traceback = None
 if self._tb_logger is not None:
 self._tb_logger.clear()
- self._tb_logger = None
+ self._tb_logger = None
 if self._exception is not None:
 raise self._exception
 return self._result
@@ -233,9 +244,10 @@
 raise CancelledError
 if self._state != _FINISHED:
 raise InvalidStateError('Exception is not set.')
+ self._traceback = None
 if self._tb_logger is not None:
 self._tb_logger.clear()
- self._tb_logger = None
+ self._tb_logger = None
 return self._exception
 
 def add_done_callback(self, fn):
@@ -286,12 +298,18 @@
 if self._state != _PENDING:
 raise InvalidStateError('{}: {!r}'.format(self._state, self))
 self._exception = exception
- self._tb_logger = _TracebackLogger(exception)
 self._state = _FINISHED
 self._schedule_callbacks()
- # 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)
+ if _PY34:
+ self._traceback = traceback.format_exception(
+ exception.__class__,
+ exception,
+ exception.__traceback__)
+ else:
+ self._tb_logger = _TracebackLogger(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)
 
 # Truly internal methods.
 
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -1352,6 +1352,7 @@
 c.set_result(3)
 d.cancel()
 e.set_exception(RuntimeError())
+ e.exception()
 
 def test_return_exceptions(self):
 a, b, c, d = [futures.Future(loop=self.one_loop) for i in range(4)]
@@ -1431,6 +1432,7 @@
 c.set_result(3)
 d.cancel()
 e.set_exception(RuntimeError())
+ e.exception()
 
 def test_result_exception_one_cancellation(self):
 a, b, c, d, e, f = [futures.Future(loop=self.one_loop)
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /