From 3bd8e598db4836b00bccc23241e30acf3b44c0e2 Mon Sep 17 00:00:00 2001 From: Xavier de Gaye Date: Mon, 16 Dec 2019 18:24:08 -0700 Subject: [PATCH 1/6] bpo-31046: ensurepip does not honour the value of $(prefix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cross-compiling, the local Python interpreter that is used to run `ensurepip` may not have the same value of `sys.prefix` as the value of the 'prefix' variable that is set in the Makefile. With the following values used to install Python locally for a later copy to the files hierarchy owned by the 'termux' application on an Android device: DESTDIR=/tmp/android prefix=/data/data/com.termux/files/usr/local 'make install' causes ensurepip to install pip in $(DESTDIR)/usr/local instead of the expected $(DESTDIR)/$(prefix) where is installed the standard library. The attached patch fixes the problem. The patch was implemented assuming that pip uses distutils for the installation (note that setup.py also uses the --prefix option in the Makefile), but I know nothing about pip so forgive me if the patch is wrong and please just assume it is just a way to demonstrate the problem. Fixes: https://github.com/python/cpython/issues/75229 Fixes: https://bugs.python.org/issue31046 Co-authored-by: Pradyun Gedam Co-authored-by: Erlend E. Aasland Co-authored-by: Zackery Spytz References: https://github.com/python/cpython/pull/17634 Signed-off-by: Matěj Cepl --- Doc/library/ensurepip.rst | 14 +++++++++++-- Lib/ensurepip/__init__.py | 20 ++++++++++++++----- Lib/test/test_ensurepip.py | 15 ++++++++++++++ Makefile.pre.in | 4 ++-- .../2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst | 1 + 5 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index fa102c4a080103..26cf1715f5d74b 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -61,7 +61,11 @@ is at least as recent as the one available in ``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: + +.. option:: --prefix + + Installs ``pip`` using the given directory prefix. .. option:: --root @@ -104,7 +108,7 @@ Module API .. 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. @@ -132,6 +136,12 @@ 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. + + .. versionadded:: 3.14 + + The *prefix* parameter. + .. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap .. note:: diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index aa641e94a8b336..68e97ad381f86e 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -108,28 +108,30 @@ def _disable_pip_configuration_settings(): 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 - 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, altinstall=altinstall, default_pip=default_pip, - verbosity=verbosity) + verbosity=verbosity, prefix=prefix) 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 - 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. """ + 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") @@ -162,6 +164,8 @@ def _bootstrap(*, root=None, upgrade=False, user=False, args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir] if root: args += ["--root", root] + if prefix: + args += ["--prefix", prefix] if upgrade: args += ["--upgrade"] if user: @@ -237,6 +241,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", @@ -256,6 +265,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 6d3c91b0b6d9f9..cd858ff09f3e4d 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -100,6 +100,21 @@ 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-cache-dir", "--no-index", "--find-links", + unittest.mock.ANY, "--prefix", "/foo/bar/", "pip", + ], + 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 0c070131cda200..8d0f80a5923868 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2366,7 +2366,7 @@ install: @FRAMEWORKINSTALLFIRST@ @INSTALLTARGETS@ @FRAMEWORKINSTALLLAST@ install|*) ensurepip="" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --root=$(DESTDIR)/ ; \ + $$ensurepip --prefix=$(prefix) ; \ fi .PHONY: altinstall @@ -2377,7 +2377,7 @@ altinstall: commoninstall install|*) ensurepip="--altinstall" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --root=$(DESTDIR)/ ; \ + $$ensurepip --prefix=$(prefix) ; \ fi .PHONY: commoninstall diff --git a/Misc/NEWS.d/next/Library/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 new file mode 100644 index 00000000000000..07eb89d4d23e50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/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 0940129a44c57675fafd44660636dd5225f5e243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Fri, 13 Jun 2025 22:58:14 +0200 Subject: [PATCH 2/6] bpo-31046: Fix ensurepip script shebangs with --root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using `python -m ensurepip` with the `--root` option for staged installations, the generated pip script contained an incorrect shebang that pointed into the staging directory. This made the installation unusable once the staging directory was removed. This commit fixes the issue by using the internal pip `--executable` option to force the shebang to point to the correct, final interpreter path. It also corrects related pathing issues: - Removes the check that incorrectly disallowed using --root and --prefix together. - Defaults the installation prefix to `/` when --root is used alone, ensuring installation occurs at the base of the staging directory. References: https://github.com/python/cpython/pull/17634#discussion_r1622453325 Signed-off-by: Matěj Cepl --- Lib/ensurepip/__init__.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 68e97ad381f86e..aeb432cee3e6ee 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -130,8 +130,6 @@ def _bootstrap(*, root=None, upgrade=False, user=False, 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") @@ -162,17 +160,38 @@ def _bootstrap(*, root=None, upgrade=False, user=False, # Construct the arguments to be passed to the pip command args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir] - if root: - args += ["--root", root] - if prefix: - args += ["--prefix", prefix] if upgrade: args += ["--upgrade"] - if user: - args += ["--user"] if verbosity: args += ["-" + "v" * verbosity] +        if user: +            # --user is mutually exclusive with --root/--prefix, +            # pip will enforce this. +            args += ["--user"] +        else: +            # Handle installation paths. +            # If --root is given but not --prefix, we default to a prefix of "/" +            # so that the install happens at the root of the --root directory. +            # Otherwise, pip would use the configured sys.prefix, e.g. +            # /usr/local, and install into ${root}/usr/local/. +            effective_prefix = prefix +            if root and not prefix: +                effective_prefix = "/" + +            if root: +                args += ["--root", root] + +            if effective_prefix: +                args += ["--prefix", effective_prefix] + +                # Force the script shebang to point to the correct, final +                # executable path. This is necessary when --root is used. +                executable_path = ( +                    Path(effective_prefix) / "bin" / Path(sys.executable).name +                ) +                args += ["--executable", os.fsdecode(executable_path)] + return _run_pip([*args, "pip"], [os.fsdecode(tmp_wheel_path)]) From d586aad09986d196657c9bd427b6f6fcdb9bc3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Mon, 7 Jul 2025 18:40:15 +0200 Subject: [PATCH 3/6] don't throw away `--root` parameter of ensurepip Don't break the default installation on the current system with good `sys.prefix`. --- Makefile.pre.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 8d0f80a5923868..d45a31ca948756 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2366,7 +2366,7 @@ install: @FRAMEWORKINSTALLFIRST@ @INSTALLTARGETS@ @FRAMEWORKINSTALLLAST@ install|*) ensurepip="" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --prefix=$(prefix) ; \ + $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ fi .PHONY: altinstall @@ -2377,7 +2377,7 @@ altinstall: commoninstall install|*) ensurepip="--altinstall" ;; \ esac; \ $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ - $$ensurepip --prefix=$(prefix) ; \ + $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ fi .PHONY: commoninstall From 85addb49be65b1852edd24cf57361202cad68870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Tue, 8 Jul 2025 13:56:44 +0200 Subject: [PATCH 4/6] fix: remove test_root_and_prefix_mutual_exclusive It is made incorrect by the previous commit. --- Lib/test/test_ensurepip.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index cd858ff09f3e4d..bf41601698cb6c 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -110,11 +110,6 @@ 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) From 90694b026108126968c2da750a524b94ce680044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Fri, 25 Jul 2025 13:02:40 +0200 Subject: [PATCH 5/6] fix test.test_ensurepip.TestBootstrap.test_bootstrapping_with_root --- Lib/test/test_ensurepip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index bf41601698cb6c..5b08cb1ccca4a1 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -94,7 +94,7 @@ def test_bootstrapping_with_root(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "--root", "/foo/bar/", + unittest.mock.ANY, "--root", "/foo/bar/", "--prefix", unittest.mock.ANY, "pip", ], unittest.mock.ANY, From 1fd580fb4e871adbe951696be18e386a2f68f56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Fri, 25 Jul 2025 13:02:40 +0200 Subject: [PATCH 6/6] Remove   characters. --- Lib/ensurepip/__init__.py | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index aeb432cee3e6ee..dd875d3a8e138a 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -165,32 +165,32 @@ def _bootstrap(*, root=None, upgrade=False, user=False, if verbosity: args += ["-" + "v" * verbosity] -        if user: -            # --user is mutually exclusive with --root/--prefix, -            # pip will enforce this. -            args += ["--user"] -        else: -            # Handle installation paths. -            # If --root is given but not --prefix, we default to a prefix of "/" -            # so that the install happens at the root of the --root directory. -            # Otherwise, pip would use the configured sys.prefix, e.g. -            # /usr/local, and install into ${root}/usr/local/. -            effective_prefix = prefix -            if root and not prefix: -                effective_prefix = "/" - -            if root: -                args += ["--root", root] - -            if effective_prefix: -                args += ["--prefix", effective_prefix] - -                # Force the script shebang to point to the correct, final -                # executable path. This is necessary when --root is used. -                executable_path = ( -                    Path(effective_prefix) / "bin" / Path(sys.executable).name -                ) -                args += ["--executable", os.fsdecode(executable_path)] + if user: + # --user is mutually exclusive with --root/--prefix, + # pip will enforce this. + args += ["--user"] + else: + # Handle installation paths. + # If --root is given but not --prefix, we default to a prefix of "/" + # so that the install happens at the root of the --root directory. + # Otherwise, pip would use the configured sys.prefix, e.g. + # /usr/local, and install into ${root}/usr/local/. + effective_prefix = prefix + if root and not prefix: + effective_prefix = "/" + + if root: + args += ["--root", root] + + if effective_prefix: + args += ["--prefix", effective_prefix] + + # Force the script shebang to point to the correct, final + # executable path. This is necessary when --root is used. + executable_path = ( + Path(effective_prefix) / "bin" / Path(sys.executable).name + ) + args += ["--executable", os.fsdecode(executable_path)] return _run_pip([*args, "pip"], [os.fsdecode(tmp_wheel_path)]) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy