Skip to content

Commit 0f5fc6c

Browse files
Fixes for 3.13 (#3005)
* Try out naive KI protection fix * Update generated files * Account for `._local` in full name * Add 3.13 to CI matrix * Avoid cryptography * Avoid an evil operation, I guess * un-inline ki protection decorator new f_locals method doesn't create a cycle in this situation * Advertise 3.12 + maybe cryptography works? * Switch back to avoiding cryptography * Try cryptography one more time * Add symbols * Try one other possibility for symbols * More symbol trial and error * Try to pick up patterns in what allows what * Test hypothesis * Finish off failures * Remove trailing whitespace --------- Co-authored-by: richardsheridan <[email protected]>
1 parent 4dcdc6d commit 0f5fc6c

15 files changed

+61
-45
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787
strategy:
8888
fail-fast: false
8989
matrix:
90-
python: ['pypy-3.9', 'pypy-3.10', '3.8', '3.9', '3.10', '3.11', '3.12']
90+
python: ['pypy-3.9', 'pypy-3.10', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
9191
check_formatting: ['0']
9292
no_test_requirements: ['0']
9393
extra_name: ['']

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ classifiers = [
3131
"Programming Language :: Python :: 3.10",
3232
"Programming Language :: Python :: 3.11",
3333
"Programming Language :: Python :: 3.12",
34+
"Programming Language :: Python :: 3.13",
3435
"Topic :: System :: Networking",
3536
"Typing :: Typed",
3637
]

src/trio/_core/_generated_instrumentation.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# *************************************************************
44
from __future__ import annotations
55

6+
import sys
67
from typing import TYPE_CHECKING
78

89
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
@@ -23,7 +24,7 @@ def add_instrument(instrument: Instrument) -> None:
2324
If ``instrument`` is already active, does nothing.
2425
2526
"""
26-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
27+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
2728
try:
2829
return GLOBAL_RUN_CONTEXT.runner.instruments.add_instrument(instrument)
2930
except AttributeError:
@@ -43,7 +44,7 @@ def remove_instrument(instrument: Instrument) -> None:
4344
deactivated.
4445
4546
"""
46-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
47+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
4748
try:
4849
return GLOBAL_RUN_CONTEXT.runner.instruments.remove_instrument(instrument)
4950
except AttributeError:

src/trio/_core/_generated_io_epoll.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
# *************************************************************
44
from __future__ import annotations
55

6+
import sys
67
from typing import TYPE_CHECKING
78

89
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
910
from ._run import GLOBAL_RUN_CONTEXT
1011

1112
if TYPE_CHECKING:
1213
from .._file_io import _HasFileNo
13-
import sys
1414

1515
assert not TYPE_CHECKING or sys.platform == "linux"
1616

@@ -40,7 +40,7 @@ async def wait_readable(fd: int | _HasFileNo) -> None:
4040
if another task calls :func:`notify_closing` while this
4141
function is still working.
4242
"""
43-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
43+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
4444
try:
4545
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(fd)
4646
except AttributeError:
@@ -59,7 +59,7 @@ async def wait_writable(fd: int | _HasFileNo) -> None:
5959
if another task calls :func:`notify_closing` while this
6060
function is still working.
6161
"""
62-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
62+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
6363
try:
6464
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(fd)
6565
except AttributeError:
@@ -91,7 +91,7 @@ def notify_closing(fd: int | _HasFileNo) -> None:
9191
step, so other tasks won't be able to tell what order they happened
9292
in anyway.
9393
"""
94-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
94+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
9595
try:
9696
return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(fd)
9797
except AttributeError:

src/trio/_core/_generated_io_kqueue.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# *************************************************************
44
from __future__ import annotations
55

6+
import sys
67
from typing import TYPE_CHECKING, Callable, ContextManager
78

89
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
@@ -14,7 +15,6 @@
1415
from .. import _core
1516
from .._file_io import _HasFileNo
1617
from ._traps import Abort, RaiseCancelT
17-
import sys
1818

1919
assert not TYPE_CHECKING or sys.platform == "darwin"
2020

@@ -34,7 +34,7 @@ def current_kqueue() -> select.kqueue:
3434
anything real. See `#26
3535
<https://github.com/python-trio/trio/issues/26>`__.
3636
"""
37-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
37+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
3838
try:
3939
return GLOBAL_RUN_CONTEXT.runner.io_manager.current_kqueue()
4040
except AttributeError:
@@ -48,7 +48,7 @@ def monitor_kevent(
4848
anything real. See `#26
4949
<https://github.com/python-trio/trio/issues/26>`__.
5050
"""
51-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
51+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
5252
try:
5353
return GLOBAL_RUN_CONTEXT.runner.io_manager.monitor_kevent(ident, filter)
5454
except AttributeError:
@@ -62,7 +62,7 @@ async def wait_kevent(
6262
anything real. See `#26
6363
<https://github.com/python-trio/trio/issues/26>`__.
6464
"""
65-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
65+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
6666
try:
6767
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_kevent(
6868
ident, filter, abort_func
@@ -93,7 +93,7 @@ async def wait_readable(fd: int | _HasFileNo) -> None:
9393
if another task calls :func:`notify_closing` while this
9494
function is still working.
9595
"""
96-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
96+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
9797
try:
9898
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(fd)
9999
except AttributeError:
@@ -112,7 +112,7 @@ async def wait_writable(fd: int | _HasFileNo) -> None:
112112
if another task calls :func:`notify_closing` while this
113113
function is still working.
114114
"""
115-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
115+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
116116
try:
117117
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(fd)
118118
except AttributeError:
@@ -144,7 +144,7 @@ def notify_closing(fd: int | _HasFileNo) -> None:
144144
step, so other tasks won't be able to tell what order they happened
145145
in anyway.
146146
"""
147-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
147+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
148148
try:
149149
return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(fd)
150150
except AttributeError:

src/trio/_core/_generated_io_windows.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# *************************************************************
44
from __future__ import annotations
55

6+
import sys
67
from typing import TYPE_CHECKING, ContextManager
78

89
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
@@ -14,7 +15,6 @@
1415
from .._file_io import _HasFileNo
1516
from ._unbounded_queue import UnboundedQueue
1617
from ._windows_cffi import CData, Handle
17-
import sys
1818

1919
assert not TYPE_CHECKING or sys.platform == "win32"
2020

@@ -54,7 +54,7 @@ async def wait_readable(sock: _HasFileNo | int) -> None:
5454
if another task calls :func:`notify_closing` while this
5555
function is still working.
5656
"""
57-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
57+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
5858
try:
5959
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(sock)
6060
except AttributeError:
@@ -73,7 +73,7 @@ async def wait_writable(sock: _HasFileNo | int) -> None:
7373
if another task calls :func:`notify_closing` while this
7474
function is still working.
7575
"""
76-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
76+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
7777
try:
7878
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(sock)
7979
except AttributeError:
@@ -105,7 +105,7 @@ def notify_closing(handle: Handle | int | _HasFileNo) -> None:
105105
step, so other tasks won't be able to tell what order they happened
106106
in anyway.
107107
"""
108-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
108+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
109109
try:
110110
return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(handle)
111111
except AttributeError:
@@ -118,7 +118,7 @@ def register_with_iocp(handle: int | CData) -> None:
118118
<https://github.com/python-trio/trio/issues/26>`__ and `#52
119119
<https://github.com/python-trio/trio/issues/52>`__.
120120
"""
121-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
121+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
122122
try:
123123
return GLOBAL_RUN_CONTEXT.runner.io_manager.register_with_iocp(handle)
124124
except AttributeError:
@@ -131,7 +131,7 @@ async def wait_overlapped(handle_: int | CData, lpOverlapped: CData | int) -> ob
131131
<https://github.com/python-trio/trio/issues/26>`__ and `#52
132132
<https://github.com/python-trio/trio/issues/52>`__.
133133
"""
134-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
134+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
135135
try:
136136
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_overlapped(
137137
handle_, lpOverlapped
@@ -148,7 +148,7 @@ async def write_overlapped(
148148
<https://github.com/python-trio/trio/issues/26>`__ and `#52
149149
<https://github.com/python-trio/trio/issues/52>`__.
150150
"""
151-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
151+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
152152
try:
153153
return await GLOBAL_RUN_CONTEXT.runner.io_manager.write_overlapped(
154154
handle, data, file_offset
@@ -165,7 +165,7 @@ async def readinto_overlapped(
165165
<https://github.com/python-trio/trio/issues/26>`__ and `#52
166166
<https://github.com/python-trio/trio/issues/52>`__.
167167
"""
168-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
168+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
169169
try:
170170
return await GLOBAL_RUN_CONTEXT.runner.io_manager.readinto_overlapped(
171171
handle, buffer, file_offset
@@ -180,7 +180,7 @@ def current_iocp() -> int:
180180
<https://github.com/python-trio/trio/issues/26>`__ and `#52
181181
<https://github.com/python-trio/trio/issues/52>`__.
182182
"""
183-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
183+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
184184
try:
185185
return GLOBAL_RUN_CONTEXT.runner.io_manager.current_iocp()
186186
except AttributeError:
@@ -193,7 +193,7 @@ def monitor_completion_key() -> ContextManager[tuple[int, UnboundedQueue[object]
193193
<https://github.com/python-trio/trio/issues/26>`__ and `#52
194194
<https://github.com/python-trio/trio/issues/52>`__.
195195
"""
196-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
196+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
197197
try:
198198
return GLOBAL_RUN_CONTEXT.runner.io_manager.monitor_completion_key()
199199
except AttributeError:

src/trio/_core/_generated_run.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# *************************************************************
44
from __future__ import annotations
55

6+
import sys
67
from typing import TYPE_CHECKING, Any
78

89
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
@@ -55,7 +56,7 @@ def current_statistics() -> RunStatistics:
5556
other attributes vary between backends.
5657
5758
"""
58-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
59+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
5960
try:
6061
return GLOBAL_RUN_CONTEXT.runner.current_statistics()
6162
except AttributeError:
@@ -72,7 +73,7 @@ def current_time() -> float:
7273
RuntimeError: if not inside a call to :func:`trio.run`.
7374
7475
"""
75-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
76+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
7677
try:
7778
return GLOBAL_RUN_CONTEXT.runner.current_time()
7879
except AttributeError:
@@ -81,7 +82,7 @@ def current_time() -> float:
8182

8283
def current_clock() -> Clock:
8384
"""Returns the current :class:`~trio.abc.Clock`."""
84-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
85+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
8586
try:
8687
return GLOBAL_RUN_CONTEXT.runner.current_clock()
8788
except AttributeError:
@@ -94,7 +95,7 @@ def current_root_task() -> Task | None:
9495
This is the task that is the ultimate parent of all other tasks.
9596
9697
"""
97-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
98+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
9899
try:
99100
return GLOBAL_RUN_CONTEXT.runner.current_root_task()
100101
except AttributeError:
@@ -119,7 +120,7 @@ def reschedule(task: Task, next_send: Outcome[Any] = _NO_SEND) -> None:
119120
raise) from :func:`wait_task_rescheduled`.
120121
121122
"""
122-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
123+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
123124
try:
124125
return GLOBAL_RUN_CONTEXT.runner.reschedule(task, next_send)
125126
except AttributeError:
@@ -183,7 +184,7 @@ def spawn_system_task(
183184
Task: the newly spawned task
184185
185186
"""
186-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
187+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
187188
try:
188189
return GLOBAL_RUN_CONTEXT.runner.spawn_system_task(
189190
async_fn, *args, name=name, context=context
@@ -197,7 +198,7 @@ def current_trio_token() -> TrioToken:
197198
:func:`trio.run`.
198199
199200
"""
200-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
201+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
201202
try:
202203
return GLOBAL_RUN_CONTEXT.runner.current_trio_token()
203204
except AttributeError:
@@ -262,7 +263,7 @@ async def test_lock_fairness():
262263
print("FAIL")
263264
264265
"""
265-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
266+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
266267
try:
267268
return await GLOBAL_RUN_CONTEXT.runner.wait_all_tasks_blocked(cushion)
268269
except AttributeError:

src/trio/_core/_ki.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def wrapper(*args: ArgsT.args, **kwargs: ArgsT.kwargs) -> RetT: # type: ignore[
178178

179179
@wraps(fn)
180180
def wrapper(*args: ArgsT.args, **kwargs: ArgsT.kwargs) -> RetT:
181-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = enabled
181+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = enabled
182182
return fn(*args, **kwargs)
183183

184184
return wrapper

src/trio/_core/_run.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ def _close(self, exc: BaseException | None) -> BaseException | None:
623623
self._cancel_status = None
624624
return exc
625625

626+
@enable_ki_protection
626627
def __exit__(
627628
self,
628629
etype: type[BaseException] | None,
@@ -633,10 +634,6 @@ def __exit__(
633634
# so __exit__() must be just _close() plus this logic for adapting
634635
# the exception-filtering result to the context manager API.
635636

636-
# This inlines the enable_ki_protection decorator so we can fix
637-
# f_locals *locally* below to avoid reference cycles
638-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
639-
640637
# Tracebacks show the 'raise' line below out of context, so let's give
641638
# this variable a name that makes sense out of context.
642639
remaining_error_after_cancel_scope = self._close(exc)
@@ -658,10 +655,6 @@ def __exit__(
658655
# see test_cancel_scope_exit_doesnt_create_cyclic_garbage
659656
# Note: still relevant
660657
del remaining_error_after_cancel_scope, value, _, exc
661-
# deep magic to remove refs via f_locals
662-
locals()
663-
# TODO: check if PEP558 changes the need for this call
664-
# https://github.com/python/cpython/pull/3640
665658

666659
def __repr__(self) -> str:
667660
if self._cancel_status is not None:
@@ -2476,7 +2469,7 @@ def unrolled_run(
24762469
args: tuple[Unpack[PosArgT]],
24772470
host_uses_signal_set_wakeup_fd: bool = False,
24782471
) -> Generator[float, EventResult, None]:
2479-
locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
2472+
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
24802473
__tracebackhide__ = True
24812474

24822475
try:

src/trio/_path.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ def __repr__(self) -> str:
242242
write_text = _wrap_method(pathlib.Path.write_text)
243243
if sys.version_info < (3, 12):
244244
link_to = _wrap_method(pathlib.Path.link_to)
245+
if sys.version_info >= (3, 13):
246+
full_match = _wrap_method(pathlib.Path.full_match)
245247

246248

247249
@final

0 commit comments

Comments
 (0)