https://github.com/python/cpython/commit/b2fff0ea858077a7bbd336e27ae3bd3d25163da2
commit: b2fff0ea858077a7bbd336e27ae3bd3d25163da2
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-12-09T20:15:50+05:30
summary:

[3.13] gh-105836: Fix `asyncio.run_coroutine_threadsafe` leaving underlying 
cancelled asyncio task running (GH-141696) (#142359)

gh-105836: Fix `asyncio.run_coroutine_threadsafe` leaving underlying cancelled 
asyncio task running (GH-141696)
(cherry picked from commit 14715e3a64a674629c781d4a3dd11143ba010990)

Co-authored-by: Kaisheng Xu <[email protected]>
Co-authored-by: Kumar Aditya <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-11-18-15-48-13.gh-issue-105836.sbUw24.rst
M Lib/asyncio/futures.py
M Lib/test/test_asyncio/test_tasks.py
M Misc/ACKS

diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 51932639097bbd..e24e16de751b9f 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -383,7 +383,7 @@ def _set_state(future, other):
 
     def _call_check_cancel(destination):
         if destination.cancelled():
-            if source_loop is None or source_loop is dest_loop:
+            if source_loop is None or source_loop is 
events._get_running_loop():
                 source.cancel()
             else:
                 source_loop.call_soon_threadsafe(source.cancel)
@@ -392,7 +392,7 @@ def _call_set_state(source):
         if (destination.cancelled() and
                 dest_loop is not None and dest_loop.is_closed()):
             return
-        if dest_loop is None or dest_loop is source_loop:
+        if dest_loop is None or dest_loop is events._get_running_loop():
             _set_state(destination, source)
         else:
             if dest_loop.is_closed():
diff --git a/Lib/test/test_asyncio/test_tasks.py 
b/Lib/test/test_asyncio/test_tasks.py
index 54692713011278..361ad8a7874077 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -3552,6 +3552,30 @@ def task_factory(loop, coro):
         (loop, context), kwargs = callback.call_args
         self.assertEqual(context['exception'], exc_context.exception)
 
+    def test_run_coroutine_threadsafe_and_cancel(self):
+        task = None
+        thread_future = None
+        # Use a custom task factory to capture the created Task
+        def task_factory(loop, coro):
+            nonlocal task
+            task = asyncio.Task(coro, loop=loop)
+            return task
+
+        self.addCleanup(self.loop.set_task_factory,
+                        self.loop.get_task_factory())
+
+        async def target():
+            nonlocal thread_future
+            self.loop.set_task_factory(task_factory)
+            thread_future = 
asyncio.run_coroutine_threadsafe(asyncio.sleep(10), self.loop)
+            await asyncio.sleep(0)
+
+            thread_future.cancel()
+
+        self.loop.run_until_complete(target())
+        self.assertTrue(task.cancelled())
+        self.assertTrue(thread_future.cancelled())
+
 
 class SleepTests(test_utils.TestCase):
     def setUp(self):
diff --git a/Misc/ACKS b/Misc/ACKS
index 6cc30812cced11..55713d3b286835 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -2074,6 +2074,7 @@ Xiang Zhang
 Robert Xiao
 Florent Xicluna
 Yanbo, Xie
+Kaisheng Xu
 Xinhang Xu
 Arnon Yaari
 Alakshendra Yadav
diff --git 
a/Misc/NEWS.d/next/Library/2025-11-18-15-48-13.gh-issue-105836.sbUw24.rst 
b/Misc/NEWS.d/next/Library/2025-11-18-15-48-13.gh-issue-105836.sbUw24.rst
new file mode 100644
index 00000000000000..d2edc5b2cb743d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-11-18-15-48-13.gh-issue-105836.sbUw24.rst
@@ -0,0 +1,2 @@
+Fix :meth:`asyncio.run_coroutine_threadsafe` leaving underlying cancelled
+asyncio task running.

_______________________________________________
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]

Reply via email to