Skip to content

Commit 4c45c64

Browse files
committed
Merge branch 'main' into locations-distutils-cfg-warning
2 parents dac6068 + 0a05d76 commit 4c45c64

21 files changed

+468
-367
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ jobs:
3030
tests:
3131
# Anything that's touching testable stuff
3232
- ".github/workflows/ci.yml"
33-
- "tools/requirements/tests.txt"
3433
- "src/**"
3534
- "tests/**"
3635
if: github.event_name == 'pull_request'

.pre-commit-config.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ repos:
2626
^src/pip/_internal/index|
2727
^src/pip/_internal/models|
2828
^src/pip/_internal/operations|
29-
^src/pip/_internal/req|
3029
^src/pip/_internal/vcs|
3130
^src/pip/_internal/\w+\.py$|
3231
# Tests

.readthedocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ sphinx:
77
python:
88
version: 3.8
99
install:
10-
- requirements: tools/requirements/docs.txt
10+
- requirements: docs/requirements.txt

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ recursive-include src/pip/_vendor *LICENSE*
1010
recursive-include src/pip/_vendor *COPYING*
1111

1212
include docs/docutils.conf
13+
include docs/requirements.txt
1314

1415
exclude .coveragerc
1516
exclude .mailmap
File renamed without changes.

news/10165.trivial.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add a ``feature_flag`` optional kwarg to the ``deprecated()`` function
2+
``pip._internal.utils.deprecation:deprecated``. Also formulate a corresponding canned
3+
message which suggests using the ``--use-feature={feature_flag}`` to test upcoming
4+
behavior.

noxfile.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
"protected-pip": "tools/tox_pip.py",
2525
}
2626
REQUIREMENTS = {
27-
"docs": "tools/requirements/docs.txt",
28-
"tests": "tools/requirements/tests.txt",
29-
"common-wheels": "tools/requirements/tests-common_wheels.txt",
27+
"docs": "docs/requirements.txt",
28+
"tests": "tests/requirements.txt",
29+
"common-wheels": "tests/requirements-common_wheels.txt",
3030
}
3131

3232
AUTHORS_FILE = "AUTHORS.txt"

src/pip/_internal/locations/__init__.py

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
import pathlib
55
import sys
66
import sysconfig
7-
from typing import List, Optional
7+
from typing import Dict, Iterator, List, Optional, Tuple
88

99
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
10+
from pip._internal.utils.compat import WINDOWS
1011
from pip._internal.utils.deprecation import deprecated
1112

1213
from . import _distutils, _sysconfig
@@ -42,6 +43,53 @@
4243
_MISMATCH_LEVEL = logging.WARNING
4344

4445

46+
def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool:
47+
platlib = scheme["platlib"]
48+
if "/lib64/" not in platlib:
49+
return False
50+
unpatched = platlib.replace("/lib64/", "/lib/")
51+
return unpatched.replace("$platbase/", "$base/") == scheme["purelib"]
52+
53+
54+
@functools.lru_cache(maxsize=None)
55+
def _looks_like_red_hat_patched() -> bool:
56+
"""Red Hat patches platlib in unix_prefix and unix_home, but not purelib.
57+
58+
This is the only way I can see to tell a Red Hat-patched Python.
59+
"""
60+
from distutils.command.install import INSTALL_SCHEMES # type: ignore
61+
62+
return all(
63+
k in INSTALL_SCHEMES
64+
and _looks_like_red_hat_patched_platlib_purelib(INSTALL_SCHEMES[k])
65+
for k in ("unix_prefix", "unix_home")
66+
)
67+
68+
69+
@functools.lru_cache(maxsize=None)
70+
def _looks_like_debian_patched() -> bool:
71+
"""Debian adds two additional schemes."""
72+
from distutils.command.install import INSTALL_SCHEMES # type: ignore
73+
74+
return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES
75+
76+
77+
def _fix_abiflags(parts: Tuple[str]) -> Iterator[str]:
78+
ldversion = sysconfig.get_config_var("LDVERSION")
79+
abiflags: str = getattr(sys, "abiflags", None)
80+
81+
# LDVERSION does not end with sys.abiflags. Just return the path unchanged.
82+
if not ldversion or not abiflags or not ldversion.endswith(abiflags):
83+
yield from parts
84+
return
85+
86+
# Strip sys.abiflags from LDVERSION-based path components.
87+
for part in parts:
88+
if part.endswith(ldversion):
89+
part = part[: (0 - len(abiflags))]
90+
yield part
91+
92+
4593
def _default_base(*, user: bool) -> str:
4694
if user:
4795
base = sysconfig.get_config_var("userbase")
@@ -145,12 +193,42 @@ def get_scheme(
145193
user
146194
and is_osx_framework()
147195
and k == "headers"
148-
and old_v.parent == new_v
149-
and old_v.name.startswith("python")
196+
and old_v.parent.parent == new_v.parent
197+
and old_v.parent.name.startswith("python")
150198
)
151199
if skip_osx_framework_user_special_case:
152200
continue
153201

202+
# On Red Hat and derived Linux distributions, distutils is patched to
203+
# use "lib64" instead of "lib" for platlib.
204+
if k == "platlib" and _looks_like_red_hat_patched():
205+
continue
206+
207+
# Both Debian and Red Hat patch Python to place the system site under
208+
# /usr/local instead of /usr. Debian also places lib in dist-packages
209+
# instead of site-packages, but the /usr/local check should cover it.
210+
skip_linux_system_special_case = (
211+
not (user or home or prefix)
212+
and old_v.parts[1:3] == ("usr", "local")
213+
and len(new_v.parts) > 1
214+
and new_v.parts[1] == "usr"
215+
and (len(new_v.parts) < 3 or new_v.parts[2] != "local")
216+
and (_looks_like_red_hat_patched() or _looks_like_debian_patched())
217+
)
218+
if skip_linux_system_special_case:
219+
continue
220+
221+
# On Python 3.7 and earlier, sysconfig does not include sys.abiflags in
222+
# the "pythonX.Y" part of the path, but distutils does.
223+
skip_sysconfig_abiflag_bug = (
224+
sys.version_info < (3, 8)
225+
and not WINDOWS
226+
and k in ("headers", "platlib", "purelib")
227+
and tuple(_fix_abiflags(old_v.parts)) == new_v.parts
228+
)
229+
if skip_sysconfig_abiflag_bug:
230+
continue
231+
154232
warning_contexts.append((old_v, new_v, f"scheme.{k}"))
155233

156234
if not warning_contexts:

src/pip/_internal/locations/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import functools
12
import os
23
import site
34
import sys
@@ -46,5 +47,6 @@ def get_src_prefix() -> str:
4647
user_site = site.USER_SITE
4748

4849

50+
@functools.lru_cache(maxsize=None)
4951
def is_osx_framework() -> bool:
5052
return bool(sysconfig.get_config_var("PYTHONFRAMEWORK"))

src/pip/_internal/req/__init__.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
from .req_set import RequirementSet
1010

1111
__all__ = [
12-
"RequirementSet", "InstallRequirement",
13-
"parse_requirements", "install_given_reqs",
12+
"RequirementSet",
13+
"InstallRequirement",
14+
"parse_requirements",
15+
"install_given_reqs",
1416
]
1517

1618
logger = logging.getLogger(__name__)
@@ -52,20 +54,18 @@ def install_given_reqs(
5254

5355
if to_install:
5456
logger.info(
55-
'Installing collected packages: %s',
56-
', '.join(to_install.keys()),
57+
"Installing collected packages: %s",
58+
", ".join(to_install.keys()),
5759
)
5860

5961
installed = []
6062

6163
with indent_log():
6264
for req_name, requirement in to_install.items():
6365
if requirement.should_reinstall:
64-
logger.info('Attempting uninstall: %s', req_name)
66+
logger.info("Attempting uninstall: %s", req_name)
6567
with indent_log():
66-
uninstalled_pathset = requirement.uninstall(
67-
auto_confirm=True
68-
)
68+
uninstalled_pathset = requirement.uninstall(auto_confirm=True)
6969
else:
7070
uninstalled_pathset = None
7171

0 commit comments

Comments
 (0)