Skip to content

Kill location warning on Debian and Red Hat system Python #10217

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 29, 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
80 changes: 79 additions & 1 deletion src/pip/_internal/locations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import pathlib
import sys
import sysconfig
from typing import List, Optional
from typing import Dict, Iterator, List, Optional, Tuple

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

from . import _distutils, _sysconfig
from .base import (
Expand Down Expand Up @@ -41,6 +42,53 @@
_MISMATCH_LEVEL = logging.WARNING


def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool:
platlib = scheme["platlib"]
if "/lib64/" not in platlib:
return False
unpatched = platlib.replace("/lib64/", "/lib/")
return unpatched.replace("$platbase/", "$base/") == scheme["purelib"]


@functools.lru_cache(maxsize=None)
def _looks_like_red_hat_patched() -> bool:
"""Red Hat patches platlib in unix_prefix and unix_home, but not purelib.

This is the only way I can see to tell a Red Hat-patched Python.
"""
from distutils.command.install import INSTALL_SCHEMES # type: ignore

return all(
k in INSTALL_SCHEMES
and _looks_like_red_hat_patched_platlib_purelib(INSTALL_SCHEMES[k])
for k in ("unix_prefix", "unix_home")
)


@functools.lru_cache(maxsize=None)
def _looks_like_debian_patched() -> bool:
"""Debian adds two additional schemes."""
from distutils.command.install import INSTALL_SCHEMES # type: ignore

return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES


def _fix_abiflags(parts: Tuple[str]) -> Iterator[str]:
ldversion = sysconfig.get_config_var("LDVERSION")
abiflags: str = getattr(sys, "abiflags", None)

# LDVERSION does not end with sys.abiflags. Just return the path unchanged.
if not ldversion or not abiflags or not ldversion.endswith(abiflags):
yield from parts
return

# Strip sys.abiflags from LDVERSION-based path components.
for part in parts:
if part.endswith(ldversion):
part = part[: (0 - len(abiflags))]
yield part


def _default_base(*, user: bool) -> str:
if user:
base = sysconfig.get_config_var("userbase")
Expand Down Expand Up @@ -143,6 +191,36 @@ def get_scheme(
if skip_osx_framework_user_special_case:
continue

# On Red Hat and derived Linux distributions, distutils is patched to
# use "lib64" instead of "lib" for platlib.
if k == "platlib" and _looks_like_red_hat_patched():
continue

# Both Debian and Red Hat patch Python to place the system site under
# /usr/local instead of /usr. Debian also places lib in dist-packages
# instead of site-packages, but the /usr/local check should cover it.
skip_linux_system_special_case = (
not (user or home or prefix)
and old_v.parts[1:3] == ("usr", "local")
and len(new_v.parts) > 1
and new_v.parts[1] == "usr"
and (len(new_v.parts) < 3 or new_v.parts[2] != "local")
and (_looks_like_red_hat_patched() or _looks_like_debian_patched())
)
if skip_linux_system_special_case:
continue

# On Python 3.7 and earlier, sysconfig does not include sys.abiflags in
# the "pythonX.Y" part of the path, but distutils does.
skip_sysconfig_abiflag_bug = (
sys.version_info < (3, 8)
and not WINDOWS
and k in ("headers", "platlib", "purelib")
and tuple(_fix_abiflags(old_v.parts)) == new_v.parts
)
if skip_sysconfig_abiflag_bug:
continue

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

if any(warned):
Expand Down
2 changes: 2 additions & 0 deletions src/pip/_internal/locations/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import functools
import os
import site
import sys
Expand Down Expand Up @@ -46,5 +47,6 @@ def get_src_prefix() -> str:
user_site = site.USER_SITE


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