https://github.com/python/cpython/commit/4681a5271a8598b46021cbc556ac8098ab8a1d81
commit: 4681a5271a8598b46021cbc556ac8098ab8a1d81
branch: main
author: Guido van Rossum <[email protected]>
committer: gvanrossum <[email protected]>
date: 2024-01-04T12:20:21-08:00
summary:
gh-113538: Don't error in stream reader protocol callback when task is
cancelled (#113690)
files:
A Misc/NEWS.d/next/Library/2024-01-03-14-19-26.gh-issue-113538.ahuBCo.rst
M Lib/asyncio/streams.py
M Lib/test/test_asyncio/test_streams.py
diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py
index ffb48b9cd6cb70..df58b7a799a5ad 100644
--- a/Lib/asyncio/streams.py
+++ b/Lib/asyncio/streams.py
@@ -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({
diff --git a/Lib/test/test_asyncio/test_streams.py
b/Lib/test/test_asyncio/test_streams.py
index b408cd1f7da205..3c8cc5f3649180 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -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 = []
@@ -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()
@@ -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__':
diff --git
a/Misc/NEWS.d/next/Library/2024-01-03-14-19-26.gh-issue-113538.ahuBCo.rst
b/Misc/NEWS.d/next/Library/2024-01-03-14-19-26.gh-issue-113538.ahuBCo.rst
new file mode 100644
index 00000000000000..a52076501b7bf4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-01-03-14-19-26.gh-issue-113538.ahuBCo.rst
@@ -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.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]