From bdc2bc25666d2067b6b2a2a6ebfd072822bf59cf Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Mon, 12 May 2025 15:02:06 +0200 Subject: [PATCH 1/8] Fix Tox hanging with --installpkg sdist due to orphaned build backend. --- .../tox_env/python/virtual_env/package/pyproject.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tox/tox_env/python/virtual_env/package/pyproject.py b/src/tox/tox_env/python/virtual_env/package/pyproject.py index 4b4be011f..cf90818f7 100644 --- a/src/tox/tox_env/python/virtual_env/package/pyproject.py +++ b/src/tox/tox_env/python/virtual_env/package/pyproject.py @@ -118,8 +118,15 @@ def root(self) -> Path: @root.setter def root(self, value: Path) -> None: - self._root = value - self._frontend_ = None # force recreating the frontend with new root + # NOTE(vytas): Recreating the frontend with a new root will orphan the + # current frontend.backend_executor, if any, making tox hang upon + # exit waiting for its threads and subprocesses (#3512). + # + # Here, we partially worka round the issue by only resetting the root + # when it has actually changed: + if self._root != value: + self._root = value + self._frontend_ = None # force recreating the frontend with new root @staticmethod def id() -> str: From 3220551248182902032fb18907c716914d07c9a5 Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Mon, 12 May 2025 15:07:39 +0200 Subject: [PATCH 2/8] Fix swapped characters. --- src/tox/tox_env/python/virtual_env/package/pyproject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tox/tox_env/python/virtual_env/package/pyproject.py b/src/tox/tox_env/python/virtual_env/package/pyproject.py index cf90818f7..b1a287f84 100644 --- a/src/tox/tox_env/python/virtual_env/package/pyproject.py +++ b/src/tox/tox_env/python/virtual_env/package/pyproject.py @@ -122,7 +122,7 @@ def root(self, value: Path) -> None: # current frontend.backend_executor, if any, making tox hang upon # exit waiting for its threads and subprocesses (#3512). # - # Here, we partially worka round the issue by only resetting the root + # Here, we partially work around the issue by only resetting the root # when it has actually changed: if self._root != value: self._root = value From d3e23c9daa58d015993b8f692c14d82efe634a05 Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Tue, 13 May 2025 19:16:53 +0200 Subject: [PATCH 3/8] Add a Towncrier newsfragment. --- docs/changelog/3530.bugfix.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/changelog/3530.bugfix.rst diff --git a/docs/changelog/3530.bugfix.rst b/docs/changelog/3530.bugfix.rst new file mode 100644 index 000000000..676d09410 --- /dev/null +++ b/docs/changelog/3530.bugfix.rst @@ -0,0 +1,3 @@ +Prevent tox from hanging upon exit due to orphaned build threads and +subprocesses when the ``--installpkg`` option is used with *sdist*. +- by :user:`vytas7` From 4ff3fcccab1edceaa367b958c74764ef72163238 Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Tue, 13 May 2025 20:38:11 +0200 Subject: [PATCH 4/8] Add an integration test exercising the scenario from #3512. --- pyproject.toml | 1 + .../python/virtual_env/package/conftest.py | 38 +++++++++++++++++++ .../package/test_package_pyproject.py | 24 ++++++++++++ 3 files changed, 63 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 9cd667865..5689a5187 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,6 +90,7 @@ test = [ "flaky>=3.8.1", "hatch-vcs>=0.4", "hatchling>=1.27", + "pdm-backend", "psutil>=6.1.1", "pytest>=8.3.4", "pytest-cov>=5", diff --git a/tests/tox_env/python/virtual_env/package/conftest.py b/tests/tox_env/python/virtual_env/package/conftest.py index b34d44c81..63b3a6232 100644 --- a/tests/tox_env/python/virtual_env/package/conftest.py +++ b/tests/tox_env/python/virtual_env/package/conftest.py @@ -40,3 +40,41 @@ def pkg_with_extras_project(tmp_path_factory: pytest.TempPathFactory) -> Path: toml = '[build-system]\nrequires=["setuptools", "wheel"]\nbuild-backend = "setuptools.build_meta"' (tmp_path / "pyproject.toml").write_text(toml) return tmp_path + + +@pytest.fixture(scope="session") +def pkg_with_pdm_backend( + tmp_path_factory: pytest.TempPathFactory, + pkg_builder: Callable[[Path, Path, list[str], bool], Path], +) -> Path: + tmp_path = tmp_path_factory.mktemp("skeleton") + + pyproject_toml = f""" + [build-system] + requires = ["pdm-backend"] + build-backend = "pdm.backend" + + [project] + name = "skeleton" + description = "Just a skeleton for reproducing #3512." + version = "0.1.1337" + dependencies = [ + "requests", + ] + + [tool.pdm.build] + includes = [ + "skeleton/", + ] + source-includes = [ + "tox.ini", + ] + """ + (tmp_path / "pyproject.toml").write_text(dedent(pyproject_toml)) + (tmp_path / "skeleton").mkdir(exist_ok=True) + (tmp_path / "skeleton" / "__init__.py").touch() + + dist = tmp_path / "dist" + pkg_builder(dist, tmp_path, ["sdist"], False) + + return tmp_path diff --git a/tests/tox_env/python/virtual_env/package/test_package_pyproject.py b/tests/tox_env/python/virtual_env/package/test_package_pyproject.py index 0ae8d2c3b..852a61b92 100644 --- a/tests/tox_env/python/virtual_env/package/test_package_pyproject.py +++ b/tests/tox_env/python/virtual_env/package/test_package_pyproject.py @@ -458,3 +458,27 @@ def test_pyproject_config_settings_editable_legacy( "get_requires_for_build_wheel": {"C": "3"}, "prepare_metadata_for_build_wheel": {"D": "4"}, } + + +@pytest.mark.usefixtures("enable_pip_pypi_access") +def test_aaa_pyproject_installpkg_pep517_envs( + tox_project: ToxProjectCreator, + pkg_with_pdm_backend: Path, +) -> None: + # Regression test for #3512 + tox_ini = """ + [tox] + envlist = dummy1,dummy2 + + [testenv:dummy1] + commands = + python -c print(1) + + [testenv:dummy2] + commands = + python -c print(42) + """ + sdist = pkg_with_pdm_backend / "dist" / "skeleton-0.1.1337.tar.gz" + proj = tox_project({"tox.ini": tox_ini}, base=pkg_with_pdm_backend) + result = proj.run("--installpkg", str(sdist), "--exit-and-dump-after", "10") + result.assert_success() From 99adb4c9e61c31b32a8db29c8464a99176fa1c24 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 18:38:49 +0000 Subject: [PATCH 5/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/tox_env/python/virtual_env/package/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tox_env/python/virtual_env/package/conftest.py b/tests/tox_env/python/virtual_env/package/conftest.py index 63b3a6232..c335de4ff 100644 --- a/tests/tox_env/python/virtual_env/package/conftest.py +++ b/tests/tox_env/python/virtual_env/package/conftest.py @@ -49,7 +49,7 @@ def pkg_with_pdm_backend( ) -> Path: tmp_path = tmp_path_factory.mktemp("skeleton") - pyproject_toml = f""" + pyproject_toml = """ [build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" From 735c89133c6cd55008497b6d081c56f9c5677caa Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Tue, 13 May 2025 20:42:16 +0200 Subject: [PATCH 6/8] Address issues found in static code analysis. --- tests/tox_env/python/virtual_env/package/conftest.py | 2 +- tox.toml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/tox_env/python/virtual_env/package/conftest.py b/tests/tox_env/python/virtual_env/package/conftest.py index c335de4ff..885a9bc80 100644 --- a/tests/tox_env/python/virtual_env/package/conftest.py +++ b/tests/tox_env/python/virtual_env/package/conftest.py @@ -7,7 +7,7 @@ import pytest if TYPE_CHECKING: - from pathlib import Path + from pathlib import Callable, Path @pytest.fixture(scope="session") diff --git a/tox.toml b/tox.toml index f998ba10d..41f748b1d 100644 --- a/tox.toml +++ b/tox.toml @@ -16,8 +16,8 @@ commands = [ { replace = "posargs", extend = true, default = [ "--durations", "15", - "-n", - { replace = "env", name = "PYTEST_XDIST_AUTO_NUM_WORKERS", default = "auto" }, + # "-n", + # { replace = "env", name = "PYTEST_XDIST_AUTO_NUM_WORKERS", default = "auto" }, "--junitxml", "{work_dir}{/}junit.{env_name}.xml", "--no-cov-on-fail", @@ -35,7 +35,8 @@ commands = [ "html:{env_tmp_dir}{/}htmlcov", "--cov-report", "xml:{work_dir}{/}coverage.{env_name}.xml", - "tests", + "tests/tox_env/python/virtual_env/package/test_package_pyproject.py::test_aaa_pyproject_installpkg_pep517_envs", + "-v", "--run-integration", ] }, ], From 6539415a6e63d30101c7d9bf5e7e43c8029ad4c1 Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Tue, 13 May 2025 20:44:47 +0200 Subject: [PATCH 7/8] Undo debugging changes. --- tox.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tox.toml b/tox.toml index 41f748b1d..f998ba10d 100644 --- a/tox.toml +++ b/tox.toml @@ -16,8 +16,8 @@ commands = [ { replace = "posargs", extend = true, default = [ "--durations", "15", - # "-n", - # { replace = "env", name = "PYTEST_XDIST_AUTO_NUM_WORKERS", default = "auto" }, + "-n", + { replace = "env", name = "PYTEST_XDIST_AUTO_NUM_WORKERS", default = "auto" }, "--junitxml", "{work_dir}{/}junit.{env_name}.xml", "--no-cov-on-fail", @@ -35,8 +35,7 @@ commands = [ "html:{env_tmp_dir}{/}htmlcov", "--cov-report", "xml:{work_dir}{/}coverage.{env_name}.xml", - "tests/tox_env/python/virtual_env/package/test_package_pyproject.py::test_aaa_pyproject_installpkg_pep517_envs", - "-v", + "tests", "--run-integration", ] }, ], From 6708d1db046982514b7459b5177572be76629bfe Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia Date: Tue, 13 May 2025 20:48:41 +0200 Subject: [PATCH 8/8] Fix a typing PEBCAK. --- tests/tox_env/python/virtual_env/package/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tox_env/python/virtual_env/package/conftest.py b/tests/tox_env/python/virtual_env/package/conftest.py index 885a9bc80..1f19e6fa5 100644 --- a/tests/tox_env/python/virtual_env/package/conftest.py +++ b/tests/tox_env/python/virtual_env/package/conftest.py @@ -2,12 +2,12 @@ import sys from textwrap import dedent -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Callable import pytest if TYPE_CHECKING: - from pathlib import Callable, Path + from pathlib import Path @pytest.fixture(scope="session")