From 6256fcbc97e0b1a1e0df1972221232b3a78dff18 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Mon, 23 Dec 2013 16:16:07 +1000 Subject: [PATCH] Close #19734: ignore pip env vars in ensurepip --- Doc/library/ensurepip.rst | 6 ++++++ Lib/ensurepip/__init__.py | 8 ++++++++ Lib/test/test_ensurepip.py | 8 ++++++++ Lib/test/test_venv.py | 14 +++++--------- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index 528370cf8a..0d821351d7 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -117,6 +117,12 @@ Module API *verbosity* controls the level of output to :data:`sys.stdout` from the bootstrapping operation. + .. note:: + + The bootstrapping process has side effects on both ``sys.path`` and + ``os.environ``. Invoking the command line interface in a subprocess + instead allows these side effects to be avoided. + .. note:: The bootstrapping process may install additional modules required by diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index b6bc4b606e..5ceda516a2 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -43,10 +43,18 @@ def bootstrap(*, root=None, upgrade=False, user=False, """ Bootstrap pip into the current Python installation (or the given root directory). + + Note that calling this function will alter both sys.path and os.environ. """ if altinstall and default_pip: raise ValueError("Cannot use altinstall and default_pip together") + # We deliberately ignore all pip environment variables + # See http://bugs.python.org/issue19734 for details + keys_to_remove = [k for k in os.environ if k.startswith("PIP_")] + for k in keys_to_remove: + del os.environ[k] + # By default, installing pip and setuptools installs all of the # following scripts (X.Y == running Python version): # diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index c119327d42..8c125bf036 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -126,6 +126,14 @@ class TestBootstrap(unittest.TestCase): ensurepip.bootstrap(altinstall=True, default_pip=True) self.run_pip.assert_not_called() + def test_pip_environment_variables_removed(self): + # ensurepip deliberately ignores all pip environment variables + # See http://bugs.python.org/issue19734 for details + self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" + ensurepip.bootstrap() + self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) + + @contextlib.contextmanager def fake_pip(version=ensurepip._PIP_VERSION): if version is None: diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index eb225fa4ae..e8437cf95e 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -294,11 +294,12 @@ class EnsurePipTest(BaseTest): # warnings in current versions of Python. Ensure related # environment settings don't cause venv to fail. envvars["PYTHONWARNINGS"] = "e" - # pip doesn't ignore environment variables when running in - # isolated mode, and we don't have an active virtualenv here, - # we're relying on the native venv support in 3.3+ + # ensurepip is different enough from a normal pip invocation + # that we want to ensure it ignores the normal pip environment + # variable settings. We set PIP_NO_INSTALL here specifically + # to check that ensurepip (and hence venv) ignores it. # See http://bugs.python.org/issue19734 for details - del envvars["PIP_REQUIRE_VIRTUALENV"] + envvars["PIP_NO_INSTALL"] = "1" try: self.run_with_capture(venv.create, self.env_dir, with_pip=True) except subprocess.CalledProcessError as exc: @@ -328,11 +329,6 @@ class EnsurePipTest(BaseTest): # installers works (at least in a virtual environment) cmd = [envpy, '-Im', 'ensurepip._uninstall'] with EnvironmentVarGuard() as envvars: - # pip doesn't ignore environment variables when running in - # isolated mode, and we don't have an active virtualenv here, - # we're relying on the native venv support in 3.3+ - # See http://bugs.python.org/issue19734 for details - del envvars["PIP_REQUIRE_VIRTUALENV"] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() -- 2.40.0