Skip to content

Commit dbeec44

Browse files
authored
Add tox_on_install and tox_env_teardown plugin hooks (#2687)
1 parent 2df6015 commit dbeec44

File tree

9 files changed

+66
-7
lines changed

9 files changed

+66
-7
lines changed

docs/changelog/2687.feature.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :meth:`tox_on_install <tox.plugin.spec.tox_on_install>` and
2+
:meth:`tox_env_teardown <tox.plugin.spec.tox_env_teardown>` plugin hooks - by :user:`gaborbernat`.

src/tox/plugin/manager.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from pathlib import Path
55
from types import ModuleType
6+
from typing import Any
67

78
import pluggy
89

@@ -76,6 +77,12 @@ def tox_before_run_commands(self, tox_env: ToxEnv) -> None:
7677
def tox_after_run_commands(self, tox_env: ToxEnv, exit_code: int, outcomes: list[Outcome]) -> None:
7778
self.manager.hook.tox_after_run_commands(tox_env=tox_env, exit_code=exit_code, outcomes=outcomes)
7879

80+
def tox_on_install(self, tox_env: ToxEnv, arguments: Any, section: str, of_type: str) -> None:
81+
self.manager.hook.tox_on_install(tox_env=tox_env, arguments=arguments, section=section, of_type=of_type)
82+
83+
def tox_env_teardown(self, tox_env: ToxEnv) -> None:
84+
self.manager.hook.tox_env_teardown(tox_env=tox_env)
85+
7986
def load_plugins(self, path: Path) -> None:
8087
for _plugin in self.manager.get_plugins(): # make sure we start with a clean state, repeated in memory run
8188
self.manager.unregister(_plugin)

src/tox/plugin/spec.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,27 @@ def tox_after_run_commands(tox_env: ToxEnv, exit_code: int, outcomes: list[Outco
8383
"""
8484

8585

86+
@_spec
87+
def tox_on_install(tox_env: ToxEnv, arguments: Any, section: str, of_type: str) -> None: # noqa: U100
88+
"""
89+
Called before executing an installation command.
90+
91+
:param tox_env: the tox environment where the command runs in
92+
:param arguments: installation arguments
93+
:param section: section of the installation
94+
:param of_type: type of the installation
95+
"""
96+
97+
98+
@_spec
99+
def tox_env_teardown(tox_env: ToxEnv) -> None: # noqa: U100
100+
"""
101+
Called before executing an installation command.
102+
103+
:param tox_env: the tox environment
104+
"""
105+
106+
86107
__all__ = [
87108
"NAME",
88109
"tox_register_tox_env",
@@ -91,4 +112,6 @@ def tox_after_run_commands(tox_env: ToxEnv, exit_code: int, outcomes: list[Outco
91112
"tox_add_env_config",
92113
"tox_before_run_commands",
93114
"tox_after_run_commands",
115+
"tox_on_install",
116+
"tox_env_teardown",
94117
]

src/tox/tox_env/api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ def executor(self) -> Execute:
8989
def installer(self) -> Installer[Any]:
9090
raise NotImplementedError
9191

92+
def _install(self, arguments: Any, section: str, of_type: str) -> None:
93+
from tox.plugin.manager import MANAGER
94+
95+
MANAGER.tox_on_install(self, arguments, section, of_type)
96+
self.installer.install(arguments, section, of_type)
97+
9298
def __repr__(self) -> str:
9399
return f"{self.__class__.__name__}(name={self.conf['env_name']})"
94100

@@ -251,6 +257,9 @@ def teardown(self) -> None:
251257
try:
252258
self._teardown()
253259
finally:
260+
from tox.plugin.manager import MANAGER
261+
262+
MANAGER.tox_env_teardown(self)
254263
self._run_state["teardown"] = True
255264

256265
def _teardown(self) -> None: # noqa: B027 # empty abstract base class

src/tox/tox_env/python/package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def __init__(self, create_args: ToxEnvCreateArgs) -> None:
5555
def _setup_env(self) -> None:
5656
"""setup the tox environment"""
5757
super()._setup_env()
58-
self.installer.install(self.requires(), PythonPackageToxEnv.__name__, "requires")
58+
self._install(self.requires(), PythonPackageToxEnv.__name__, "requires")
5959

6060
@abstractmethod
6161
def requires(self) -> tuple[Requirement, ...] | PythonDeps:

src/tox/tox_env/python/runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def _setup_env(self) -> None:
100100

101101
def _install_deps(self) -> None:
102102
requirements_file: PythonDeps = self.conf["deps"]
103-
self.installer.install(requirements_file, PythonRun.__name__, "deps")
103+
self._install(requirements_file, PythonRun.__name__, "deps")
104104

105105
def _build_packages(self) -> list[Package]:
106106
package_env = self.package_env

src/tox/tox_env/python/virtual_env/package/pyproject.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ def _setup_env(self) -> None:
148148
if not self._frontend.optional_hooks["build_editable"]:
149149
raise BuildEditableNotSupported
150150
build_requires = self._frontend.get_requires_for_build_editable().requires
151-
self.installer.install(build_requires, PythonPackageToxEnv.__name__, "requires_for_build_editable")
151+
self._install(build_requires, PythonPackageToxEnv.__name__, "requires_for_build_editable")
152152
if "wheel" in self.builds:
153153
build_requires = self._frontend.get_requires_for_build_wheel().requires
154-
self.installer.install(build_requires, PythonPackageToxEnv.__name__, "requires_for_build_wheel")
154+
self._install(build_requires, PythonPackageToxEnv.__name__, "requires_for_build_wheel")
155155
if "sdist" in self.builds or "external" in self.builds:
156156
build_requires = self._frontend.get_requires_for_build_sdist().requires
157-
self.installer.install(build_requires, PythonPackageToxEnv.__name__, "requires_for_build_sdist")
157+
self._install(build_requires, PythonPackageToxEnv.__name__, "requires_for_build_sdist")
158158

159159
def _teardown(self) -> None:
160160
executor = self._frontend.backend_executor

src/tox/tox_env/runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def _register_package_conf(self) -> bool:
170170

171171
def _setup_pkg(self) -> None:
172172
self._packages = self._build_packages()
173-
self.installer.install(self._packages, RunToxEnv.__name__, "package")
173+
self._install(self._packages, RunToxEnv.__name__, "package")
174174
self._handle_journal_package(self.journal, self._packages)
175175

176176
@staticmethod

tests/plugin/test_plugin.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import os
55
import sys
6+
from typing import Any
67
from unittest.mock import patch
78

89
import pytest
@@ -47,6 +48,14 @@ def tox_before_run_commands(tox_env: ToxEnv) -> None:
4748
assert isinstance(tox_env, ToxEnv)
4849
logging.warning("tox_before_run_commands")
4950

51+
@impl
52+
def tox_on_install(tox_env: ToxEnv, arguments: Any, section: str, of_type: str) -> None:
53+
assert isinstance(tox_env, ToxEnv)
54+
assert arguments is not None
55+
assert isinstance(section, str)
56+
assert isinstance(of_type, str)
57+
logging.warning(f"tox_on_install {section} {of_type}")
58+
5059
@impl
5160
def tox_after_run_commands(tox_env: ToxEnv, exit_code: int, outcomes: list[Outcome]) -> None:
5261
assert isinstance(tox_env, ToxEnv)
@@ -55,8 +64,13 @@ def tox_after_run_commands(tox_env: ToxEnv, exit_code: int, outcomes: list[Outco
5564
assert all(isinstance(i, Outcome) for i in outcomes)
5665
logging.warning("tox_after_run_commands")
5766

67+
@impl
68+
def tox_env_teardown(tox_env: ToxEnv) -> None:
69+
assert isinstance(tox_env, ToxEnv)
70+
logging.warning("teardown")
71+
5872
plugins = tuple(v for v in locals().values() if callable(v) and hasattr(v, "tox_impl"))
59-
assert len(plugins) == 6
73+
assert len(plugins) == 8
6074
register_inline_plugin(mocker, *plugins)
6175
project = tox_project({"tox.ini": "[testenv]\npackage=skip\ncommands=python -c 'print(1)'"})
6276
result = project.run("r", "-e", "a,b")
@@ -68,15 +82,19 @@ def tox_after_run_commands(tox_env: ToxEnv, exit_code: int, outcomes: list[Outco
6882
"ROOT: tox_add_core_config",
6983
"a: tox_add_env_config",
7084
"b: tox_add_env_config",
85+
"a: tox_on_install PythonRun deps",
7186
"a: tox_before_run_commands",
7287
f"a: commands[0]> python -c {cmd}",
7388
mocker.ANY, # output a
7489
"a: tox_after_run_commands",
90+
"a: teardown",
7591
mocker.ANY, # report finished A
92+
"b: tox_on_install PythonRun deps",
7693
"b: tox_before_run_commands",
7794
f"b: commands[0]> python -c {cmd}",
7895
mocker.ANY, # output b
7996
"b: tox_after_run_commands",
97+
"b: teardown",
8098
mocker.ANY, # report a
8199
mocker.ANY, # report b
82100
mocker.ANY, # overall report

0 commit comments

Comments
 (0)