Skip to content

Commit b751725

Browse files
alexander-alderman-webbshellmayr
authored andcommitted
ci: Run common test suite on Python 3.14t (#4969)
Update `split_tox_gh_actions.py` to support the free-threading `t` suffix in versions. Upgrade `pip` in tox for free-threaded Python by setting `VIRTUALENV_PIP`. Check sys.flags.thread_inherit_context to determine if context is already propagated when creating threads in the `threading` tests. See https://docs.python.org/3/howto/free-threading-python.html#context-variables Closes #4970
1 parent 68bdbda commit b751725

File tree

7 files changed

+39
-17
lines changed

7 files changed

+39
-17
lines changed

.github/workflows/test-integrations-common.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
strategy:
3030
fail-fast: false
3131
matrix:
32-
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14"]
32+
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t"]
3333
# python3.6 reached EOL and is no longer being supported on
3434
# new versions of hosted runners on Github Actions
3535
# ubuntu-20.04 is the last version that supported python3.6

.github/workflows/test-integrations-misc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
strategy:
3030
fail-fast: false
3131
matrix:
32-
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14"]
32+
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t"]
3333
# python3.6 reached EOL and is no longer being supported on
3434
# new versions of hosted runners on Github Actions
3535
# ubuntu-20.04 is the last version that supported python3.6

.github/workflows/test-integrations-web-2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
strategy:
3030
fail-fast: false
3131
matrix:
32-
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14"]
32+
python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t"]
3333
# python3.6 reached EOL and is no longer being supported on
3434
# new versions of hosted runners on Github Actions
3535
# ubuntu-20.04 is the last version that supported python3.6

scripts/populate_tox/tox.jinja

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ requires =
1818
virtualenv<20.26.3
1919
envlist =
2020
# === Common ===
21-
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}-common
21+
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t}-common
2222

2323
# === Gevent ===
2424
{py3.6,py3.8,py3.10,py3.11,py3.12}-gevent
2525

2626
# === Integrations ===
2727

2828
# Asgi
29-
{py3.7,py3.12,py3.13,py3.14}-asgi
29+
{py3.7,py3.12,py3.13,py3.14,py3.14t}-asgi
3030

3131
# AWS Lambda
3232
{py3.8,py3.9,py3.11,py3.13}-aws_lambda
@@ -38,7 +38,7 @@ envlist =
3838
{py3.7}-gcp
3939

4040
# OpenTelemetry (OTel)
41-
{py3.7,py3.9,py3.12,py3.13,py3.14}-opentelemetry
41+
{py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-opentelemetry
4242

4343
# OpenTelemetry Experimental (POTel)
4444
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel
@@ -74,7 +74,7 @@ deps =
7474
# and https://github.com/pytest-dev/pytest-forked/issues/67
7575
# for justification of the upper bound on pytest
7676
{py3.6,py3.7}-common: pytest<7.0.0
77-
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}-common: pytest
77+
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t}-common: pytest
7878
7979
# === Gevent ===
8080
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0
@@ -134,6 +134,9 @@ setenv =
134134
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
135135
COVERAGE_FILE=.coverage-sentry-{envname}
136136
py3.6: COVERAGE_RCFILE=.coveragerc36
137+
# Lowest version to support free-threading
138+
# https://discuss.python.org/t/announcement-pip-24-1-release/56281
139+
py3.14t: VIRTUALENV_PIP=24.1
137140
138141
django: DJANGO_SETTINGS_MODULE=tests.integrations.django.myapp.settings
139142
spark-v{3.0.3,3.5.6}: JAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64
@@ -178,6 +181,7 @@ basepython =
178181
py3.12: python3.12
179182
py3.13: python3.13
180183
py3.14: python3.14
184+
py3.14t: python3.14t
181185
182186
# Python version is pinned here for consistency across environments.
183187
# Tools like ruff and mypy have options that pin the target Python

scripts/split_tox_gh_actions/split_tox_gh_actions.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
TOXENV_REGEX = re.compile(
3030
r"""
31-
{?(?P<py_versions>(py\d+\.\d+,?)+)}?
31+
{?(?P<py_versions>(py\d+\.\d+t?,?)+)}?
3232
-(?P<framework>[a-z](?:[a-z_]|-(?!v{?\d))*[a-z0-9])
3333
(?:-(
3434
(v{?(?P<framework_versions>[0-9.]+[0-9a-z,.]*}?))
@@ -250,11 +250,19 @@ def find_frameworks_missing_from_groups(py_versions):
250250
return all_frameworks - frameworks_in_a_group
251251

252252

253+
def _version_key(v):
254+
major_version, minor_version_and_suffix = v.split(".")
255+
if minor_version_and_suffix.endswith("t"):
256+
return int(major_version), int(minor_version_and_suffix.rstrip("t")), 1
257+
258+
return int(major_version), int(minor_version_and_suffix), 0
259+
260+
253261
def _normalize_py_versions(py_versions):
254262
def replace_and_sort(versions):
255263
return sorted(
256264
[py.replace("py", "") for py in versions],
257-
key=lambda v: tuple(map(int, v.split("."))),
265+
key=_version_key,
258266
)
259267

260268
if isinstance(py_versions, dict):

tests/integrations/threading/test_threading.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import gc
2+
import sys
23
from concurrent import futures
34
from textwrap import dedent
45
from threading import Thread
@@ -68,7 +69,8 @@ def stage2():
6869
assert exception["mechanism"]["type"] == "threading"
6970
assert not exception["mechanism"]["handled"]
7071

71-
if propagate_hub:
72+
# Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False
73+
if propagate_hub or getattr(sys.flags, "thread_inherit_context", None):
7274
assert event["tags"]["stage1"] == "true"
7375
else:
7476
assert "stage1" not in event.get("tags", {})
@@ -94,7 +96,8 @@ def double(number):
9496

9597
sentry_sdk.flush()
9698

97-
if propagate_hub:
99+
# Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False
100+
if propagate_hub or getattr(sys.flags, "thread_inherit_context", None):
98101
assert len(events) == 1
99102
(event,) = events
100103
assert event["spans"][0]["trace_id"] == event["spans"][1]["trace_id"]
@@ -248,7 +251,9 @@ def do_some_work(number):
248251
t.join()
249252

250253
(event,) = events
251-
if propagate_scope:
254+
255+
# Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False
256+
if propagate_scope or getattr(sys.flags, "thread_inherit_context", None):
252257
assert render_span_tree(event) == dedent(
253258
"""\
254259
- op="outer-trx": description=null
@@ -309,7 +314,8 @@ def do_some_work(number):
309314

310315
(event,) = events
311316

312-
if propagate_scope:
317+
# Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False
318+
if propagate_scope or getattr(sys.flags, "thread_inherit_context", None):
313319
assert render_span_tree(event) == dedent(
314320
"""\
315321
- op="outer-trx": description=null

tox.ini

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ requires =
1818
virtualenv<20.26.3
1919
envlist =
2020
# === Common ===
21-
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}-common
21+
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t}-common
2222

2323
# === Gevent ===
2424
{py3.6,py3.8,py3.10,py3.11,py3.12}-gevent
2525

2626
# === Integrations ===
2727

2828
# Asgi
29-
{py3.7,py3.12,py3.13,py3.14}-asgi
29+
{py3.7,py3.12,py3.13,py3.14,py3.14t}-asgi
3030

3131
# AWS Lambda
3232
{py3.8,py3.9,py3.11,py3.13}-aws_lambda
@@ -38,7 +38,7 @@ envlist =
3838
{py3.7}-gcp
3939

4040
# OpenTelemetry (OTel)
41-
{py3.7,py3.9,py3.12,py3.13,py3.14}-opentelemetry
41+
{py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-opentelemetry
4242

4343
# OpenTelemetry Experimental (POTel)
4444
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel
@@ -303,7 +303,7 @@ deps =
303303
# and https://github.com/pytest-dev/pytest-forked/issues/67
304304
# for justification of the upper bound on pytest
305305
{py3.6,py3.7}-common: pytest<7.0.0
306-
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}-common: pytest
306+
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t}-common: pytest
307307

308308
# === Gevent ===
309309
{py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0
@@ -728,6 +728,9 @@ setenv =
728728
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
729729
COVERAGE_FILE=.coverage-sentry-{envname}
730730
py3.6: COVERAGE_RCFILE=.coveragerc36
731+
# Lowest version to support free-threading
732+
# https://discuss.python.org/t/announcement-pip-24-1-release/56281
733+
py3.14t: VIRTUALENV_PIP=24.1
731734

732735
django: DJANGO_SETTINGS_MODULE=tests.integrations.django.myapp.settings
733736
spark-v{3.0.3,3.5.6}: JAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64
@@ -824,6 +827,7 @@ basepython =
824827
py3.12: python3.12
825828
py3.13: python3.13
826829
py3.14: python3.14
830+
py3.14t: python3.14t
827831

828832
# Python version is pinned here for consistency across environments.
829833
# Tools like ruff and mypy have options that pin the target Python

0 commit comments

Comments
 (0)