Skip to content

Commit dac6068

Browse files
committed
Post a deprecation warning for distutils configs
Since we can't do anything about them in the transition (CPython is dropping support for those entirely), there's nothing we can do but to tell users to not use them. This also accounts for Homebrew and Linuxbrew for now. Hopefully they will come up with better solutions that don't trigger the location mismatch warning.
1 parent a53f888 commit dac6068

File tree

2 files changed

+57
-18
lines changed

2 files changed

+57
-18
lines changed

src/pip/_internal/locations/__init__.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import List, Optional
88

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

1112
from . import _distutils, _sysconfig
1213
from .base import (
@@ -51,16 +52,20 @@ def _default_base(*, user: bool) -> str:
5152

5253

5354
@functools.lru_cache(maxsize=None)
54-
def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool:
55-
if old == new:
56-
return False
55+
def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None:
5756
issue_url = "https://github.com/pypa/pip/issues/10151"
5857
message = (
5958
"Value for %s does not match. Please report this to <%s>"
6059
"\ndistutils: %s"
6160
"\nsysconfig: %s"
6261
)
6362
logger.log(_MISMATCH_LEVEL, message, key, issue_url, old, new)
63+
64+
65+
def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool:
66+
if old == new:
67+
return False
68+
_warn_mismatched(old, new, key=key)
6469
return True
6570

6671

@@ -109,12 +114,15 @@ def get_scheme(
109114
)
110115

111116
base = prefix or home or _default_base(user=user)
112-
warned = []
117+
warning_contexts = []
113118
for k in SCHEME_KEYS:
114119
# Extra join because distutils can return relative paths.
115120
old_v = pathlib.Path(base, getattr(old, k))
116121
new_v = pathlib.Path(getattr(new, k))
117122

123+
if old_v == new_v:
124+
continue
125+
118126
# distutils incorrectly put PyPy packages under ``site-packages/python``
119127
# in the ``posix_home`` scheme, but PyPy devs said they expect the
120128
# directory name to be ``pypy`` instead. So we treat this as a bug fix
@@ -143,10 +151,38 @@ def get_scheme(
143151
if skip_osx_framework_user_special_case:
144152
continue
145153

146-
warned.append(_warn_if_mismatch(old_v, new_v, key=f"scheme.{k}"))
154+
warning_contexts.append((old_v, new_v, f"scheme.{k}"))
147155

148-
if any(warned):
149-
_log_context(user=user, home=home, root=root, prefix=prefix)
156+
if not warning_contexts:
157+
return old
158+
159+
# Check if this path mismatch is caused by distutils config files. Those
160+
# files will no longer work once we switch to sysconfig, so this raises a
161+
# deprecation message for them.
162+
default_old = _distutils.distutils_scheme(
163+
dist_name,
164+
user,
165+
home,
166+
root,
167+
isolated,
168+
prefix,
169+
ignore_config_files=True,
170+
)
171+
if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS):
172+
deprecated(
173+
"Configuring installation scheme with distutils config files "
174+
"is deprecated and will no longer work in the near future. If you "
175+
"are using a Homebrew or Linuxbrew Python, please see discussion "
176+
"at https://github.com/Homebrew/homebrew-core/issues/76621",
177+
replacement=None,
178+
gone_in=None,
179+
)
180+
return old
181+
182+
# Post warnings about this mismatch so user can report them back.
183+
for old_v, new_v, key in warning_contexts:
184+
_warn_mismatched(old_v, new_v, key=key)
185+
_log_context(user=user, home=home, root=root, prefix=prefix)
150186

151187
return old
152188

src/pip/_internal/locations/_distutils.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
logger = logging.getLogger(__name__)
2222

2323

24-
def _distutils_scheme(
24+
def distutils_scheme(
2525
dist_name: str,
2626
user: bool = False,
2727
home: str = None,
2828
root: str = None,
2929
isolated: bool = False,
3030
prefix: str = None,
31+
*,
32+
ignore_config_files: bool = False,
3133
) -> Dict[str, str]:
3234
"""
3335
Return a distutils install scheme
@@ -39,15 +41,16 @@ def _distutils_scheme(
3941
dist_args["script_args"] = ["--no-user-cfg"]
4042

4143
d = Distribution(dist_args)
42-
try:
43-
d.parse_config_files()
44-
except UnicodeDecodeError:
45-
# Typeshed does not include find_config_files() for some reason.
46-
paths = d.find_config_files() # type: ignore
47-
logger.warning(
48-
"Ignore distutils configs in %s due to encoding errors.",
49-
", ".join(os.path.basename(p) for p in paths),
50-
)
44+
if not ignore_config_files:
45+
try:
46+
d.parse_config_files()
47+
except UnicodeDecodeError:
48+
# Typeshed does not include find_config_files() for some reason.
49+
paths = d.find_config_files() # type: ignore
50+
logger.warning(
51+
"Ignore distutils configs in %s due to encoding errors.",
52+
", ".join(os.path.basename(p) for p in paths),
53+
)
5154
obj: Optional[DistutilsCommand] = None
5255
obj = d.get_command_obj("install", create=True)
5356
assert obj is not None
@@ -121,7 +124,7 @@ def get_scheme(
121124
:param prefix: indicates to use the "prefix" scheme and provides the
122125
base directory for the same
123126
"""
124-
scheme = _distutils_scheme(dist_name, user, home, root, isolated, prefix)
127+
scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix)
125128
return Scheme(
126129
platlib=scheme["platlib"],
127130
purelib=scheme["purelib"],

0 commit comments

Comments
 (0)