Skip to content

Post a deprecation warning for distutils configs #10218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions src/pip/_internal/locations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from pip._internal.models.scheme import SCHEME_KEYS, Scheme
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.deprecation import deprecated

from . import _distutils, _sysconfig
from .base import (
Expand Down Expand Up @@ -99,16 +100,20 @@ def _default_base(*, user: bool) -> str:


@functools.lru_cache(maxsize=None)
def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool:
if old == new:
return False
def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None:
issue_url = "https://github.com/pypa/pip/issues/10151"
message = (
"Value for %s does not match. Please report this to <%s>"
"\ndistutils: %s"
"\nsysconfig: %s"
)
logger.log(_MISMATCH_LEVEL, message, key, issue_url, old, new)


def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool:
if old == new:
return False
_warn_mismatched(old, new, key=key)
return True


Expand Down Expand Up @@ -157,12 +162,15 @@ def get_scheme(
)

base = prefix or home or _default_base(user=user)
warned = []
warning_contexts = []
for k in SCHEME_KEYS:
# Extra join because distutils can return relative paths.
old_v = pathlib.Path(base, getattr(old, k))
new_v = pathlib.Path(getattr(new, k))

if old_v == new_v:
continue

# distutils incorrectly put PyPy packages under ``site-packages/python``
# in the ``posix_home`` scheme, but PyPy devs said they expect the
# directory name to be ``pypy`` instead. So we treat this as a bug fix
Expand Down Expand Up @@ -221,10 +229,38 @@ def get_scheme(
if skip_sysconfig_abiflag_bug:
continue

warned.append(_warn_if_mismatch(old_v, new_v, key=f"scheme.{k}"))
warning_contexts.append((old_v, new_v, f"scheme.{k}"))

if any(warned):
_log_context(user=user, home=home, root=root, prefix=prefix)
if not warning_contexts:
return old

# Check if this path mismatch is caused by distutils config files. Those
# files will no longer work once we switch to sysconfig, so this raises a
# deprecation message for them.
default_old = _distutils.distutils_scheme(
dist_name,
user,
home,
root,
isolated,
prefix,
ignore_config_files=True,
)
if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS):
deprecated(
"Configuring installation scheme with distutils config files "
"is deprecated and will no longer work in the near future. If you "
"are using a Homebrew or Linuxbrew Python, please see discussion "
"at https://github.com/Homebrew/homebrew-core/issues/76621",
replacement=None,
gone_in=None,
)
return old

# Post warnings about this mismatch so user can report them back.
for old_v, new_v, key in warning_contexts:
_warn_mismatched(old_v, new_v, key=key)
_log_context(user=user, home=home, root=root, prefix=prefix)

return old

Expand Down
25 changes: 14 additions & 11 deletions src/pip/_internal/locations/_distutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
logger = logging.getLogger(__name__)


def _distutils_scheme(
def distutils_scheme(
dist_name: str,
user: bool = False,
home: str = None,
root: str = None,
isolated: bool = False,
prefix: str = None,
*,
ignore_config_files: bool = False,
) -> Dict[str, str]:
"""
Return a distutils install scheme
Expand All @@ -39,15 +41,16 @@ def _distutils_scheme(
dist_args["script_args"] = ["--no-user-cfg"]

d = Distribution(dist_args)
try:
d.parse_config_files()
except UnicodeDecodeError:
# Typeshed does not include find_config_files() for some reason.
paths = d.find_config_files() # type: ignore
logger.warning(
"Ignore distutils configs in %s due to encoding errors.",
", ".join(os.path.basename(p) for p in paths),
)
if not ignore_config_files:
try:
d.parse_config_files()
except UnicodeDecodeError:
# Typeshed does not include find_config_files() for some reason.
paths = d.find_config_files() # type: ignore
logger.warning(
"Ignore distutils configs in %s due to encoding errors.",
", ".join(os.path.basename(p) for p in paths),
)
obj: Optional[DistutilsCommand] = None
obj = d.get_command_obj("install", create=True)
assert obj is not None
Expand Down Expand Up @@ -121,7 +124,7 @@ def get_scheme(
:param prefix: indicates to use the "prefix" scheme and provides the
base directory for the same
"""
scheme = _distutils_scheme(dist_name, user, home, root, isolated, prefix)
scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix)
return Scheme(
platlib=scheme["platlib"],
purelib=scheme["purelib"],
Expand Down