Skip to content

Commit ec0951c

Browse files
committed
Allow disabling plugins on a one-off
Signed-off-by: Bernát Gábor <[email protected]>
1 parent 57b5dc6 commit ec0951c

File tree

21 files changed

+171
-83
lines changed

21 files changed

+171
-83
lines changed

.github/workflows/check.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ jobs:
3030
- "3.10"
3131
- "3.9"
3232
os:
33-
- ubuntu-latest
34-
- windows-latest
35-
- macos-latest
33+
- ubuntu-24.04
34+
- windows-2025
35+
- macos-15
3636
steps:
3737
- uses: actions/checkout@v4
3838
with:
@@ -70,8 +70,8 @@ jobs:
7070
- docs
7171
- pkg_meta
7272
os:
73-
- ubuntu-latest
74-
- windows-latest
73+
- ubuntu-24.04
74+
- windows-2025
7575
exclude:
7676
- { os: windows-latest, tox_env: docs }
7777
steps:

.github/workflows/release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ env:
99

1010
jobs:
1111
build:
12-
runs-on: ubuntu-latest
12+
runs-on: ubuntu-24.04
1313
steps:
1414
- uses: actions/checkout@v4
1515
with:
@@ -31,7 +31,7 @@ jobs:
3131
release:
3232
needs:
3333
- build
34-
runs-on: ubuntu-latest
34+
runs-on: ubuntu-24.04
3535
environment:
3636
name: release
3737
url: https://pypi.org/project/tox/${{ github.ref_name }}

docs/changelog/3468.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow disabling tox plugins via the ``TOX_DISABLED_EXTERNAL_PLUGINS`` environment variable - by :user:`gaborbernat`.

docs/plugins.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ installed. For example:
2727
2828
For more information, refer to :ref:`the user guide <auto-provisioning>`.
2929

30+
Plugins can be disabled via the ``TOX_DISABLED_EXTERNAL_PLUGINS`` environment variable. This variable can be set to a
31+
comma separated list of plugin names, e.g.:
32+
33+
```bash
34+
env TOX_DISABLED_EXTERNAL_PLUGINS=tox-uv,tox-extra tox --version
35+
```
36+
3037
Developing your own plugin
3138
--------------------------
3239

pyproject.toml

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[build-system]
22
build-backend = "hatchling.build"
33
requires = [
4-
"hatch-vcs>=0.4",
4+
"hatch-vcs>=0.5",
55
"hatchling>=1.27",
66
]
77

@@ -50,22 +50,17 @@ dynamic = [
5050
"version",
5151
]
5252
dependencies = [
53-
"cachetools>=5.5.1",
53+
"cachetools>=6.1",
5454
"chardet>=5.2",
5555
"colorama>=0.4.6",
56-
"filelock>=3.16.1",
57-
"packaging>=24.2",
58-
"platformdirs>=4.3.6",
59-
"pluggy>=1.5",
60-
"pyproject-api>=1.8",
56+
"filelock>=3.18",
57+
"packaging>=25",
58+
"platformdirs>=4.3.8",
59+
"pluggy>=1.6",
60+
"pyproject-api>=1.9.1",
6161
"tomli>=2.2.1; python_version<'3.11'",
62-
"typing-extensions>=4.12.2; python_version<'3.11'",
63-
"virtualenv>=20.31",
64-
]
65-
optional-dependencies.test = [
66-
"devpi-process>=1.0.2",
67-
"pytest>=8.3.4",
68-
"pytest-mock>=3.14",
62+
"typing-extensions>=4.14.1; python_version<'3.11'",
63+
"virtualenv>=20.31.2",
6964
]
7065
urls.Documentation = "https://tox.wiki"
7166
urls.Homepage = "http://tox.readthedocs.org"
@@ -83,35 +78,35 @@ dev = [
8378
test = [
8479
"build[virtualenv]>=1.2.2.post1",
8580
"covdefaults>=2.3",
86-
"coverage>=7.9.1",
81+
"coverage>=7.9.2",
8782
"detect-test-pollution>=1.2",
8883
"devpi-process>=1.0.2",
89-
"diff-cover>=9.2",
90-
"distlib>=0.3.9",
84+
"diff-cover>=9.6",
85+
"distlib>=0.4",
9186
"flaky>=3.8.1",
92-
"hatch-vcs>=0.4",
87+
"hatch-vcs>=0.5",
9388
"hatchling>=1.27",
94-
"psutil>=6.1.1",
95-
"pytest>=8.3.4",
96-
"pytest-cov>=5",
97-
"pytest-mock>=3.14",
98-
"pytest-xdist>=3.6.1",
89+
"psutil>=7",
90+
"pytest>=8.4.1",
91+
"pytest-cov>=6.2.1",
92+
"pytest-mock>=3.14.1",
93+
"pytest-xdist>=3.8",
9994
"re-assert>=1.1",
100-
"setuptools>=75.8",
101-
"time-machine>=2.15; implementation_name!='pypy'",
95+
"setuptools>=80.9",
96+
"time-machine>=2.16; implementation_name!='pypy'",
10297
"wheel>=0.45.1",
10398
]
10499
type = [
105-
"mypy==1.15",
106-
"types-cachetools>=5.5.0.20240820",
100+
"mypy==1.17",
101+
"types-cachetools>=6.1.0.20250717",
107102
"types-chardet>=5.0.4.6",
108103
{ include-group = "test" },
109104
]
110105
docs = [
111-
"furo>=2024.8.6",
112-
"sphinx>=8.1.3",
106+
"furo>=2025.7.19",
107+
"sphinx>=8.2.3",
113108
"sphinx-argparse-cli>=1.19",
114-
"sphinx-autodoc-typehints>=3.0.1",
109+
"sphinx-autodoc-typehints>=3.2",
115110
"sphinx-copybutton>=0.5.2",
116111
"sphinx-inline-tabs>=2023.4.21",
117112
"sphinxcontrib-towncrier>=0.2.1a0",
@@ -121,13 +116,13 @@ fix = [
121116
"pre-commit-uv>=4.1.4",
122117
]
123118
pkg-meta = [
124-
"check-wheel-contents>=0.6.1",
119+
"check-wheel-contents>=0.6.2",
125120
"twine>=6.1",
126-
"uv>=0.5.29",
121+
"uv>=0.8",
127122
]
128123
release = [
129124
"gitpython>=3.1.44",
130-
"packaging>=24.2",
125+
"packaging>=25",
131126
"towncrier>=24.8",
132127
]
133128

@@ -201,8 +196,13 @@ max_supported_python = "3.14"
201196
testpaths = [
202197
"tests",
203198
]
204-
addopts = "--tb=auto -ra --showlocals --no-success-flaky-report"
205-
# Keep temporary directories only for failed or errored tests.
199+
addopts = "--no-success-flaky-report"
200+
verbosity_assertions = 2
201+
filterwarnings = [
202+
"error",
203+
"ignore:unclosed database in <sqlite3.Connection object at:ResourceWarning",
204+
"ignore:unclosed file <_io.TextIOWrapper:ResourceWarning",
205+
]
206206
tmp_path_retention_policy = "failed"
207207

208208
[tool.coverage]

src/tox/config/cli/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def add_argument_group(self, *args: Any, **kwargs: Any) -> Any:
263263

264264
def add_mutually_exclusive_group(**e_kwargs: Any) -> Any:
265265
def add_argument(*a_args: str, of_type: type[Any] | None = None, **a_kwargs: Any) -> Action:
266-
res_args: Action = prev_add_arg(*a_args, **a_kwargs) # type: ignore[has-type]
266+
res_args: Action = prev_add_arg(*a_args, **a_kwargs)
267267
arguments.append((a_args, of_type, a_kwargs))
268268
return res_args
269269

src/tox/config/loader/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,13 @@ def load(
151151
converted_override = _STR_CONVERT.to(override.value, of_type, factory)
152152
if override.append and converted is not None:
153153
if isinstance(converted, list) and isinstance(converted_override, list):
154-
converted += converted_override
154+
converted += converted_override # type: ignore[assignment]
155155
elif isinstance(converted, dict) and isinstance(converted_override, dict):
156156
converted.update(converted_override)
157157
elif isinstance(converted, SetEnv) and isinstance(converted_override, SetEnv):
158158
converted.update(converted_override, override=True)
159159
elif isinstance(converted, PythonDeps) and isinstance(converted_override, PythonDeps):
160-
converted += converted_override
160+
converted += converted_override # type: ignore[operator]
161161
else:
162162
msg = "Only able to append to lists and dicts"
163163
raise ValueError(msg)

src/tox/config/loader/convert.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def to(self, raw: T, of_type: type[V], factory: Factory[V]) -> V: # noqa: PLR09
4747
return list(self.to_list(raw, of_type=of_type)) # type: ignore[return-value]
4848
if isinstance(raw, of_type): # already target type no need to transform it
4949
# do it this late to allow normalization - e.g. string strip
50-
return raw # type: ignore[no-any-return]
50+
return raw
5151
if factory:
5252
return factory(raw)
5353
return of_type(raw) # type: ignore[no-any-return]

src/tox/plugin/manager.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import os
56
from typing import TYPE_CHECKING, Any
67

78
import pluggy
@@ -49,7 +50,7 @@ def _register_plugins(self, inline: ModuleType | None) -> None:
4950

5051
if inline is not None:
5152
self.manager.register(inline)
52-
self.manager.load_setuptools_entrypoints(NAME)
53+
self._load_external_plugins()
5354
internal_plugins = (
5455
loader_api,
5556
provision,
@@ -74,6 +75,11 @@ def _register_plugins(self, inline: ModuleType | None) -> None:
7475
self.manager.register(state)
7576
self.manager.check_pending()
7677

78+
def _load_external_plugins(self) -> None:
79+
for name in os.environ.get("TOX_DISABLED_EXTERNAL_PLUGINS", "").split(","):
80+
self.manager.set_blocked(name)
81+
self.manager.load_setuptools_entrypoints(NAME)
82+
7783
def tox_add_option(self, parser: ToxParser) -> None:
7884
self.manager.hook.tox_add_option(parser=parser)
7985

src/tox/pytest.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ def _load_inline(path: Path) -> ModuleType | None: # register only on first run
8282
@contextmanager
8383
def check_os_environ() -> Iterator[None]:
8484
old = os.environ.copy()
85-
to_clean = {k: os.environ.pop(k, None) for k in (ENV_VAR_KEY, "TOX_WORK_DIR", "PYTHONPATH", "COV_CORE_CONTEXT")}
85+
to_clean = {
86+
k: os.environ.pop(k, None)
87+
for k in (ENV_VAR_KEY, "TOX_WORK_DIR", "PYTHONPATH", "COV_CORE_CONTEXT", "TOX_DISABLED_EXTERNAL_PLUGINS")
88+
}
8689

8790
yield
8891

@@ -93,6 +96,7 @@ def check_os_environ() -> Iterator[None]:
9396
new = os.environ
9497
extra = {k: new[k] for k in set(new) - set(old)}
9598
extra.pop("PLAT", None)
99+
extra.pop("TOX_DISABLED_EXTERNAL_PLUGINS", None)
96100
miss = {k: old[k] for k in set(old) - set(new)}
97101
diff = {
98102
f"{k} = {old[k]} vs {new[k]}" for k in set(old) & set(new) if old[k] != new[k] and not k.startswith("PYTEST_")

0 commit comments

Comments
 (0)