Skip to content

Commit

Permalink
pythongh-113538: Don't error in stream reader protocol callback when …
Browse files Browse the repository at this point in the history
…task is cancelled (python#113690)
  • Loading branch information
gvanrossum committed Jan 4, 2024
1 parent 1600d78 commit 4681a52
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 7 deletions.
3 changes: 3 additions & 0 deletions Lib/asyncio/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ def connection_made(self, transport):
self._stream_writer)
if coroutines.iscoroutine(res):
def callback(task):
if task.cancelled():
transport.close()
return
exc = task.exception()
if exc is not None:
self._loop.call_exception_handler({
Expand Down
20 changes: 13 additions & 7 deletions Lib/test/test_asyncio/test_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,7 @@ async def inner(httpd):

self.assertEqual(messages, [])

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

messages = []
Expand All @@ -1143,9 +1143,6 @@ async def client():
await wr.wait_closed()

async def main():
async def handle_echo(reader, writer):
raise Exception('test')

server = await asyncio.start_server(
handle_echo, 'localhost', port)
await server.start_serving()
Expand All @@ -1154,11 +1151,20 @@ async def handle_echo(reader, writer):
await server.wait_closed()

self.loop.run_until_complete(main())
return messages

def test_unhandled_exception(self):
async def handle_echo(reader, writer):
raise Exception('test')
messages = self._basetest_unhandled_exceptions(handle_echo)
self.assertEqual(messages[0]['message'],
'Unhandled exception in client_connected_cb')
# Break explicitly reference cycle
messages = None
'Unhandled exception in client_connected_cb')

def test_unhandled_cancel(self):
async def handle_echo(reader, writer):
asyncio.current_task().cancel()
messages = self._basetest_unhandled_exceptions(handle_echo)
self.assertEqual(messages, [])


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

0 comments on commit 4681a52

Please sign in to comment.