From 342f19f9decc902b7cdbb97350d426cf4cdf9dc0 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Thu, 24 Feb 2022 11:20:50 +0100 Subject: [PATCH 1/3] Prevent leaking PYTHONPATH to spawned processes in tests This enhances environment isolation, as in special cases, like downstream distro packaging, PYTHONPATH can be set to point to a specific setuptools codebase. When it leaks, it shadows the virtual environment's paths and produces wrong test results. --- setuptools/tests/environment.py | 13 +++++++++++++ setuptools/tests/fixtures.py | 13 ++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index a0c0ec6e70..79407d9f6a 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -18,6 +18,19 @@ class VirtualEnv(jaraco.envs.VirtualEnv): def run(self, cmd, *args, **kwargs): cmd = [self.exe(cmd[0])] + cmd[1:] kwargs = {"cwd": self.root, **kwargs} # Allow overriding + # In some environments (eg. downstream distro packaging), where: + # - tox isn't used to run tests and + # - PYTHONPATH is set to point to a specific setuptools codebase and + # - no custom env is explicitly set by a test + # that PYTHONPATH leaks to the spawned processes. + # In that case tests look for module in the wrong place (on PYTHONPATH). + # Unless the test sets its own special env, pass a copy of the existing + # environment with removed PYTHONPATH to the subprocesses. + if "env" not in kwargs: + env = dict(os.environ) + if "PYTHONPATH" in env: + del env["PYTHONPATH"] + kwargs["env"] = env return subprocess.check_output(cmd, *args, **kwargs) diff --git a/setuptools/tests/fixtures.py b/setuptools/tests/fixtures.py index 7599e65540..837e6490ec 100644 --- a/setuptools/tests/fixtures.py +++ b/setuptools/tests/fixtures.py @@ -98,7 +98,18 @@ def venv(tmp_path, setuptools_wheel): env = environment.VirtualEnv() env.root = path.Path(tmp_path / 'venv') env.req = str(setuptools_wheel) - return env.create() + # In some environments (eg. downstream distro packaging), + # where tox isn't used to run tests and PYTHONPATH is set to point to + # a specific setuptools codebase, that PYTHONPATH leaks to the spawned + # processes. + # env.create() should install the just created setuptools + # wheel, but it doesn't if it finds another existing matching setuptools + # installation present on PYTHONPATH: + # `setuptools is already installed with the same version as the provided + # wheel. Use --force-reinstall to force an installation of the wheel.` + # This prevents leaking PYTHONPATH to the created environment. + with contexts.environment(PYTHONPATH=None): + return env.create() @pytest.fixture From 6cabd18d6fa251d9c08b4298cb0b44a29cc1ae1d Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Thu, 24 Feb 2022 13:53:44 +0100 Subject: [PATCH 2/3] Add news fragment --- changelog.d/3133.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3133.misc.rst diff --git a/changelog.d/3133.misc.rst b/changelog.d/3133.misc.rst new file mode 100644 index 0000000000..3377e06178 --- /dev/null +++ b/changelog.d/3133.misc.rst @@ -0,0 +1 @@ +Enhanced isolation of tests using virtual environments - PYTHONPATH is not leaking to spawned subprocesses -- by :user:`befeleme` From 634dd7e1779663d98cc2fa0382656e8f578b669e Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 25 Feb 2022 15:14:03 +0000 Subject: [PATCH 3/3] Apply suggestions from code review --- setuptools/tests/environment.py | 2 +- setuptools/tests/fixtures.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index 79407d9f6a..bcf29601ce 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -22,7 +22,7 @@ def run(self, cmd, *args, **kwargs): # - tox isn't used to run tests and # - PYTHONPATH is set to point to a specific setuptools codebase and # - no custom env is explicitly set by a test - # that PYTHONPATH leaks to the spawned processes. + # PYTHONPATH will leak into the spawned processes. # In that case tests look for module in the wrong place (on PYTHONPATH). # Unless the test sets its own special env, pass a copy of the existing # environment with removed PYTHONPATH to the subprocesses. diff --git a/setuptools/tests/fixtures.py b/setuptools/tests/fixtures.py index 837e6490ec..e912399d0e 100644 --- a/setuptools/tests/fixtures.py +++ b/setuptools/tests/fixtures.py @@ -100,7 +100,7 @@ def venv(tmp_path, setuptools_wheel): env.req = str(setuptools_wheel) # In some environments (eg. downstream distro packaging), # where tox isn't used to run tests and PYTHONPATH is set to point to - # a specific setuptools codebase, that PYTHONPATH leaks to the spawned + # a specific setuptools codebase, PYTHONPATH will leak into the spawned # processes. # env.create() should install the just created setuptools # wheel, but it doesn't if it finds another existing matching setuptools