Skip to content

Commit 430091a

Browse files
committed
fix: Python 3.14 task
python/cpython#129899
1 parent 6fd4dfd commit 430091a

File tree

5 files changed

+133
-3
lines changed

5 files changed

+133
-3
lines changed

nest_asyncio.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ def _get_event_loop(stacklevel=3):
4343
# Use module level _current_tasks, all_tasks and patch run method.
4444
if hasattr(asyncio, '_nest_patched'):
4545
return
46-
if sys.version_info >= (3, 6, 0):
46+
47+
# Using _PyTask on Python 3.14+ will break current_task() (and all_tasks(),
48+
# _swap_current_task())
49+
# Even we replace it with _py_current_task(), it only works with _PyTask, but
50+
# the external loop is probably using _CTask.
51+
# https://github.com/python/cpython/pull/129899
52+
if sys.version_info >= (3, 6, 0) and sys.version_info < (3, 14, 0):
4753
asyncio.Task = asyncio.tasks._CTask = asyncio.tasks.Task = \
4854
asyncio.tasks._PyTask
4955
asyncio.Future = asyncio.futures._CFuture = asyncio.futures.Future = \
@@ -127,14 +133,25 @@ def _run_once(self):
127133
if not handle._cancelled:
128134
# preempt the current task so that that checks in
129135
# Task.__step do not raise
130-
curr_task = curr_tasks.pop(self, None)
136+
if sys.version_info < (3, 14, 0):
137+
curr_task = curr_tasks.pop(self, None)
138+
else:
139+
# Work with both C and Py
140+
try:
141+
curr_task = asyncio.tasks._swap_current_task(self, None)
142+
except KeyError:
143+
curr_task = None
131144

132145
try:
133146
handle._run()
134147
finally:
135148
# restore the current task
136149
if curr_task is not None:
137-
curr_tasks[self] = curr_task
150+
if sys.version_info < (3, 14, 0):
151+
curr_tasks[self] = curr_task
152+
else:
153+
# Work with both C and Py
154+
asyncio.tasks._swap_current_task(self, curr_task)
138155

139156
handle = None
140157

tests/314_task.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# /// script
2+
# requires-python = ">=3.14"
3+
# dependencies = [
4+
# "nest-asyncio",
5+
# ]
6+
#
7+
# [tool.uv.sources]
8+
# nest-asyncio = { path = "../", editable = true }
9+
# ///
10+
import asyncio
11+
import nest_asyncio
12+
13+
nest_asyncio.apply()
14+
15+
async def f():
16+
print(asyncio.get_running_loop())
17+
assert asyncio.get_running_loop() is not None
18+
19+
print(asyncio.tasks._current_tasks)
20+
# assert asyncio.tasks._current_tasks == {}
21+
22+
print(asyncio.tasks.current_task())
23+
assert asyncio.tasks.current_task() is not None
24+
25+
print(asyncio.tasks._py_current_task())
26+
# assert asyncio.tasks._py_current_task() is None
27+
28+
print(asyncio.tasks._current_tasks)
29+
# assert asyncio.tasks._current_tasks == {}
30+
31+
asyncio.run(f())

tests/314_task_mix.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# /// script
2+
# requires-python = ">=3.14"
3+
# dependencies = [
4+
# "nest-asyncio",
5+
# ]
6+
#
7+
# [tool.uv.sources]
8+
# nest-asyncio = { path = "../", editable = true }
9+
# ///
10+
import asyncio
11+
import nest_asyncio
12+
13+
async def f():
14+
nest_asyncio.apply()
15+
16+
print(asyncio.get_running_loop())
17+
assert asyncio.get_running_loop() is not None
18+
19+
print(asyncio.tasks._current_tasks)
20+
# assert asyncio.tasks._current_tasks == {}
21+
22+
print(asyncio.tasks.current_task())
23+
assert asyncio.tasks.current_task() is not None
24+
25+
print(asyncio.tasks._py_current_task())
26+
# assert asyncio.tasks._py_current_task() is None
27+
28+
print(asyncio.tasks._current_tasks)
29+
# assert asyncio.tasks._current_tasks == {}
30+
31+
asyncio.run(f())

tests/nest_test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# /// script
2+
# requires-python = ">=3.5"
3+
# dependencies = [
4+
# "nest-asyncio",
5+
# ]
6+
#
7+
# [tool.uv.sources]
8+
# nest-asyncio = { path = "../", editable = true }
9+
# ///
110
import asyncio
211
import sys
312
import unittest

tests/test.ps1

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
pushd tests
2+
3+
# uv run --python 3.5 nest_test.py
4+
uv run --python 3.8 nest_test.py
5+
if (!$?) {
6+
throw "3.10"
7+
}
8+
uv run --python 3.9 nest_test.py
9+
if (!$?) {
10+
throw "3.9"
11+
}
12+
uv run --python 3.10 nest_test.py
13+
if (!$?) {
14+
throw "3.10"
15+
}
16+
uv run --python 3.11 nest_test.py
17+
if (!$?) {
18+
throw "3.11"
19+
}
20+
uv run --python 3.12 nest_test.py
21+
if (!$?) {
22+
throw "3.12"
23+
}
24+
uv run --python 3.13 nest_test.py
25+
if (!$?) {
26+
throw "3.13"
27+
}
28+
uv run --python 3.14 nest_test.py
29+
if (!$?) {
30+
throw "3.14"
31+
}
32+
33+
uv run --python 3.14 314_task.py
34+
if (!$?) {
35+
throw "314_task"
36+
}
37+
uv run --python 3.14 314_task_mix.py
38+
if (!$?) {
39+
throw "314_task_mix"
40+
}
41+
42+
popd

0 commit comments

Comments
 (0)