Skip to content

Commit 176f2eb

Browse files
authored
bpo-30508: Don't log exceptions if Task/Future "cancel()" method was called. (#2109)
1 parent 59422a2 commit 176f2eb

File tree

6 files changed

+49
-1
lines changed

6 files changed

+49
-1
lines changed

Lib/asyncio/futures.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ def cancel(self):
191191
change the future's state to cancelled, schedule the callbacks and
192192
return True.
193193
"""
194+
self._log_traceback = False
194195
if self._state != _PENDING:
195196
return False
196197
self._state = _CANCELLED

Lib/asyncio/tasks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ def cancel(self):
148148
terminates with a CancelledError exception (even if cancel()
149149
was not called).
150150
"""
151+
self._log_traceback = False
151152
if self.done():
152153
return False
153154
if self._fut_waiter is not None:

Lib/test/test_asyncio/test_futures.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,14 @@ def test_tb_logger_abandoned(self, m_log):
318318
del fut
319319
self.assertFalse(m_log.error.called)
320320

321+
@mock.patch('asyncio.base_events.logger')
322+
def test_tb_logger_not_called_after_cancel(self, m_log):
323+
fut = self._new_future(loop=self.loop)
324+
fut.set_exception(Exception())
325+
fut.cancel()
326+
del fut
327+
self.assertFalse(m_log.error.called)
328+
321329
@mock.patch('asyncio.base_events.logger')
322330
def test_tb_logger_result_unretrieved(self, m_log):
323331
fut = self._new_future(loop=self.loop)

Lib/test/test_asyncio/test_tasks.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,25 @@ def kill_me(loop):
18651865
})
18661866
mock_handler.reset_mock()
18671867

1868+
@mock.patch('asyncio.base_events.logger')
1869+
def test_tb_logger_not_called_after_cancel(self, m_log):
1870+
loop = asyncio.new_event_loop()
1871+
self.set_event_loop(loop)
1872+
1873+
@asyncio.coroutine
1874+
def coro():
1875+
raise TypeError
1876+
1877+
@asyncio.coroutine
1878+
def runner():
1879+
task = self.new_task(loop, coro())
1880+
yield from asyncio.sleep(0.05, loop=loop)
1881+
task.cancel()
1882+
task = None
1883+
1884+
loop.run_until_complete(runner())
1885+
self.assertFalse(m_log.error.called)
1886+
18681887
@mock.patch('asyncio.coroutines.logger')
18691888
def test_coroutine_never_yielded(self, m_log):
18701889
with set_coroutine_debug(True):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Core and Builtins
4949
Library
5050
-------
5151

52+
- bpo-30508: Don't log exceptions if Task/Future "cancel()" method was
53+
called.
54+
5255
- bpo-28556: Updates to typing module: Add generic AsyncContextManager, add
5356
support for ContextManager on all versions. Original PRs by Jelle Zijlstra
5457
and Ivan Levkivskyi

Modules/_asynciomodule.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ future_add_done_callback(FutureObj *fut, PyObject *arg)
305305
static PyObject *
306306
future_cancel(FutureObj *fut)
307307
{
308+
fut->fut_log_tb = 0;
309+
308310
if (fut->fut_state != STATE_PENDING) {
309311
Py_RETURN_FALSE;
310312
}
@@ -638,6 +640,17 @@ FutureObj_get_log_traceback(FutureObj *fut)
638640
}
639641
}
640642

643+
static int
644+
FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
645+
{
646+
int is_true = PyObject_IsTrue(val);
647+
if (is_true < 0) {
648+
return -1;
649+
}
650+
fut->fut_log_tb = is_true;
651+
return 0;
652+
}
653+
641654
static PyObject *
642655
FutureObj_get_loop(FutureObj *fut)
643656
{
@@ -882,7 +895,8 @@ static PyMethodDef FutureType_methods[] = {
882895
{"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \
883896
{"_result", (getter)FutureObj_get_result, NULL, NULL}, \
884897
{"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \
885-
{"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, \
898+
{"_log_traceback", (getter)FutureObj_get_log_traceback, \
899+
(setter)FutureObj_set_log_traceback, NULL}, \
886900
{"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL},
887901

888902
static PyGetSetDef FutureType_getsetlist[] = {
@@ -1568,6 +1582,8 @@ static PyObject *
15681582
_asyncio_Task_cancel_impl(TaskObj *self)
15691583
/*[clinic end generated code: output=6bfc0479da9d5757 input=13f9bf496695cb52]*/
15701584
{
1585+
self->task_log_tb = 0;
1586+
15711587
if (self->task_state != STATE_PENDING) {
15721588
Py_RETURN_FALSE;
15731589
}

0 commit comments

Comments
 (0)