]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-113538: Don't error in stream reader protocol callback when task is cancell...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 4 Jan 2024 20:39:52 +0000 (21:39 +0100)
committerGitHub <noreply@github.com>
Thu, 4 Jan 2024 20:39:52 +0000 (20:39 +0000)
(cherry picked from commit 4681a5271a8598b46021cbc556ac8098ab8a1d81)

Co-authored-by: Guido van Rossum <guido@python.org>
Lib/asyncio/streams.py
Lib/test/test_asyncio/test_streams.py
Misc/NEWS.d/next/Library/2024-01-03-14-19-26.gh-issue-113538.ahuBCo.rst [new file with mode: 0644]

index 23b6e4c32f7c6858093767235371c2be9362dbd2..26ffc86584e31f3b7f2f0c6ae1df0059096bbb46 100644 (file)
@@ -246,6 +246,9 @@ class StreamReaderProtocol(FlowControlMixin, protocols.Protocol):
                                             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({
index f5decbe53dacb30bbe4f1e7d53033783fefa389b..59ff89e7734dafb322dd26d55012f7961da38bb7 100644 (file)
@@ -1123,7 +1123,7 @@ os.close(fd)
 
         self.assertEqual(messages, [])
 
-    def test_unhandled_exceptions(self) -> None:
+    def _basetest_unhandled_exceptions(self, handle_echo):
         port = socket_helper.find_unused_port()
 
         messages = []
@@ -1137,9 +1137,6 @@ os.close(fd)
             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()
@@ -1148,11 +1145,20 @@ os.close(fd)
             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 (file)
index 0000000..a520765
--- /dev/null
@@ -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.