Skip to content

Commit bbea098

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

File tree

91 files changed

+416
-300
lines changed

Some content is hidden

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

91 files changed

+416
-300
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 --

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)