Skip to content

Commit dac3196

Browse files
committed
Add 3.14 support and drop 3.9
Signed-off-by: Bernát Gábor <[email protected]>
1 parent 1f28422 commit dac3196

File tree

92 files changed

+418
-302
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+418
-302
lines changed

.github/workflows/check.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ jobs:
2828
- "3.12"
2929
- "3.11"
3030
- "3.10"
31-
- "3.9"
3231
os:
3332
- ubuntu-24.04
3433
- windows-2025
@@ -89,7 +88,7 @@ jobs:
8988
shell: bash
9089
run: echo "$USERPROFILE/.local/bin" >> $GITHUB_PATH
9190
- name: Install tox@self
92-
run: uv tool install --python-preference only-managed --python 3.13 tox@.
91+
run: uv tool install --python-preference only-managed --python 3.14 tox@.
9392
- name: Setup check suite
9493
run: tox r -vv --notest --skip-missing-interpreters false -e ${{ matrix.tox_env }}
9594
- name: Run check for ${{ matrix.tox_env }}

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
cache-dependency-glob: "pyproject.toml"
2222
github-token: ${{ secrets.GITHUB_TOKEN }}
2323
- name: Build package
24-
run: uv build --python 3.13 --python-preference only-managed --sdist --wheel . --out-dir dist
24+
run: uv build --python 3.14 --python-preference only-managed --sdist --wheel . --out-dir dist
2525
- name: Store the distribution packages
2626
uses: actions/upload-artifact@v4
2727
with:

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ repos:
1313
rev: v2.4.1
1414
hooks:
1515
- id: codespell
16-
additional_dependencies: ["tomli>=2.2.1"]
16+
additional_dependencies: ["tomli>=2.3"]
1717
- repo: https://github.com/tox-dev/pyproject-fmt
18-
rev: "v2.6.0"
18+
rev: "v2.8.0"
1919
hooks:
2020
- id: pyproject-fmt
2121
- repo: https://github.com/abravalheri/validate-pyproject
2222
rev: "v0.24.1"
2323
hooks:
2424
- id: validate-pyproject
2525
- repo: https://github.com/astral-sh/ruff-pre-commit
26-
rev: "v0.13.2"
26+
rev: "v0.14.0"
2727
hooks:
2828
- id: ruff-check
2929
args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"]
@@ -32,7 +32,7 @@ repos:
3232
rev: 1.20.0
3333
hooks:
3434
- id: blacken-docs
35-
additional_dependencies: [black==25.1]
35+
additional_dependencies: [black==25.9]
3636
- repo: https://github.com/pre-commit/pygrep-hooks
3737
rev: v1.10.0
3838
hooks:

.readthedocs.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ build:
55
python: "3"
66
commands:
77
- pip install uv
8-
- uv venv
8+
- uv venv -p 3.14
99
- uv pip install tox-uv tox@.
10-
- .venv/bin/tox run -e docs --
10+
- .venv/bin/tox run -e docs --notest
11+
- .venv/bin/tox run -e docs --skip-pkg-install --

docs/installation.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Installation
44
As tool
55
-------
66

7-
:pypi:`tox` is a CLI tool that needs a Python interpreter (version 3.9 or higher) to run. We recommend either
7+
:pypi:`tox` is a CLI tool that needs a Python interpreter (version 3.10 or higher) to run. We recommend either
88
:pypi:`pipx` or :pypi:`uv` to install tox into an isolated environment. This has the added benefit that later you'll
99
be able to upgrade tox without affecting other parts of the system. We provide method for ``pip`` too here but we
1010
discourage that path if you can:
@@ -80,7 +80,7 @@ Python and OS Compatibility
8080

8181
tox works with the following Python interpreter implementations:
8282

83-
- `CPython <https://www.python.org/>`_ versions 3.9, 3.10, 3.11, 3.12, 3.13
83+
- `CPython <https://www.python.org/>`_ versions 3.10, 3.11, 3.12, 3.13, 3.14
8484

8585
This means tox works on the latest patch version of each of these minor versions. Previous patch versions are supported
8686
on a best effort approach.

pyproject.toml

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ maintainers = [
2626
authors = [
2727
{ name = "Bernát Gábor", email = "[email protected]" },
2828
]
29-
requires-python = ">=3.9"
29+
requires-python = ">=3.10"
3030
classifiers = [
3131
"Development Status :: 5 - Production/Stable",
3232
"Framework :: tox",
@@ -36,7 +36,6 @@ classifiers = [
3636
"Operating System :: Microsoft :: Windows",
3737
"Operating System :: POSIX",
3838
"Programming Language :: Python :: 3 :: Only",
39-
"Programming Language :: Python :: 3.9",
4039
"Programming Language :: Python :: 3.10",
4140
"Programming Language :: Python :: 3.11",
4241
"Programming Language :: Python :: 3.12",
@@ -50,17 +49,17 @@ dynamic = [
5049
"version",
5150
]
5251
dependencies = [
53-
"cachetools>=6.1",
52+
"cachetools>=6.2",
5453
"chardet>=5.2",
5554
"colorama>=0.4.6",
56-
"filelock>=3.18",
55+
"filelock>=3.19.1",
5756
"packaging>=25",
58-
"platformdirs>=4.3.8",
57+
"platformdirs>=4.5",
5958
"pluggy>=1.6",
6059
"pyproject-api>=1.9.1",
61-
"tomli>=2.2.1; python_version<'3.11'",
62-
"typing-extensions>=4.14.1; python_version<'3.11'",
63-
"virtualenv>=20.31.2",
60+
"tomli>=2.3; python_version<'3.11'",
61+
"typing-extensions>=4.15; python_version<'3.11'",
62+
"virtualenv>=20.35",
6463
]
6564
urls.Documentation = "https://tox.wiki"
6665
urls.Homepage = "http://tox.readthedocs.org"
@@ -76,55 +75,55 @@ dev = [
7675
{ include-group = "type" },
7776
]
7877
test = [
79-
"build[virtualenv]>=1.2.2.post1",
78+
"build[virtualenv]>=1.3",
8079
"covdefaults>=2.3",
81-
"coverage>=7.9.2",
80+
"coverage>=7.10.7",
8281
"detect-test-pollution>=1.2",
8382
"devpi-process>=1.0.2",
84-
"diff-cover>=9.6",
83+
"diff-cover>=9.7.1",
8584
"distlib>=0.4",
8685
"flaky>=3.8.1",
8786
"hatch-vcs>=0.5",
8887
"hatchling>=1.27",
89-
"pdm-backend",
90-
"psutil>=7",
91-
"pytest>=8.4.1",
92-
"pytest-cov>=6.2.1",
93-
"pytest-mock>=3.14.1",
88+
"pdm-backend>=2.4.5",
89+
"psutil>=7.1",
90+
"pytest>=8.4.2",
91+
"pytest-cov>=7",
92+
"pytest-mock>=3.15.1",
9493
"pytest-xdist>=3.8",
9594
"re-assert>=1.1",
9695
"setuptools>=80.9",
97-
"time-machine>=2.16; implementation_name!='pypy'",
96+
"time-machine>=2.19; implementation_name!='pypy'",
9897
"wheel>=0.45.1",
9998
]
10099
type = [
101-
"mypy==1.17",
102-
"types-cachetools>=6.1.0.20250717",
100+
"mypy==1.18.2",
101+
"types-cachetools>=6.2.0.20250827",
103102
"types-chardet>=5.0.4.6",
104103
{ include-group = "test" },
105104
]
106105
docs = [
107-
"furo>=2025.7.19",
106+
"furo>=2025.9.25",
108107
"sphinx>=8.2.3",
109-
"sphinx-argparse-cli>=1.19",
110-
"sphinx-autodoc-typehints>=3.2",
108+
"sphinx-argparse-cli>=1.20.1",
109+
"sphinx-autodoc-typehints>=3.4",
111110
"sphinx-copybutton>=0.5.2",
112111
"sphinx-inline-tabs>=2023.4.21",
113112
"sphinxcontrib-towncrier>=0.2.1a0",
114-
"towncrier>=24.8",
113+
"towncrier>=25.8",
115114
]
116115
fix = [
117-
"pre-commit-uv>=4.1.4",
116+
"pre-commit-uv>=4.1.5",
118117
]
119118
pkg-meta = [
120-
"check-wheel-contents>=0.6.2",
121-
"twine>=6.1",
122-
"uv>=0.8",
119+
"check-wheel-contents>=0.6.3",
120+
"twine>=6.2",
121+
"uv>=0.9",
123122
]
124123
release = [
125-
"gitpython>=3.1.44",
124+
"gitpython>=3.1.45",
126125
"packaging>=25",
127-
"towncrier>=24.8",
126+
"towncrier>=25.8",
128127
]
129128

130129
[tool.hatch]
@@ -140,7 +139,6 @@ build.targets.sdist.include = [
140139
version.source = "vcs"
141140

142141
[tool.ruff]
143-
target-version = "py38"
144142
line-length = 120
145143
format.preview = true
146144
format.docstring-code-line-length = 100

src/tox/config/cli/env_var.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import logging
66
import os
7-
from typing import Any, List
7+
from typing import Any
88

99
from tox.config.loader.str_convert import StrConvert
1010

@@ -25,7 +25,7 @@ def get_env_var(key: str, of_type: type[Any]) -> tuple[Any, str] | None:
2525
value = os.environ[environ_key]
2626
origin = getattr(of_type, "__origin__", of_type.__class__)
2727
try:
28-
if origin in {list, List}:
28+
if origin in {list, list}:
2929
entry_type = of_type.__args__[0]
3030
result = [CONVERT.to(raw=v, of_type=entry_type, factory=None) for v in value.split(";")]
3131
else:

src/tox/config/cli/parse.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
import os
77
from contextlib import redirect_stderr
88
from pathlib import Path
9-
from typing import TYPE_CHECKING, Callable, NamedTuple, Sequence, cast
9+
from typing import TYPE_CHECKING, NamedTuple, cast
1010

1111
from tox.config.source import Source, discover_source
1212
from tox.report import ToxHandler, setup_report
1313

1414
from .parser import Parsed, ToxParser
1515

1616
if TYPE_CHECKING:
17+
from collections.abc import Callable, Sequence
18+
1719
from tox.session.state import State
1820

1921

@@ -47,9 +49,10 @@ def _get_base(args: Sequence[str]) -> tuple[int, ToxHandler, Source]:
4749
tox_parser = ToxParser.base()
4850
parsed = Parsed()
4951
try:
50-
with Path(os.devnull).open(
51-
"w", encoding=locale.getpreferredencoding(do_setlocale=False)
52-
) as file_handler, redirect_stderr(file_handler):
52+
with (
53+
Path(os.devnull).open("w", encoding=locale.getpreferredencoding(do_setlocale=False)) as file_handler,
54+
redirect_stderr(file_handler),
55+
):
5356
tox_parser.parse_known_args(args, namespace=parsed)
5457
except SystemExit:
5558
... # ignore parse errors, such as -va raises ignored explicit argument 'a'

src/tox/config/cli/parser.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import sys
1010
from argparse import SUPPRESS, Action, ArgumentDefaultsHelpFormatter, ArgumentError, ArgumentParser, Namespace
1111
from pathlib import Path
12-
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Type, TypeVar, cast
12+
from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast
1313

1414
from colorama import Fore
1515

@@ -26,6 +26,8 @@
2626
from typing_extensions import Self
2727

2828
if TYPE_CHECKING:
29+
from collections.abc import Callable, Sequence
30+
2931
from tox.session.state import State
3032

3133

@@ -64,7 +66,7 @@ def get_type(action: Action) -> type[Any]:
6466
of_type: type[Any] | None = getattr(action, "of_type", None)
6567
if of_type is None:
6668
if isinstance(action, argparse._AppendAction): # noqa: SLF001
67-
of_type = List[action.type] # type: ignore[name-defined]
69+
of_type = list[action.type] # type: ignore[name-defined]
6870
elif isinstance(action, argparse._StoreAction) and action.choices: # noqa: SLF001
6971
loc = locals()
7072
loc["Literal"] = Literal
@@ -135,7 +137,7 @@ def is_colored(self) -> bool:
135137
exit_and_dump_after: int
136138

137139

138-
ArgumentArgs = Tuple[Tuple[str, ...], Optional[Type[Any]], Dict[str, Any]]
140+
ArgumentArgs = tuple[tuple[str, ...], type[Any] | None, dict[str, Any]]
139141

140142

141143
class ToxParser(ArgumentParserWithEnvAndConfig):
@@ -230,7 +232,7 @@ def __call__(
230232
help="set PYTHONHASHSEED to SEED before running commands. Defaults to a random integer in the range "
231233
"[1, 4294967295] ([1, 1024] on Windows). Passing 'notset' suppresses this behavior.",
232234
action=SeedAction,
233-
of_type=Optional[int], # type: ignore[arg-type]
235+
of_type=int | None,
234236
default=hashseed_default,
235237
dest="hash_seed",
236238
)
@@ -239,7 +241,7 @@ def __call__(
239241
dest="discover",
240242
nargs="+",
241243
metavar="path",
242-
of_type=List[str],
244+
of_type=list[str],
243245
help="for Python discovery first try these Python executables",
244246
default=[],
245247
)
@@ -403,7 +405,7 @@ def add_core_arguments(parser: ArgumentParser) -> None:
403405
metavar="file",
404406
default=None,
405407
type=Path,
406-
of_type=Optional[Path],
408+
of_type=Path | None,
407409
help="configuration file/folder for tox (if not specified will discover one)",
408410
)
409411
parser.add_argument(
@@ -412,7 +414,7 @@ def add_core_arguments(parser: ArgumentParser) -> None:
412414
metavar="dir",
413415
default=None,
414416
type=Path,
415-
of_type=Optional[Path],
417+
of_type=Path | None,
416418
help="tox working directory (if not specified will be the folder of the config file)",
417419
)
418420
parser.add_argument(
@@ -421,7 +423,7 @@ def add_core_arguments(parser: ArgumentParser) -> None:
421423
metavar="dir",
422424
default=None,
423425
type=Path,
424-
of_type=Optional[Path],
426+
of_type=Path | None,
425427
help="project root directory (if not specified will be the folder of the config file)",
426428
)
427429

src/tox/config/loader/api.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
from abc import abstractmethod
44
from argparse import ArgumentTypeError
5-
from typing import TYPE_CHECKING, Any, List, Mapping, TypeVar
5+
from collections.abc import Mapping
6+
from typing import TYPE_CHECKING, Any, TypeVar
67

78
from tox.plugin import impl
89
from tox.tox_env.python.pip.req_file import PythonDeps
@@ -70,7 +71,7 @@ def copy(self) -> ConfigLoadArgs:
7071
return ConfigLoadArgs(self.chain.copy(), self.name, self.env_name)
7172

7273

73-
OverrideMap = Mapping[str, List[Override]]
74+
OverrideMap = Mapping[str, list[Override]]
7475

7576
T = TypeVar("T")
7677
V = TypeVar("V")

0 commit comments

Comments
 (0)