From 52cbe9a9c717c94e80f345cc76095a19cfdd3558 Mon Sep 17 00:00:00 2001 From: Teejay Date: Wed, 5 Apr 2023 09:51:24 -0700 Subject: Fix `tox_root` propagation to `work_dir` (#2962) Co-authored-by: kdestin <101366538+kdestin@users.noreply.github.com> Co-authored-by: TJ Bruno --- docs/changelog/2933.bugfix.rst | 1 + src/tox/config/sets.py | 21 ++++---- tests/session/cmd/test_sequential.py | 4 +- tests/test_run.py | 78 ++++++++++++++++++++++++++++-- tests/tox_env/python/test_python_runner.py | 11 ++++- 5 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 docs/changelog/2933.bugfix.rst diff --git a/docs/changelog/2933.bugfix.rst b/docs/changelog/2933.bugfix.rst new file mode 100644 index 00000000..fe91a704 --- /dev/null +++ b/docs/changelog/2933.bugfix.rst @@ -0,0 +1 @@ +Fix issue where ``work_dir`` was not correctly including ``tox_root`` for test runs. diff --git a/src/tox/config/sets.py b/src/tox/config/sets.py index 98a31251..f75aca37 100644 --- a/src/tox/config/sets.py +++ b/src/tox/config/sets.py @@ -179,6 +179,15 @@ class CoreConfigSet(ConfigSet): desc = "define environments to automatically run" self.add_config(keys=["env_list", "envlist"], of_type=EnvList, default=EnvList([]), desc=desc) + def _default_work_dir(self, conf: Config, env_name: str | None) -> Path: # noqa: U100 + return cast(Path, self["tox_root"] / ".tox") + + def _default_temp_dir(self, conf: Config, env_name: str | None) -> Path: # noqa: U100 + return cast(Path, self["work_dir"] / ".tmp") + + def _work_dir_post_process(self, dir: Path) -> Path: + return self._conf.work_dir if self._conf.options.work_dir else dir + def register_config(self) -> None: self.add_constant(keys=["config_file_path"], desc="path to the configuration file", value=self._src_path) self.add_config( @@ -188,23 +197,17 @@ class CoreConfigSet(ConfigSet): desc="the root directory (where the configuration file is found)", ) - def work_dir_builder(conf: Config, env_name: str | None) -> Path: # noqa: U100 - return (conf.work_dir if conf.work_dir is not None else cast(Path, self["tox_root"])) / ".tox" - - def work_dir_post_process(value: Path) -> Path: - return self._conf.work_dir if self._conf.options.work_dir else value - self.add_config( keys=["work_dir", "toxworkdir"], of_type=Path, - default=work_dir_builder, - post_process=work_dir_post_process, + default=self._default_work_dir, + post_process=self._work_dir_post_process, desc="working directory", ) self.add_config( keys=["temp_dir"], of_type=Path, - default=lambda conf, _: cast(Path, self["work_dir"]) / ".tmp", # noqa: U100, U101 + default=self._default_temp_dir, desc="a folder for temporary files (is not cleaned at start)", ) self.add_constant("host_python", "the host python executable path", sys.executable) diff --git a/tests/session/cmd/test_sequential.py b/tests/session/cmd/test_sequential.py index 8672234a..f3bd9231 100644 --- a/tests/session/cmd/test_sequential.py +++ b/tests/session/cmd/test_sequential.py @@ -280,7 +280,7 @@ def test_skip_pkg_install(tox_project: ToxProjectCreator, demo_pkg_inline: Path) def test_skip_develop_mode(tox_project: ToxProjectCreator, demo_pkg_setuptools: Path) -> None: proj = tox_project({"tox.ini": "[testenv]\npackage=wheel\n"}) execute_calls = proj.patch_execute(lambda r: 0 if "install" in r.run_id else None) - result = proj.run("--root", str(demo_pkg_setuptools), "--develop") + result = proj.run("--root", str(demo_pkg_setuptools), "--develop", "--workdir", str(proj.path / ".tox")) result.assert_success() calls = [(i[0][0].conf.name, i[0][3].run_id) for i in execute_calls.call_args_list] expected = [ @@ -430,7 +430,7 @@ def test_sequential_inserted_env_vars(tox_project: ToxProjectCreator, demo_pkg_i k.startswith("TOX_") or k == "VIRTUAL_ENV"]' """ project = tox_project({"tox.ini": ini}) - result = project.run("r", "--root", str(demo_pkg_inline)) + result = project.run("r", "--root", str(demo_pkg_inline), "--workdir", str(project.path / ".tox")) result.assert_success() assert re.search(f"TOX_PACKAGE={re.escape(str(project.path))}.*.tar.gz{os.linesep}", result.out) diff --git a/tests/test_run.py b/tests/test_run.py index ca36f41f..bcb2be34 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pathlib import Path + import pytest from pytest_mock import MockerFixture @@ -22,7 +24,77 @@ def test_re_raises_on_unexpected_exit(mocker: MockerFixture) -> None: run() -def test_custom_work_dir(tox_project: ToxProjectCreator) -> None: +def test_custom_work_dir(tox_project: ToxProjectCreator, tmp_path: Path) -> None: + project = tox_project({}) + + expected_tox_root = project.path + expected_work_dir = tmp_path + + outcome = project.run("c", "--workdir", str(expected_work_dir)) + outcome.assert_success() + + assert outcome.state.conf.options.work_dir == expected_work_dir, "should parse the --workdir argument" + + assert outcome.state.conf.core["work_dir"], f"should set work_dir to {expected_work_dir}" + + assert outcome.state.conf.core["tox_root"] == expected_tox_root, "should not update the value of tox_root" + assert outcome.state.conf.core["work_dir"] != ( + expected_tox_root / ".tox" + ), "should explicitly demonstrate that tox_root and work_dir are decoupled" + + # should update config values that depend on work_dir + assert outcome.state.conf.core["temp_dir"] == expected_work_dir / ".tmp" + + env_conf = outcome.state.conf.get_env("py") + + assert env_conf["env_dir"] == expected_work_dir / "py" + assert env_conf["env_log_dir"] == expected_work_dir / "py" / "log" + assert env_conf["env_tmp_dir"] == expected_work_dir / "py" / "tmp" + + +def test_custom_root_dir(tox_project: ToxProjectCreator, tmp_path: Path) -> None: + project = tox_project({}) + + expected_tox_root = tmp_path + expected_work_dir = expected_tox_root / ".tox" + + outcome = project.run("c", "--root", str(expected_tox_root)) + outcome.assert_success() + + assert outcome.state.conf.options.root_dir == expected_tox_root, "should parse the --root argument" + + assert outcome.state.conf.core["tox_root"] == expected_tox_root, f"should set tox_root to {expected_tox_root}" + + # values that depend on tox_root should also be updated + + assert outcome.state.conf.core["work_dir"] == expected_work_dir + assert outcome.state.conf.core["temp_dir"] == expected_work_dir / ".tmp" + + env_conf = outcome.state.conf.get_env("py") + + assert env_conf["env_dir"] == expected_work_dir / "py" + assert env_conf["env_log_dir"] == expected_work_dir / "py" / "log" + assert env_conf["env_tmp_dir"] == expected_work_dir / "py" / "tmp" + + +def test_custom_root_dir_and_work_dir(tox_project: ToxProjectCreator, tmp_path: Path) -> None: project = tox_project({}) - outcome = project.run("c", "--workdir", str(project.path.parent)) - assert outcome.state.conf.options.work_dir == project.path.parent + + expected_tox_root = tmp_path / "tox_root" + expected_work_dir = tmp_path / "work_dir" + + outcome = project.run("c", "--root", str(expected_tox_root), "--workdir", str(expected_work_dir)) + outcome.assert_success() + + assert outcome.state.conf.core["tox_root"] == expected_tox_root, f"should set tox_root to {expected_tox_root}" + assert outcome.state.conf.core["work_dir"] == expected_work_dir, f"should set work_dir to {expected_work_dir}" + + # values that depend on work_dir should also be updated + + assert outcome.state.conf.core["temp_dir"] == expected_work_dir / ".tmp" + + env_conf = outcome.state.conf.get_env("py") + + assert env_conf["env_dir"] == expected_work_dir / "py" + assert env_conf["env_log_dir"] == expected_work_dir / "py" / "log" + assert env_conf["env_tmp_dir"] == expected_work_dir / "py" / "tmp" diff --git a/tests/tox_env/python/test_python_runner.py b/tests/tox_env/python/test_python_runner.py index 33de626a..3b8af5cc 100644 --- a/tests/tox_env/python/test_python_runner.py +++ b/tests/tox_env/python/test_python_runner.py @@ -95,7 +95,16 @@ def test_journal_package_dir(tmp_path: Path) -> None: def test_package_temp_dir_view(tox_project: ToxProjectCreator, demo_pkg_inline: Path) -> None: project = tox_project({"tox.ini": "[testenv]\npackage=wheel"}) - result = project.run("r", "-vv", "-e", "py", "--root", str(demo_pkg_inline)) + result = project.run( + "r", + "-vv", + "-e", + "py", + "--root", + str(demo_pkg_inline), + "--workdir", + str(project.path / ".tox"), + ) result.assert_success() wheel_name = "demo_pkg_inline-1.0.0-py3-none-any.whl" session_path = Path(".tmp") / "package" / "1" / wheel_name -- cgit v1.2.1