[Python-checkins] GH-95097: fix `asyncio.run` for tasks without `uncancel` method (GH-95211) (GH-95387)

ambv webhook-mailer at python.org
Fri Jul 29 08:38:06 EDT 2022


https://github.com/python/cpython/commit/efeda8b4a1fd8f1c510311c40e46d5fad65512a0
commit: efeda8b4a1fd8f1c510311c40e46d5fad65512a0
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: ambv <lukasz at langa.pl>
date: 2022-07-29T14:38:02+02:00
summary:

GH-95097: fix `asyncio.run` for tasks without `uncancel` method (GH-95211) (GH-95387)

(cherry picked from commit 54f48844d18bc6fb98849f15a2fc08f92ad240ea)

Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com>
Co-authored-by: Thomas Grainger <tagrain at gmail.com>

files:
A Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst
M Lib/asyncio/runners.py
M Lib/test/test_asyncio/test_runners.py

diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py
index c58b52ed862e8..a19a7f99af064 100644
--- a/Lib/asyncio/runners.py
+++ b/Lib/asyncio/runners.py
@@ -119,10 +119,11 @@ def run(self, coro, *, context=None):
                 events.set_event_loop(self._loop)
             return self._loop.run_until_complete(task)
         except exceptions.CancelledError:
-            if self._interrupt_count > 0 and task.uncancel() == 0:
-                raise KeyboardInterrupt()
-            else:
-                raise  # CancelledError
+            if self._interrupt_count > 0:
+                uncancel = getattr(task, "uncancel", None)
+                if uncancel is not None and uncancel() == 0:
+                    raise KeyboardInterrupt()
+            raise  # CancelledError
         finally:
             if (sigint_handler is not None
                 and signal.getsignal(signal.SIGINT) is sigint_handler
diff --git a/Lib/test/test_asyncio/test_runners.py b/Lib/test/test_asyncio/test_runners.py
index a27942c4f53eb..5e1db2357e75f 100644
--- a/Lib/test/test_asyncio/test_runners.py
+++ b/Lib/test/test_asyncio/test_runners.py
@@ -6,10 +6,9 @@
 import signal
 import threading
 import unittest
-
+from test.test_asyncio import utils as test_utils
 from unittest import mock
 from unittest.mock import patch
-from test.test_asyncio import utils as test_utils
 
 
 def tearDownModule():
@@ -211,6 +210,54 @@ async def main():
         asyncio.run(main())
         self.assertTrue(policy.set_event_loop.called)
 
+    def test_asyncio_run_without_uncancel(self):
+        # See https://github.com/python/cpython/issues/95097
+        class Task:
+            def __init__(self, loop, coro, **kwargs):
+                self._task = asyncio.Task(coro, loop=loop, **kwargs)
+
+            def cancel(self, *args, **kwargs):
+                return self._task.cancel(*args, **kwargs)
+
+            def add_done_callback(self, *args, **kwargs):
+                return self._task.add_done_callback(*args, **kwargs)
+
+            def remove_done_callback(self, *args, **kwargs):
+                return self._task.remove_done_callback(*args, **kwargs)
+
+            @property
+            def _asyncio_future_blocking(self):
+                return self._task._asyncio_future_blocking
+
+            def result(self, *args, **kwargs):
+                return self._task.result(*args, **kwargs)
+
+            def done(self, *args, **kwargs):
+                return self._task.done(*args, **kwargs)
+
+            def cancelled(self, *args, **kwargs):
+                return self._task.cancelled(*args, **kwargs)
+
+            def exception(self, *args, **kwargs):
+                return self._task.exception(*args, **kwargs)
+
+            def get_loop(self, *args, **kwargs):
+                return self._task.get_loop(*args, **kwargs)
+
+
+        async def main():
+            interrupt_self()
+            await asyncio.Event().wait()
+
+        def new_event_loop():
+            loop = self.new_loop()
+            loop.set_task_factory(Task)
+            return loop
+
+        asyncio.set_event_loop_policy(TestPolicy(new_event_loop))
+        with self.assertRaises(asyncio.CancelledError):
+            asyncio.run(main())
+
 
 class RunnerTests(BaseTest):
 
diff --git a/Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst b/Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst
new file mode 100644
index 0000000000000..2840f057a9c1d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst
@@ -0,0 +1 @@
+Fix :func:`asyncio.run` for :class:`asyncio.Task` implementations without :meth:`~asyncio.Task.uncancel` method. Patch by Kumar Aditya.



More information about the Python-checkins mailing list