4
4
import pathlib
5
5
import sys
6
6
import sysconfig
7
- from typing import Dict , Iterator , List , Optional , Tuple
7
+ from typing import Any , Dict , Iterator , List , Optional , Tuple
8
8
9
9
from pip ._internal .models .scheme import SCHEME_KEYS , Scheme
10
10
from pip ._internal .utils .compat import WINDOWS
11
11
from pip ._internal .utils .deprecation import deprecated
12
+ from pip ._internal .utils .virtualenv import running_under_virtualenv
12
13
13
14
from . import _distutils , _sysconfig
14
15
from .base import (
@@ -52,7 +53,7 @@ def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool:
52
53
53
54
54
55
@functools .lru_cache (maxsize = None )
55
- def _looks_like_red_hat_patched () -> bool :
56
+ def _looks_like_red_hat_lib () -> bool :
56
57
"""Red Hat patches platlib in unix_prefix and unix_home, but not purelib.
57
58
58
59
This is the only way I can see to tell a Red Hat-patched Python.
@@ -67,13 +68,33 @@ def _looks_like_red_hat_patched() -> bool:
67
68
68
69
69
70
@functools .lru_cache (maxsize = None )
70
- def _looks_like_debian_patched () -> bool :
71
+ def _looks_like_debian_scheme () -> bool :
71
72
"""Debian adds two additional schemes."""
72
73
from distutils .command .install import INSTALL_SCHEMES # type: ignore
73
74
74
75
return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES
75
76
76
77
78
+ @functools .lru_cache (maxsize = None )
79
+ def _looks_like_red_hat_scheme () -> bool :
80
+ """Red Hat patches ``sys.prefix`` and ``sys.exec_prefix``.
81
+
82
+ Red Hat's ``00251-change-user-install-location.patch`` changes the install
83
+ command's ``prefix`` and ``exec_prefix`` to append ``"/local"``. This is
84
+ (fortunately?) done quite unconditionally, so we create a default command
85
+ object without any configuration to detect this.
86
+ """
87
+ from distutils .command .install import install
88
+ from distutils .dist import Distribution
89
+
90
+ cmd : Any = install (Distribution ())
91
+ cmd .finalize_options ()
92
+ return (
93
+ cmd .exec_prefix == f"{ os .path .normpath (sys .exec_prefix )} /local"
94
+ and cmd .prefix == f"{ os .path .normpath (sys .prefix )} /local"
95
+ )
96
+
97
+
77
98
def _fix_abiflags (parts : Tuple [str ]) -> Iterator [str ]:
78
99
ldversion = sysconfig .get_config_var ("LDVERSION" )
79
100
abiflags : str = getattr (sys , "abiflags" , None )
@@ -201,19 +222,19 @@ def get_scheme(
201
222
202
223
# On Red Hat and derived Linux distributions, distutils is patched to
203
224
# use "lib64" instead of "lib" for platlib.
204
- if k == "platlib" and _looks_like_red_hat_patched ():
225
+ if k == "platlib" and _looks_like_red_hat_lib ():
205
226
continue
206
227
207
228
# Both Debian and Red Hat patch Python to place the system site under
208
229
# /usr/local instead of /usr. Debian also places lib in dist-packages
209
230
# instead of site-packages, but the /usr/local check should cover it.
210
231
skip_linux_system_special_case = (
211
- not (user or home or prefix )
232
+ not (user or home or prefix or running_under_virtualenv () )
212
233
and old_v .parts [1 :3 ] == ("usr" , "local" )
213
234
and len (new_v .parts ) > 1
214
235
and new_v .parts [1 ] == "usr"
215
236
and (len (new_v .parts ) < 3 or new_v .parts [2 ] != "local" )
216
- and (_looks_like_red_hat_patched () or _looks_like_debian_patched ())
237
+ and (_looks_like_red_hat_scheme () or _looks_like_debian_scheme ())
217
238
)
218
239
if skip_linux_system_special_case :
219
240
continue
0 commit comments