Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions Lib/asyncio/futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class Future:
# `yield Future()` (incorrect).
_asyncio_future_blocking = False

_log_traceback = False
__log_traceback = False

def __init__(self, *, loop=None):
"""Initialize the future.
Expand All @@ -90,7 +90,7 @@ def __repr__(self):
' '.join(self._repr_info()))

def __del__(self):
if not self._log_traceback:
if not self.__log_traceback:
# set_exception() was not called, or result() or exception()
# has consumed the exception
return
Expand All @@ -105,6 +105,16 @@ def __del__(self):
context['source_traceback'] = self._source_traceback
self._loop.call_exception_handler(context)

@property
def _log_traceback(self):
return self.__log_traceback

@_log_traceback.setter
def _log_traceback(self, val):
if bool(val):
raise ValueError('_log_traceback can only be set to False')
self.__log_traceback = False

def get_loop(self):
"""Return the event loop the Future is bound to."""
return self._loop
Expand All @@ -116,7 +126,7 @@ def cancel(self):
change the future's state to cancelled, schedule the callbacks and
return True.
"""
self._log_traceback = False
self.__log_traceback = False
if self._state != _PENDING:
return False
self._state = _CANCELLED
Expand Down Expand Up @@ -162,7 +172,7 @@ def result(self):
raise CancelledError
if self._state != _FINISHED:
raise InvalidStateError('Result is not ready.')
self._log_traceback = False
self.__log_traceback = False
if self._exception is not None:
raise self._exception
return self._result
Expand All @@ -179,7 +189,7 @@ def exception(self):
raise CancelledError
if self._state != _FINISHED:
raise InvalidStateError('Exception is not set.')
self._log_traceback = False
self.__log_traceback = False
return self._exception

def add_done_callback(self, fn):
Expand Down Expand Up @@ -237,7 +247,7 @@ def set_exception(self, exception):
self._exception = exception
self._state = _FINISHED
self._schedule_callbacks()
self._log_traceback = True
self.__log_traceback = True

def __iter__(self):
if not self.done():
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_asyncio/test_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@ def test():
self.assertRaises(AssertionError, test)
fut.cancel()

def test_log_traceback(self):
fut = self._new_future(loop=self.loop)
with self.assertRaisesRegex(ValueError, 'can only be set to False'):
fut._log_traceback = True

@mock.patch('asyncio.base_events.logger')
def test_tb_logger_abandoned(self, m_log):
fut = self._new_future(loop=self.loop)
Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_asyncio/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,15 @@ async def task():
t.cancel()
self.assertRaises(asyncio.CancelledError, loop.run_until_complete, t)

def test_log_traceback(self):
async def coro():
pass

task = self.new_task(self.loop, coro())
with self.assertRaisesRegex(ValueError, 'can only be set to False'):
task._log_traceback = True
self.loop.run_until_complete(task)

def test_wait_for_timeout_less_then_0_or_0_future_done(self):
def gen():
when = yield
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Prevent Python crash from happening when Future._log_traceback is set to
True manually. Now it can only be set to False, or a ValueError is raised.
5 changes: 5 additions & 0 deletions Modules/_asynciomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,11 @@ FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
if (is_true < 0) {
return -1;
}
if (is_true) {
PyErr_SetString(PyExc_ValueError,
"_log_traceback can only be set to False");
return -1;
}
fut->fut_log_tb = is_true;
return 0;
}
Expand Down