Skip to content

Commit cd54b53

Browse files
CPython Developersyouknowone
CPython Developers
authored andcommitted
Udpate ensurepip from CPython 3.13.2
1 parent d46bcd9 commit cd54b53

File tree

4 files changed

+73
-104
lines changed

4 files changed

+73
-104
lines changed

Lib/ensurepip/__init__.py

Lines changed: 52 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,64 @@
1-
import collections
21
import os
3-
import os.path
42
import subprocess
53
import sys
64
import sysconfig
75
import tempfile
6+
from contextlib import nullcontext
87
from importlib import resources
8+
from pathlib import Path
9+
from shutil import copy2
910

1011

1112
__all__ = ["version", "bootstrap"]
12-
_PACKAGE_NAMES = ('pip',)
13-
_PIP_VERSION = "23.2.1"
14-
_PROJECTS = [
15-
("pip", _PIP_VERSION, "py3"),
16-
]
17-
18-
# Packages bundled in ensurepip._bundled have wheel_name set.
19-
# Packages from WHEEL_PKG_DIR have wheel_path set.
20-
_Package = collections.namedtuple('Package',
21-
('version', 'wheel_name', 'wheel_path'))
13+
_PIP_VERSION = "24.3.1"
2214

2315
# Directory of system wheel packages. Some Linux distribution packaging
2416
# policies recommend against bundling dependencies. For example, Fedora
2517
# installs wheel packages in the /usr/share/python-wheels/ directory and don't
2618
# install the ensurepip._bundled package.
27-
_WHEEL_PKG_DIR = sysconfig.get_config_var('WHEEL_PKG_DIR')
19+
if (_pkg_dir := sysconfig.get_config_var('WHEEL_PKG_DIR')) is not None:
20+
_WHEEL_PKG_DIR = Path(_pkg_dir).resolve()
21+
else:
22+
_WHEEL_PKG_DIR = None
23+
2824

25+
def _find_wheel_pkg_dir_pip():
26+
if _WHEEL_PKG_DIR is None:
27+
# NOTE: The compile-time `WHEEL_PKG_DIR` is unset so there is no place
28+
# NOTE: for looking up the wheels.
29+
return None
2930

30-
def _find_packages(path):
31-
packages = {}
31+
dist_matching_wheels = _WHEEL_PKG_DIR.glob('pip-*.whl')
3232
try:
33-
filenames = os.listdir(path)
34-
except OSError:
35-
# Ignore: path doesn't exist or permission error
36-
filenames = ()
37-
# Make the code deterministic if a directory contains multiple wheel files
38-
# of the same package, but don't attempt to implement correct version
39-
# comparison since this case should not happen.
40-
filenames = sorted(filenames)
41-
for filename in filenames:
42-
# filename is like 'pip-21.2.4-py3-none-any.whl'
43-
if not filename.endswith(".whl"):
44-
continue
45-
for name in _PACKAGE_NAMES:
46-
prefix = name + '-'
47-
if filename.startswith(prefix):
48-
break
49-
else:
50-
continue
51-
52-
# Extract '21.2.4' from 'pip-21.2.4-py3-none-any.whl'
53-
version = filename.removeprefix(prefix).partition('-')[0]
54-
wheel_path = os.path.join(path, filename)
55-
packages[name] = _Package(version, None, wheel_path)
56-
return packages
57-
58-
59-
def _get_packages():
60-
global _PACKAGES, _WHEEL_PKG_DIR
61-
if _PACKAGES is not None:
62-
return _PACKAGES
63-
64-
packages = {}
65-
for name, version, py_tag in _PROJECTS:
66-
wheel_name = f"{name}-{version}-{py_tag}-none-any.whl"
67-
packages[name] = _Package(version, wheel_name, None)
68-
if _WHEEL_PKG_DIR:
69-
dir_packages = _find_packages(_WHEEL_PKG_DIR)
70-
# only used the wheel package directory if all packages are found there
71-
if all(name in dir_packages for name in _PACKAGE_NAMES):
72-
packages = dir_packages
73-
_PACKAGES = packages
74-
return packages
75-
_PACKAGES = None
33+
last_matching_dist_wheel = sorted(dist_matching_wheels)[-1]
34+
except IndexError:
35+
# NOTE: `WHEEL_PKG_DIR` does not contain any wheel files for `pip`.
36+
return None
37+
38+
return nullcontext(last_matching_dist_wheel)
39+
40+
41+
def _get_pip_whl_path_ctx():
42+
# Prefer pip from the wheel package directory, if present.
43+
if (alternative_pip_wheel_path := _find_wheel_pkg_dir_pip()) is not None:
44+
return alternative_pip_wheel_path
45+
46+
return resources.as_file(
47+
resources.files('ensurepip')
48+
/ '_bundled'
49+
/ f'pip-{_PIP_VERSION}-py3-none-any.whl'
50+
)
51+
52+
53+
def _get_pip_version():
54+
with _get_pip_whl_path_ctx() as bundled_wheel_path:
55+
wheel_name = bundled_wheel_path.name
56+
return (
57+
# Extract '21.2.4' from 'pip-21.2.4-py3-none-any.whl'
58+
wheel_name.
59+
removeprefix('pip-').
60+
partition('-')[0]
61+
)
7662

7763

7864
def _run_pip(args, additional_paths=None):
@@ -105,7 +91,7 @@ def version():
10591
"""
10692
Returns a string specifying the bundled version of pip.
10793
"""
108-
return _get_packages()['pip'].version
94+
return _get_pip_version()
10995

11096

11197
def _disable_pip_configuration_settings():
@@ -167,24 +153,10 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
167153
with tempfile.TemporaryDirectory() as tmpdir:
168154
# Put our bundled wheels into a temporary directory and construct the
169155
# additional paths that need added to sys.path
170-
additional_paths = []
171-
for name, package in _get_packages().items():
172-
if package.wheel_name:
173-
# Use bundled wheel package
174-
wheel_name = package.wheel_name
175-
wheel_path = resources.files("ensurepip") / "_bundled" / wheel_name
176-
whl = wheel_path.read_bytes()
177-
else:
178-
# Use the wheel package directory
179-
with open(package.wheel_path, "rb") as fp:
180-
whl = fp.read()
181-
wheel_name = os.path.basename(package.wheel_path)
182-
183-
filename = os.path.join(tmpdir, wheel_name)
184-
with open(filename, "wb") as fp:
185-
fp.write(whl)
186-
187-
additional_paths.append(filename)
156+
tmpdir_path = Path(tmpdir)
157+
with _get_pip_whl_path_ctx() as bundled_wheel_path:
158+
tmp_wheel_path = tmpdir_path / bundled_wheel_path.name
159+
copy2(bundled_wheel_path, tmp_wheel_path)
188160

189161
# Construct the arguments to be passed to the pip command
190162
args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir]
@@ -197,7 +169,8 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
197169
if verbosity:
198170
args += ["-" + "v" * verbosity]
199171

200-
return _run_pip([*args, *_PACKAGE_NAMES], additional_paths)
172+
return _run_pip([*args, "pip"], [os.fsdecode(tmp_wheel_path)])
173+
201174

202175
def _uninstall_helper(*, verbosity=0):
203176
"""Helper to support a clean default uninstall process on Windows
@@ -227,7 +200,7 @@ def _uninstall_helper(*, verbosity=0):
227200
if verbosity:
228201
args += ["-" + "v" * verbosity]
229202

230-
return _run_pip([*args, *reversed(_PACKAGE_NAMES)])
203+
return _run_pip([*args, "pip"])
231204

232205

233206
def _main(argv=None):
Binary file not shown.
Binary file not shown.

Lib/test/test_ensurepip.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import test.support
77
import unittest
88
import unittest.mock
9+
from importlib.resources.abc import Traversable
10+
from pathlib import Path
911

1012
import ensurepip
1113
import ensurepip._uninstall
@@ -20,41 +22,35 @@ def test_version(self):
2022
# Test version()
2123
with tempfile.TemporaryDirectory() as tmpdir:
2224
self.touch(tmpdir, "pip-1.2.3b1-py2.py3-none-any.whl")
23-
with (unittest.mock.patch.object(ensurepip, '_PACKAGES', None),
24-
unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)):
25+
with unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', Path(tmpdir)):
2526
self.assertEqual(ensurepip.version(), '1.2.3b1')
2627

27-
def test_get_packages_no_dir(self):
28-
# Test _get_packages() without a wheel package directory
29-
with (unittest.mock.patch.object(ensurepip, '_PACKAGES', None),
30-
unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', None)):
31-
packages = ensurepip._get_packages()
32-
33-
# when bundled wheel packages are used, we get _PIP_VERSION
28+
def test_version_no_dir(self):
29+
# Test version() without a wheel package directory
30+
with unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', None):
31+
# when the bundled pip wheel is used, we get _PIP_VERSION
3432
self.assertEqual(ensurepip._PIP_VERSION, ensurepip.version())
3533

36-
# use bundled wheel packages
37-
self.assertIsNotNone(packages['pip'].wheel_name)
34+
def test_selected_wheel_path_no_dir(self):
35+
pip_filename = f'pip-{ensurepip._PIP_VERSION}-py3-none-any.whl'
36+
with unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', None):
37+
with ensurepip._get_pip_whl_path_ctx() as bundled_wheel_path:
38+
self.assertEqual(pip_filename, bundled_wheel_path.name)
3839

39-
def test_get_packages_with_dir(self):
40-
# Test _get_packages() with a wheel package directory
40+
def test_selected_wheel_path_with_dir(self):
41+
# Test _get_pip_whl_path_ctx() with a wheel package directory
4142
pip_filename = "pip-20.2.2-py2.py3-none-any.whl"
4243

4344
with tempfile.TemporaryDirectory() as tmpdir:
4445
self.touch(tmpdir, pip_filename)
45-
# not used, make sure that it's ignored
46+
# not used, make sure that they're ignored
47+
self.touch(tmpdir, "pip-1.2.3-py2.py3-none-any.whl")
4648
self.touch(tmpdir, "wheel-0.34.2-py2.py3-none-any.whl")
49+
self.touch(tmpdir, "pip-script.py")
4750

48-
with (unittest.mock.patch.object(ensurepip, '_PACKAGES', None),
49-
unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)):
50-
packages = ensurepip._get_packages()
51-
52-
self.assertEqual(packages['pip'].version, '20.2.2')
53-
self.assertEqual(packages['pip'].wheel_path,
54-
os.path.join(tmpdir, pip_filename))
55-
56-
# wheel package is ignored
57-
self.assertEqual(sorted(packages), ['pip'])
51+
with unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', Path(tmpdir)):
52+
with ensurepip._get_pip_whl_path_ctx() as bundled_wheel_path:
53+
self.assertEqual(pip_filename, bundled_wheel_path.name)
5854

5955

6056
class EnsurepipMixin:
@@ -69,7 +65,7 @@ def setUp(self):
6965
real_devnull = os.devnull
7066
os_patch = unittest.mock.patch("ensurepip.os")
7167
patched_os = os_patch.start()
72-
# But expose os.listdir() used by _find_packages()
68+
# But expose os.listdir() used by _find_wheel_pkg_dir_pip()
7369
patched_os.listdir = os.listdir
7470
self.addCleanup(os_patch.stop)
7571
patched_os.devnull = real_devnull

0 commit comments

Comments
 (0)
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