Skip to content

Commit a98f660

Browse files
sentrivanarominf
andauthored
feat: Preliminary support for Python 3.13 (#3200)
Adding preliminary support for Python 3.13. The `_partialmethod` attribute of methods wrapped with `partialmethod()` was renamed to `__partialmethod__` in CPython 3.13: python/cpython#16600 Starting from Python 3.13, `frame.f_locals` is not `dict` anymore, but `FrameLocalsProxy`, that cannot be copied using `copy.copy()`. In Python 3.13 and later, it should be copied using a method `.copy()`. The new way of copying works the same as the old one for versions of Python prior to 3.13, according to the documentation (both copying methods produce a shallow copy). Since Python 3.13, `FrameLocalsProxy` skips items of `locals()` that have non-`str` keys; this is a CPython implementation detail, so we hence disable `test_non_string_variables` test on Python 3.13. See: https://peps.python.org/pep-0667/ python/cpython#118921 python/cpython#118923 https://docs.python.org/3.13/whatsnew/3.13.html#porting-to-python-3-13 https://docs.python.org/3/library/copy.html https://github.com/python/cpython/blame/7b413952e817ae87bfda2ac85dd84d30a6ce743b/Objects/frameobject.c#L148 --------- Co-authored-by: Roman Inflianskas <rominf@pm.me>
1 parent cf8e37f commit a98f660

15 files changed

+43
-11
lines changed

Diff for: .github/workflows/test-integrations-ai.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox
@@ -96,6 +97,7 @@ jobs:
9697
- uses: actions/setup-python@v5
9798
with:
9899
python-version: ${{ matrix.python-version }}
100+
allow-prereleases: true
99101
- name: Setup Test Env
100102
run: |
101103
pip install coverage tox

Diff for: .github/workflows/test-integrations-aws-lambda.yml

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ jobs:
7171
- uses: actions/setup-python@v5
7272
with:
7373
python-version: ${{ matrix.python-version }}
74+
allow-prereleases: true
7475
- name: Setup Test Env
7576
run: |
7677
pip install coverage tox

Diff for: .github/workflows/test-integrations-cloud-computing.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox
@@ -92,6 +93,7 @@ jobs:
9293
- uses: actions/setup-python@v5
9394
with:
9495
python-version: ${{ matrix.python-version }}
96+
allow-prereleases: true
9597
- name: Setup Test Env
9698
run: |
9799
pip install coverage tox

Diff for: .github/workflows/test-integrations-common.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
strategy:
2626
fail-fast: false
2727
matrix:
28-
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12"]
28+
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13"]
2929
# python3.6 reached EOL and is no longer being supported on
3030
# new versions of hosted runners on Github Actions
3131
# ubuntu-20.04 is the last version that supported python3.6
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox

Diff for: .github/workflows/test-integrations-data-processing.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Start Redis
4041
uses: supercharge/redis-github-action@1.8.0
4142
- name: Setup Test Env
@@ -102,6 +103,7 @@ jobs:
102103
- uses: actions/setup-python@v5
103104
with:
104105
python-version: ${{ matrix.python-version }}
106+
allow-prereleases: true
105107
- name: Start Redis
106108
uses: supercharge/redis-github-action@1.8.0
107109
- name: Setup Test Env

Diff for: .github/workflows/test-integrations-databases.yml

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
- uses: actions/setup-python@v5
5555
with:
5656
python-version: ${{ matrix.python-version }}
57+
allow-prereleases: true
5758
- uses: getsentry/action-clickhouse-in-ci@v1
5859
- name: Setup Test Env
5960
run: |
@@ -137,6 +138,7 @@ jobs:
137138
- uses: actions/setup-python@v5
138139
with:
139140
python-version: ${{ matrix.python-version }}
141+
allow-prereleases: true
140142
- uses: getsentry/action-clickhouse-in-ci@v1
141143
- name: Setup Test Env
142144
run: |

Diff for: .github/workflows/test-integrations-graphql.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox
@@ -92,6 +93,7 @@ jobs:
9293
- uses: actions/setup-python@v5
9394
with:
9495
python-version: ${{ matrix.python-version }}
96+
allow-prereleases: true
9597
- name: Setup Test Env
9698
run: |
9799
pip install coverage tox

Diff for: .github/workflows/test-integrations-miscellaneous.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox
@@ -96,6 +97,7 @@ jobs:
9697
- uses: actions/setup-python@v5
9798
with:
9899
python-version: ${{ matrix.python-version }}
100+
allow-prereleases: true
99101
- name: Setup Test Env
100102
run: |
101103
pip install coverage tox

Diff for: .github/workflows/test-integrations-networking.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox
@@ -92,6 +93,7 @@ jobs:
9293
- uses: actions/setup-python@v5
9394
with:
9495
python-version: ${{ matrix.python-version }}
96+
allow-prereleases: true
9597
- name: Setup Test Env
9698
run: |
9799
pip install coverage tox

Diff for: .github/workflows/test-integrations-web-frameworks-1.yml

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
- uses: actions/setup-python@v5
5555
with:
5656
python-version: ${{ matrix.python-version }}
57+
allow-prereleases: true
5758
- name: Setup Test Env
5859
run: |
5960
pip install coverage tox
@@ -128,6 +129,7 @@ jobs:
128129
- uses: actions/setup-python@v5
129130
with:
130131
python-version: ${{ matrix.python-version }}
132+
allow-prereleases: true
131133
- name: Setup Test Env
132134
run: |
133135
pip install coverage tox

Diff for: .github/workflows/test-integrations-web-frameworks-2.yml

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
- uses: actions/setup-python@v5
3737
with:
3838
python-version: ${{ matrix.python-version }}
39+
allow-prereleases: true
3940
- name: Setup Test Env
4041
run: |
4142
pip install coverage tox
@@ -112,6 +113,7 @@ jobs:
112113
- uses: actions/setup-python@v5
113114
with:
114115
python-version: ${{ matrix.python-version }}
116+
allow-prereleases: true
115117
- name: Setup Test Env
116118
run: |
117119
pip install coverage tox

Diff for: scripts/split-tox-gh-actions/templates/test_group.jinja

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
- uses: actions/setup-python@v5
5050
with:
5151
python-version: {% raw %}${{ matrix.python-version }}{% endraw %}
52+
allow-prereleases: true
5253
{% if needs_clickhouse %}
5354
- uses: getsentry/action-clickhouse-in-ci@v1
5455
{% endif %}

Diff for: sentry_sdk/utils.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import threading
1212
import time
1313
from collections import namedtuple
14-
from copy import copy
1514
from datetime import datetime
1615
from decimal import Decimal
1716
from functools import partial, partialmethod, wraps
@@ -611,7 +610,7 @@ def serialize_frame(
611610
)
612611

613612
if include_local_variables:
614-
rv["vars"] = copy(frame.f_locals)
613+
rv["vars"] = frame.f_locals.copy()
615614

616615
return rv
617616

@@ -1330,14 +1329,18 @@ def qualname_from_function(func):
13301329

13311330
prefix, suffix = "", ""
13321331

1333-
if hasattr(func, "_partialmethod") and isinstance(
1334-
func._partialmethod, partialmethod
1335-
):
1336-
prefix, suffix = "partialmethod(<function ", ">)"
1337-
func = func._partialmethod.func
1338-
elif isinstance(func, partial) and hasattr(func.func, "__name__"):
1332+
if isinstance(func, partial) and hasattr(func.func, "__name__"):
13391333
prefix, suffix = "partial(<function ", ">)"
13401334
func = func.func
1335+
else:
1336+
# The _partialmethod attribute of methods wrapped with partialmethod() was renamed to __partialmethod__ in CPython 3.13:
1337+
# https://github.com/python/cpython/pull/16600
1338+
partial_method = getattr(func, "_partialmethod", None) or getattr(
1339+
func, "__partialmethod__", None
1340+
)
1341+
if isinstance(partial_method, partialmethod):
1342+
prefix, suffix = "partialmethod(<function ", ">)"
1343+
func = partial_method.func
13411344

13421345
if hasattr(func, "__qualname__"):
13431346
func_qualname = func.__qualname__

Diff for: tests/test_client.py

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333
from sentry_sdk._types import Event
3434

3535

36+
maximum_python_312 = pytest.mark.skipif(
37+
sys.version_info > (3, 12),
38+
reason="Since Python 3.13, `FrameLocalsProxy` skips items of `locals()` that have non-`str` keys; this is a CPython implementation detail: https://github.com/python/cpython/blame/7b413952e817ae87bfda2ac85dd84d30a6ce743b/Objects/frameobject.c#L148",
39+
)
40+
41+
3642
class EnvelopeCapturedError(Exception):
3743
pass
3844

@@ -889,6 +895,7 @@ class FooError(Exception):
889895
assert exception["mechanism"]["meta"]["errno"]["number"] == 69
890896

891897

898+
@maximum_python_312
892899
def test_non_string_variables(sentry_init, capture_events):
893900
"""There is some extremely terrible code in the wild that
894901
inserts non-strings as variable names into `locals()`."""

Diff for: tox.ini

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ requires =
99
virtualenv<20.26.3
1010
envlist =
1111
# === Common ===
12-
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12}-common
12+
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-common
1313

1414
# === Gevent ===
1515
{py3.6,py3.8,py3.10,py3.11,py3.12}-gevent
@@ -271,11 +271,12 @@ deps =
271271

272272
# === Common ===
273273
py3.8-common: hypothesis
274-
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12}-common: pytest-asyncio
274+
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-common: pytest-asyncio
275275
# See https://github.com/pytest-dev/pytest/issues/9621
276276
# and https://github.com/pytest-dev/pytest-forked/issues/67
277277
# for justification of the upper bound on pytest
278278
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12}-common: pytest<7.0.0
279+
py3.13-common: pytest
279280

280281
# === Gevent ===
281282
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0

0 commit comments

Comments
 (0)