diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 20ad76a..92f2550 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -19,6 +19,8 @@ jobs: fail-fast: false matrix: env: + - "3.15" + - "3.15t" - "3.14" - "3.13" - "3.12" diff --git a/docs/changelog/104.packaging.rst b/docs/changelog/104.packaging.rst new file mode 100644 index 0000000..3206810 --- /dev/null +++ b/docs/changelog/104.packaging.rst @@ -0,0 +1 @@ +Declare support for Python 3.15 and run the test suite against it, currently in beta. diff --git a/pyproject.toml b/pyproject.toml index bdfede7..f4a0b14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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", @@ -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" ] diff --git a/tests/test_discovery.py b/tests/test_discovery.py index 9ea5ab4..138650d 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -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 diff --git a/tests/test_py_info_extra.py b/tests/test_py_info_extra.py index 19b5685..6cdebf1 100644 --- a/tests/test_py_info_extra.py +++ b/tests/test_py_info_extra.py @@ -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 diff --git a/tox.toml b/tox.toml index 20f6da5..c90e125 100644 --- a/tox.toml +++ b/tox.toml @@ -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]