mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
bpo-31721: Allow Future._log_traceback to only be set to False (#5009)
This commit is contained in:
parent
3070b71e5e
commit
e0aef4f3cd
5 changed files with 37 additions and 6 deletions
|
@ -65,7 +65,7 @@ class Future:
|
||||||
# `yield Future()` (incorrect).
|
# `yield Future()` (incorrect).
|
||||||
_asyncio_future_blocking = False
|
_asyncio_future_blocking = False
|
||||||
|
|
||||||
_log_traceback = False
|
__log_traceback = False
|
||||||
|
|
||||||
def __init__(self, *, loop=None):
|
def __init__(self, *, loop=None):
|
||||||
"""Initialize the future.
|
"""Initialize the future.
|
||||||
|
@ -90,7 +90,7 @@ class Future:
|
||||||
' '.join(self._repr_info()))
|
' '.join(self._repr_info()))
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if not self._log_traceback:
|
if not self.__log_traceback:
|
||||||
# set_exception() was not called, or result() or exception()
|
# set_exception() was not called, or result() or exception()
|
||||||
# has consumed the exception
|
# has consumed the exception
|
||||||
return
|
return
|
||||||
|
@ -105,6 +105,16 @@ class Future:
|
||||||
context['source_traceback'] = self._source_traceback
|
context['source_traceback'] = self._source_traceback
|
||||||
self._loop.call_exception_handler(context)
|
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):
|
def get_loop(self):
|
||||||
"""Return the event loop the Future is bound to."""
|
"""Return the event loop the Future is bound to."""
|
||||||
return self._loop
|
return self._loop
|
||||||
|
@ -116,7 +126,7 @@ class Future:
|
||||||
change the future's state to cancelled, schedule the callbacks and
|
change the future's state to cancelled, schedule the callbacks and
|
||||||
return True.
|
return True.
|
||||||
"""
|
"""
|
||||||
self._log_traceback = False
|
self.__log_traceback = False
|
||||||
if self._state != _PENDING:
|
if self._state != _PENDING:
|
||||||
return False
|
return False
|
||||||
self._state = _CANCELLED
|
self._state = _CANCELLED
|
||||||
|
@ -162,7 +172,7 @@ class Future:
|
||||||
raise CancelledError
|
raise CancelledError
|
||||||
if self._state != _FINISHED:
|
if self._state != _FINISHED:
|
||||||
raise InvalidStateError('Result is not ready.')
|
raise InvalidStateError('Result is not ready.')
|
||||||
self._log_traceback = False
|
self.__log_traceback = False
|
||||||
if self._exception is not None:
|
if self._exception is not None:
|
||||||
raise self._exception
|
raise self._exception
|
||||||
return self._result
|
return self._result
|
||||||
|
@ -179,7 +189,7 @@ class Future:
|
||||||
raise CancelledError
|
raise CancelledError
|
||||||
if self._state != _FINISHED:
|
if self._state != _FINISHED:
|
||||||
raise InvalidStateError('Exception is not set.')
|
raise InvalidStateError('Exception is not set.')
|
||||||
self._log_traceback = False
|
self.__log_traceback = False
|
||||||
return self._exception
|
return self._exception
|
||||||
|
|
||||||
def add_done_callback(self, fn):
|
def add_done_callback(self, fn):
|
||||||
|
@ -237,7 +247,7 @@ class Future:
|
||||||
self._exception = exception
|
self._exception = exception
|
||||||
self._state = _FINISHED
|
self._state = _FINISHED
|
||||||
self._schedule_callbacks()
|
self._schedule_callbacks()
|
||||||
self._log_traceback = True
|
self.__log_traceback = True
|
||||||
|
|
||||||
def __await__(self):
|
def __await__(self):
|
||||||
if not self.done():
|
if not self.done():
|
||||||
|
|
|
@ -374,6 +374,11 @@ class BaseFutureTests:
|
||||||
test()
|
test()
|
||||||
fut.cancel()
|
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')
|
@mock.patch('asyncio.base_events.logger')
|
||||||
def test_tb_logger_abandoned(self, m_log):
|
def test_tb_logger_abandoned(self, m_log):
|
||||||
fut = self._new_future(loop=self.loop)
|
fut = self._new_future(loop=self.loop)
|
||||||
|
|
|
@ -623,6 +623,15 @@ class BaseTaskTests:
|
||||||
t.cancel()
|
t.cancel()
|
||||||
self.assertRaises(asyncio.CancelledError, loop.run_until_complete, t)
|
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 test_wait_for_timeout_less_then_0_or_0_future_done(self):
|
||||||
def gen():
|
def gen():
|
||||||
when = yield
|
when = yield
|
||||||
|
|
|
@ -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.
|
|
@ -1058,6 +1058,11 @@ FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
|
||||||
if (is_true < 0) {
|
if (is_true < 0) {
|
||||||
return -1;
|
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;
|
fut->fut_log_tb = is_true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue