Skip to content

Commit 3d35511

Browse files
committed
Add support for free-threading Python builds
This change adds support for Python's free-threading builds (e.g., Python 3.14t) by detecting the Py_GIL_DISABLED configuration variable and appending a "t" suffix to version keys when running on a free-threading build. Changes include: - Updated plugin to check sysconfig.get_config_var("Py_GIL_DISABLED") - Added "t" suffix to version keys for free-threading builds - Updated documentation with example configuration - Added test case for free-threading Python version detection
1 parent 8deb697 commit 3d35511

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,22 @@ python =
174174
...
175175
```
176176

177+
_Added in 3.5.0_: To use a free-threaded Python build, add the `t` suffix.
178+
179+
`tox.ini`:
180+
```ini
181+
[tox]
182+
envlist = py314, py314t
183+
184+
[gh-actions]
185+
python =
186+
3.14: py314
187+
3.14t: py314t
188+
189+
[testenv]
190+
...
191+
```
192+
177193
PyPy is also supported in the `python` configuration key.
178194
Support of Pyston is experimental and not tested by our CI.
179195

src/tox_gh_actions/plugin.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from logging import getLogger
33
import os
44
import sys
5+
import sysconfig
56
from typing import Any, Dict, Iterable, List
67

78
from tox.config.cli.parser import Parsed
@@ -163,25 +164,27 @@ def get_python_version_keys() -> List[str]:
163164
164165
Examples:
165166
- CPython 3.8.z => [3.8, 3]
167+
- CPython 3.14.z free-threading build => [3.14t, 3t]
166168
- PyPy 3.6 (v7.3.z) => [pypy-3.6, pypy-3, pypy3]
167169
- Pyston based on Python CPython 3.8.8 (v2.2) => [pyston-3.8, pyston-3]
168170
169171
"""
170172
major_version = str(sys.version_info[0])
171173
major_minor_version = ".".join([str(i) for i in sys.version_info[:2]])
174+
suffix = "t" if sysconfig.get_config_var("Py_GIL_DISABLED") == 1 else ""
172175
if "PyPy" in sys.version:
173176
return [
174-
"pypy-" + major_minor_version,
175-
"pypy-" + major_version,
177+
"pypy-" + major_minor_version + suffix,
178+
"pypy-" + major_version + suffix,
176179
]
177180
elif hasattr(sys, "pyston_version_info"): # Pyston
178181
return [
179-
"pyston-" + major_minor_version,
180-
"pyston-" + major_version,
182+
"pyston-" + major_minor_version + suffix,
183+
"pyston-" + major_version + suffix,
181184
]
182185
else:
183186
# Assume this is running on CPython
184-
return [major_minor_version, major_version]
187+
return [major_minor_version + suffix, major_version + suffix]
185188

186189

187190
def is_running_on_actions() -> bool:

tests/test_plugin.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,29 +247,40 @@ def test_get_envlist_from_factors(
247247

248248

249249
@pytest.mark.parametrize(
250-
"version,info,expected",
250+
"version,info,gil,expected",
251251
[
252+
(
253+
"3.14.0 free-threading build (main, Oct 7 2025, 09:34:52)"
254+
" [Clang 17.0.0 (clang-1700.3.19.1)]",
255+
(3, 14, 0, "final", 0),
256+
1,
257+
["3.14t", "3t"],
258+
),
252259
(
253260
"3.8.1 (default, Jan 22 2020, 06:38:00) \n[GCC 9.2.0]",
254261
(3, 8, 1, "final", 0),
262+
0,
255263
["3.8", "3"],
256264
),
257265
(
258266
"3.6.9 (1608da62bfc7, Dec 23 2019, 10:50:04)\n"
259267
"[PyPy 7.3.0 with GCC 7.3.1 20180303 (Red Hat 7.3.1-5)]",
260268
(3, 6, 9, "final", 0),
269+
0,
261270
["pypy-3.6", "pypy-3"],
262271
),
263272
],
264273
)
265274
def test_get_version_keys(
266275
mocker: MockerFixture,
267276
version: str,
277+
gil: int,
268278
info: Tuple[int, int, int, str, int],
269279
expected: List[str],
270280
) -> None:
271281
mocker.patch("tox_gh_actions.plugin.sys.version", version)
272282
mocker.patch("tox_gh_actions.plugin.sys.version_info", info)
283+
mocker.patch("tox_gh_actions.plugin.sysconfig.get_config_var", return_value=gil)
273284
assert plugin.get_python_version_keys() == expected
274285

275286

0 commit comments

Comments
 (0)