Skip to content

Commit

Permalink
Split scheme inference functions for clarity
Browse files Browse the repository at this point in the history
This also helps catch bugs in the logic, which are also fixed in this
commit.
  • Loading branch information
uranusjr committed Feb 23, 2021
1 parent 0c4bd55 commit a0a3bde
Showing 1 changed file with 35 additions and 24 deletions.
59 changes: 35 additions & 24 deletions src/pip/_internal/locations/_sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,46 @@
logger = logging.getLogger(__name__)


_AVAILABLE_SCHEMES = set(sysconfig.get_scheme_names())
# Notes on _infer_* functions.
# Unfortunately ``_get_default_scheme()`` is private, so there's no way to
# ask things like "what is the '_prefix' scheme on this platform". These
# functions try to answer that with some heuristics while accounting for ad-hoc
# platforms not covered by CPython's default sysconfig implementation. If the
# ad-hoc implementation does not fully implement sysconfig, we'll fall back to
# a POSIX scheme.

_AVAILABLE_SCHEMES = set(sysconfig.get_scheme_names())

def _infer_scheme(variant):
# type: (typing.Literal["home", "prefix", "user"]) -> str
"""Try to find a scheme for the current platform.

Unfortunately ``_get_default_scheme()`` is private, so there's no way to
ask things like "what is the '_home' scheme on this platform". This tries
to answer that with some heuristics while accounting for ad-hoc platforms
not covered by CPython's default sysconfig implementation.
"""
# Most schemes are named like this e.g. "posix_home", "nt_user".
suffixed = f"{os.name}_{variant}"
def _infer_prefix():
# type: () -> str
"""Try to find a prefix scheme for the current platform."""
suffixed = f"{os.name}_prefix"
if suffixed in _AVAILABLE_SCHEMES:
return suffixed
if os.name in _AVAILABLE_SCHEMES: # On Windows, prefx is just called "nt".
return os.name
return "posix_prefix"


# The user scheme is not available.
if variant == "user" and sysconfig.get_config_var("userbase") is None:
def _infer_user():
# type: () -> str
"""Try to find a user scheme for the current platform."""
suffixed = f"{os.name}_user"
if suffixed in _AVAILABLE_SCHEMES:
return suffixed
if "posix_user" not in _AVAILABLE_SCHEMES: # User scheme unavailable.
raise UserInstallationInvalid()
return "posix_user"

# On Windows, prefx and home schemes are the same and just called "nt".
if os.name in _AVAILABLE_SCHEMES:
return os.name

# Not sure what's happening, some obscure platform that does not fully
# implement sysconfig? Just use the POSIX scheme.
logger.warning("No %r scheme for %r; fallback to POSIX.", variant, os.name)
return f"posix_{variant}"
def _infer_home():
# type: () -> str
"""Try to find a home for the current platform."""
suffixed = f"{os.name}_home"
if suffixed in _AVAILABLE_SCHEMES:
return suffixed
return "posix_home"


# Update these keys if the user sets a custom home.
Expand Down Expand Up @@ -86,11 +97,11 @@ def get_scheme(
raise InvalidSchemeCombination("--home", "--prefix")

if home is not None:
scheme_name = _infer_scheme("home")
scheme_name = _infer_home()
elif user:
scheme_name = _infer_scheme("user")
scheme_name = _infer_user()
else:
scheme_name = _infer_scheme("prefix")
scheme_name = _infer_prefix()

if home is not None:
variables = {k: home for k in _HOME_KEYS}
Expand Down Expand Up @@ -136,7 +147,7 @@ def get_bin_prefix():
# Forcing to use /usr/local/bin for standard macOS framework installs.
if sys.platform[:6] == "darwin" and sys.prefix[:16] == "/System/Library/":
return "/usr/local/bin"
return sysconfig.get_paths(scheme=_infer_scheme("prefix"))["scripts"]
return sysconfig.get_paths()["scripts"]


def get_purelib():
Expand Down

0 comments on commit a0a3bde

Please sign in to comment.