Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
fail-fast: false
matrix:
env:
- "3.15"
- "3.15t"
- "3.14"
- "3.13"
- "3.12"
Expand Down
1 change: 1 addition & 0 deletions docs/changelog/104.packaging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Declare support for Python 3.15 and run the test suite against it, currently in beta.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Software Development :: Libraries",
"Topic :: Utilities",
Expand Down Expand Up @@ -145,7 +146,7 @@ write-changes = true
count = true

[tool.pyproject-fmt]
max_supported_python = "3.14"
max_supported_python = "3.15"

[tool.ty]
src.exclude = [ "tests/windows/winreg_mock_values.py" ]
Expand Down
3 changes: 2 additions & 1 deletion tests/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ def reject_first(info: PythonInfo) -> bool:
proposed.append(str(info.executable))
return len(proposed) > 1

result = get_interpreter([f"{major}.{minor}", sys.executable], [], session_cache, predicate=reject_first)
threaded = "t" if current.free_threaded else ""
result = get_interpreter([f"{major}.{minor}{threaded}", sys.executable], [], session_cache, predicate=reject_first)
# rejecting the first proposal must not abort discovery; a later proposal (same or fallback spec) is accepted -
# on hosts where every alias resolves to one interpreter the fallback re-proposes it, so executables may match
assert result is not None
Expand Down
5 changes: 4 additions & 1 deletion tests/test_py_info_extra.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,10 @@ def test_satisfies_version_specifier_prerelease(version_info: VersionInfo, spec_

def test_satisfies_path_not_abs_basename_match() -> None:
info = copy.deepcopy(CURRENT)
basename = Path(info.original_executable).stem
# stem drops everything from the first dot, so python3.15t arrives as python3 and stops naming a free-threaded
# build; only the Windows .exe belongs off the end.
name = Path(info.original_executable).name
basename = name[: -len(".exe")] if name.endswith(".exe") else name
spec = PythonSpec.from_string_spec(basename)
assert info.satisfies(spec, impl_must_match=False) is True

Expand Down
2 changes: 1 addition & 1 deletion tox.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
requires = ["tox>=4.38", "tox-uv>=1.29"]
env_list = ["fix", "3.14", "3.13", "3.12", "3.11", "3.10", "3.9", "3.8", "type-3.8", "type-3.14", "docs", "pkg_meta"]
env_list = ["fix", "3.15", "3.15t", "3.14", "3.13", "3.12", "3.11", "3.10", "3.9", "3.8", "type-3.8", "type-3.14", "docs", "pkg_meta"]
skip_missing_interpreters = true

[env_run_base]
Expand Down