From 5754521af1d51aa8e445cba07a093bbc0c88596d Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Mon, 16 Dec 2019 18:24:08 -0700 Subject: [PATCH 1/6] bpo-31046: ensurepip does not honour the value of $(prefix) Co-Authored-By: Xavier de Gaye --- Doc/library/ensurepip.rst | 9 +++++++-- Lib/ensurepip/__init__.py | 18 +++++++++++++----- Lib/test/test_ensurepip.py | 11 +++++++++++ Makefile.pre.in | 4 ++-- .../2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst | 1 + 5 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index a2bb045e57e3c0..c5e27388198f2b 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -56,8 +56,9 @@ is at least as recent as the one bundled with ``ensurepip``, pass the By default, ``pip`` is installed into the current virtual environment (if one is active) or into the system site packages (if there is no active virtual environment). The installation location can be controlled -through two additional command line options: +through some additional command line options: +* ``--prefix ``: Installs ``pip`` using the given directory prefix. * ``--root ``: Installs ``pip`` relative to the given root directory rather than the root of the currently active virtual environment (if any) or the default root for the current Python installation. @@ -89,7 +90,7 @@ Module API Returns a string specifying the bundled version of pip that will be installed when bootstrapping an environment. -.. function:: bootstrap(root=None, upgrade=False, user=False, \ +.. function:: bootstrap(root=None, prefix=None, upgrade=False, user=False, \ altinstall=False, default_pip=False, \ verbosity=0) @@ -99,6 +100,8 @@ Module API If *root* is ``None``, then installation uses the default install location for the current environment. + *prefix* specifies the directory prefix to use when installing. + *upgrade* indicates whether or not to upgrade an existing installation of an earlier version of ``pip`` to the bundled version. @@ -119,6 +122,8 @@ Module API *verbosity* controls the level of output to :data:`sys.stdout` from the bootstrapping operation. + .. versionchanged:: 3.9 the *prefix* parameter was added. + .. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap .. note:: diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 386ed6c25c763e..e4293e32860590 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -49,27 +49,27 @@ def _disable_pip_configuration_settings(): os.environ['PIP_CONFIG_FILE'] = os.devnull -def bootstrap(*, root=None, upgrade=False, user=False, +def bootstrap(*, root=None, prefix=None, upgrade=False, user=False, altinstall=False, default_pip=False, verbosity=0): """ Bootstrap pip into the current Python installation (or the given root - directory). + and directory prefix). Note that calling this function will alter both sys.path and os.environ. """ # Discard the return value - _bootstrap(root=root, upgrade=upgrade, user=user, + _bootstrap(root=root, prefix=prefix, upgrade=upgrade, user=user, altinstall=altinstall, default_pip=default_pip, verbosity=verbosity) -def _bootstrap(*, root=None, upgrade=False, user=False, +def _bootstrap(*, root=None, prefix=None, upgrade=False, user=False, altinstall=False, default_pip=False, verbosity=0): """ Bootstrap pip into the current Python installation (or the given root - directory). Returns pip command status code. + and directory prefix). Returns pip command status code. Note that calling this function will alter both sys.path and os.environ. """ @@ -112,6 +112,8 @@ def _bootstrap(*, root=None, upgrade=False, user=False, args = ["install", "--no-index", "--find-links", tmpdir] if root: args += ["--root", root] + if prefix: + args += ["--prefix", prefix] if upgrade: args += ["--upgrade"] if user: @@ -183,6 +185,11 @@ def _main(argv=None): default=None, help="Install everything relative to this alternate root directory.", ) + parser.add_argument( + "--prefix", + default=None, + help="Install everything using this prefix.", + ) parser.add_argument( "--altinstall", action="store_true", @@ -202,6 +209,7 @@ def _main(argv=None): return _bootstrap( root=args.root, + prefix=args.prefix, upgrade=args.upgrade, user=args.user, verbosity=args.verbosity, diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index 89966893092851..79de02c574cdb1 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -61,6 +61,17 @@ def test_bootstrapping_with_root(self): unittest.mock.ANY, ) + def test_bootstrapping_with_prefix(self): + ensurepip.bootstrap(prefix="/foo/bar/") + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + unittest.mock.ANY, "--prefix", "/foo/bar/", + "setuptools", "pip", + ], + unittest.mock.ANY, + ) + def test_bootstrapping_with_user(self): ensurepip.bootstrap(user=True) diff --git a/Makefile.pre.in b/Makefile.pre.in index d08c78df394b37..532ce59ff9df85 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1181,7 +1181,7 @@ install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKI install|*) ensurepip="" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --root=$(DESTDIR)/ ; \ + $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ fi altinstall: commoninstall @@ -1191,7 +1191,7 @@ altinstall: commoninstall install|*) ensurepip="--altinstall" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --root=$(DESTDIR)/ ; \ + $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ fi commoninstall: check-clean-src @FRAMEWORKALTINSTALLFIRST@ \ diff --git a/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst b/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst new file mode 100644 index 00000000000000..07eb89d4d23e50 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst @@ -0,0 +1 @@ +A directory prefix can now be specified when using :mod:`ensurepip`. From 893fc98cf7e8aa033befd9815f3b0fd6e5b6e446 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Jan 2024 15:46:47 +0100 Subject: [PATCH 2/6] Update Doc/library/ensurepip.rst Co-authored-by: Pradyun Gedam --- Doc/library/ensurepip.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index 6d3ae9b40897ad..82d9f9eb00bf7c 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -125,7 +125,9 @@ Module API *verbosity* controls the level of output to :data:`sys.stdout` from the bootstrapping operation. - .. versionchanged:: 3.9 the *prefix* parameter was added. + .. versionchanged:: 3.13 + + The *prefix* parameter was added. .. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap From 462211527b0d65233a86652d19c9b6e192e5a13b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Jan 2024 15:47:45 +0100 Subject: [PATCH 3/6] Move blurb --- .../{Build => Library}/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Misc/NEWS.d/next/{Build => Library}/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst (100%) diff --git a/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst b/Misc/NEWS.d/next/Library/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst similarity index 100% rename from Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst rename to Misc/NEWS.d/next/Library/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst From 22767b5a06475cc2b20f41647cf5737868936dde Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Jan 2024 15:53:19 +0100 Subject: [PATCH 4/6] Fix tests --- Lib/test/test_ensurepip.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index e1ceb04df9208e..1a11a6fac9df1f 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -109,9 +109,8 @@ def test_bootstrapping_with_prefix(self): ensurepip.bootstrap(prefix="/foo/bar/") self.run_pip.assert_called_once_with( [ - "install", "--no-index", "--find-links", - unittest.mock.ANY, "--prefix", "/foo/bar/", - "setuptools", "pip", + "install", "--no-cache-dir", "--no-index", "--find-links", + unittest.mock.ANY, "--prefix", "/foo/bar/", "pip", ], unittest.mock.ANY, ) From 47927a13de839eff97339135c8d6eda5cf92b0d7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Jan 2024 17:23:51 +0100 Subject: [PATCH 5/6] Address Paul's review --- Doc/library/ensurepip.rst | 10 +++++----- Lib/ensurepip/__init__.py | 14 ++++++++------ Lib/test/test_ensurepip.py | 5 +++++ Makefile.pre.in | 4 ++-- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index 82d9f9eb00bf7c..4a2b430c607484 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -93,9 +93,9 @@ Module API Returns a string specifying the available version of pip that will be installed when bootstrapping an environment. -.. function:: bootstrap(root=None, prefix=None, upgrade=False, user=False, \ +.. function:: bootstrap(root=None, upgrade=False, user=False, \ altinstall=False, default_pip=False, \ - verbosity=0) + verbosity=0, prefix=None) Bootstraps ``pip`` into the current or designated environment. @@ -103,8 +103,6 @@ Module API If *root* is ``None``, then installation uses the default install location for the current environment. - *prefix* specifies the directory prefix to use when installing. - *upgrade* indicates whether or not to upgrade an existing installation of an earlier version of ``pip`` to the available version. @@ -125,9 +123,11 @@ Module API *verbosity* controls the level of output to :data:`sys.stdout` from the bootstrapping operation. + *prefix* specifies the directory prefix to use when installing. + .. versionchanged:: 3.13 - The *prefix* parameter was added. + The *prefix* parameter. .. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 1bd22d74dfdd77..3f9c87bc7baaa3 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -120,9 +120,9 @@ def _disable_pip_configuration_settings(): os.environ['PIP_CONFIG_FILE'] = os.devnull -def bootstrap(*, root=None, prefix=None, upgrade=False, user=False, +def bootstrap(*, root=None, upgrade=False, user=False, altinstall=False, default_pip=False, - verbosity=0): + verbosity=0, prefix=None): """ Bootstrap pip into the current Python installation (or the given root and directory prefix). @@ -130,20 +130,22 @@ def bootstrap(*, root=None, prefix=None, upgrade=False, user=False, Note that calling this function will alter both sys.path and os.environ. """ # Discard the return value - _bootstrap(root=root, prefix=prefix, upgrade=upgrade, user=user, + _bootstrap(root=root, upgrade=upgrade, user=user, altinstall=altinstall, default_pip=default_pip, - verbosity=verbosity) + verbosity=verbosity, prefix=prefix) -def _bootstrap(*, root=None, prefix=None, upgrade=False, user=False, +def _bootstrap(*, root=None, upgrade=False, user=False, altinstall=False, default_pip=False, - verbosity=0): + verbosity=0, prefix=None): """ Bootstrap pip into the current Python installation (or the given root and directory prefix). Returns pip command status code. Note that calling this function will alter both sys.path and os.environ. """ + if root is not None and prefix is not None: + raise ValueError("Cannot use 'root' and 'prefix' together") if altinstall and default_pip: raise ValueError("Cannot use altinstall and default_pip together") diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index 1a11a6fac9df1f..5e8ad0681eb116 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -115,6 +115,11 @@ def test_bootstrapping_with_prefix(self): unittest.mock.ANY, ) + def test_root_and_prefix_mutual_exclusive(self): + with self.assertRaises(ValueError): + ensurepip.bootstrap(root="", prefix="") + self.assertFalse(self.run_pip.called) + def test_bootstrapping_with_user(self): ensurepip.bootstrap(user=True) diff --git a/Makefile.pre.in b/Makefile.pre.in index 2c4006dd2adc5a..efdc1dd938e961 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1981,7 +1981,7 @@ install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKI install|*) ensurepip="" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ + $$ensurepip --prefix=$(prefix) ; \ fi .PHONY: altinstall @@ -1992,7 +1992,7 @@ altinstall: commoninstall install|*) ensurepip="--altinstall" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ + $$ensurepip --prefix=$(prefix) ; \ fi .PHONY: commoninstall From aee28dbdcee9d95c035ecce1d42fcf6c5afb4b4e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Jan 2024 18:39:01 +0100 Subject: [PATCH 6/6] Sphinx nit --- Doc/library/ensurepip.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index 4a2b430c607484..7f643731130671 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -125,7 +125,7 @@ Module API *prefix* specifies the directory prefix to use when installing. - .. versionchanged:: 3.13 + .. versionadded:: 3.13 The *prefix* parameter.