summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKumar Aditya <59607654+kumaraditya303@users.noreply.github.com>2022-07-28 15:47:54 (GMT)
committerGitHub <noreply@github.com>2022-07-28 15:47:54 (GMT)
commit54f48844d18bc6fb98849f15a2fc08f92ad240ea (patch)
tree203de211ae283397c8bc92c182e6bee42aeab3e6
parentbceb197947bbaebb11e01195bdce4f240fdf9332 (diff)
downloadcpython-54f48844d18bc6fb98849f15a2fc08f92ad240ea.zip
cpython-54f48844d18bc6fb98849f15a2fc08f92ad240ea.tar.gz
cpython-54f48844d18bc6fb98849f15a2fc08f92ad240ea.tar.bz2
GH-95097: fix `asyncio.run` for tasks without `uncancel` method (#95211)
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
-rw-r--r--Lib/asyncio/runners.py9
-rw-r--r--Lib/test/test_asyncio/test_runners.py51
-rw-r--r--Misc/NEWS.d/next/Library/2022-07-24-18-00-42.gh-issue-95097.lu5qNf.rst1
3 files changed, 55 insertions, 6 deletions
diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py
index 7489a50..a8b74d5 100644
--- a/Lib/asyncio/runners.py
+++ b/Lib/asyncio/runners.py
@@ -118,10 +118,11 @@ class Runner:
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 1f6a498..d61d073a 100644
--- a/Lib/test/test_asyncio/test_runners.py
+++ b/Lib/test/test_asyncio/test_runners.py
@@ -5,10 +5,9 @@ import re
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():
@@ -210,6 +209,54 @@ class RunTests(BaseTest):
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 0000000..2840f05
--- /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.