Skip to content

Commit 456e2ec

Browse files
[3.11] gh-113538: Don't error in stream reader protocol callback when task is cancelled (GH-113690) (#113714)
(cherry picked from commit 4681a52) Co-authored-by: Guido van Rossum <[email protected]>
1 parent c828dbc commit 456e2ec

File tree

3 files changed

+21
-7
lines changed

3 files changed

+21
-7
lines changed

Lib/asyncio/streams.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ def connection_made(self, transport):
246246
self._stream_writer)
247247
if coroutines.iscoroutine(res):
248248
def callback(task):
249+
if task.cancelled():
250+
transport.close()
251+
return
249252
exc = task.exception()
250253
if exc is not None:
251254
self._loop.call_exception_handler({

Lib/test/test_asyncio/test_streams.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,7 @@ async def inner(httpd):
11231123

11241124
self.assertEqual(messages, [])
11251125

1126-
def test_unhandled_exceptions(self) -> None:
1126+
def _basetest_unhandled_exceptions(self, handle_echo):
11271127
port = socket_helper.find_unused_port()
11281128

11291129
messages = []
@@ -1137,9 +1137,6 @@ async def client():
11371137
await wr.wait_closed()
11381138

11391139
async def main():
1140-
async def handle_echo(reader, writer):
1141-
raise Exception('test')
1142-
11431140
server = await asyncio.start_server(
11441141
handle_echo, 'localhost', port)
11451142
await server.start_serving()
@@ -1148,11 +1145,20 @@ async def handle_echo(reader, writer):
11481145
await server.wait_closed()
11491146

11501147
self.loop.run_until_complete(main())
1148+
return messages
11511149

1150+
def test_unhandled_exception(self):
1151+
async def handle_echo(reader, writer):
1152+
raise Exception('test')
1153+
messages = self._basetest_unhandled_exceptions(handle_echo)
11521154
self.assertEqual(messages[0]['message'],
1153-
'Unhandled exception in client_connected_cb')
1154-
# Break explicitly reference cycle
1155-
messages = None
1155+
'Unhandled exception in client_connected_cb')
1156+
1157+
def test_unhandled_cancel(self):
1158+
async def handle_echo(reader, writer):
1159+
asyncio.current_task().cancel()
1160+
messages = self._basetest_unhandled_exceptions(handle_echo)
1161+
self.assertEqual(messages, [])
11561162

11571163

11581164
if __name__ == '__main__':
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
In :meth:`asyncio.StreamReaderProtocol.connection_made`, there is callback
2+
that logs an error if the task wrapping the "connected callback" fails. This
3+
callback would itself fail if the task was cancelled. Prevent this by
4+
checking whether the task was cancelled first. If so, close the transport
5+
but don't log an error.

0 commit comments

Comments
 (0)