From 41a844263c4d687903982f3ced14ba8e8da246f8 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sun, 1 Aug 2021 18:00:02 +0800 Subject: [PATCH] Use posix_prefix for Apple's system Python --- src/pip/_internal/locations/_sysconfig.py | 39 ++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/locations/_sysconfig.py b/src/pip/_internal/locations/_sysconfig.py index 86dbee7e954..5e141aa1be7 100644 --- a/src/pip/_internal/locations/_sysconfig.py +++ b/src/pip/_internal/locations/_sysconfig.py @@ -15,8 +15,8 @@ # 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 +# Unfortunately ``get_default_scheme()`` didn't exist before 3.10, 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 @@ -27,6 +27,32 @@ _PREFERRED_SCHEME_API = getattr(sysconfig, "get_preferred_scheme", None) +def _should_use_osx_framework_prefix() -> bool: + """Check for Apple's ``osx_framework_library`` scheme. + + Python distributed by Apple's Command Line Tools has this special scheme + that's used when: + + * This is a framework build. + * We are installing into the system prefix. + + This does not account for ``pip install --prefix`` (also means we're not + installing to the system prefix), which should use ``posix_prefix``, but + logic here means ``_infer_prefix()`` outputs ``osx_framework_library``. But + since ``prefix`` is not available for ``sysconfig.get_default_scheme()``, + which is the stdlib replacement for ``_infer_prefix()``, presumably Apple + wouldn't be able to magically switch between ``osx_framework_library`` and + ``posix_prefix``. ``_infer_prefix()`` returning ``osx_framework_library`` + means its behavior is consistent whether we use the stdlib implementation + or our own, and we deal with this special case in ``get_scheme()`` instead. + """ + return ( + "osx_framework_library" in _AVAILABLE_SCHEMES + and not running_under_virtualenv() + and is_osx_framework() + ) + + def _infer_prefix() -> str: """Try to find a prefix scheme for the current platform. @@ -43,8 +69,7 @@ def _infer_prefix() -> str: """ if _PREFERRED_SCHEME_API: return _PREFERRED_SCHEME_API("prefix") - os_framework_global = is_osx_framework() and not running_under_virtualenv() - if os_framework_global and "osx_framework_library" in _AVAILABLE_SCHEMES: + if _should_use_osx_framework_prefix(): return "osx_framework_library" implementation_suffixed = f"{sys.implementation.name}_{os.name}" if implementation_suffixed in _AVAILABLE_SCHEMES: @@ -130,6 +155,12 @@ def get_scheme( else: scheme_name = _infer_prefix() + # Special case: When installing into a custom prefix, use posix_prefix + # instead of osx_framework_library. See _should_use_osx_framework_prefix() + # docstring for details. + if prefix is not None and scheme_name == "osx_framework_library": + scheme_name = "posix_prefix" + if home is not None: variables = {k: home for k in _HOME_KEYS} elif prefix is not None: