6
6
import site
7
7
import sys
8
8
import sysconfig
9
- from pathlib import Path
10
9
from shutil import which
11
10
12
11
# The `pkg_resources` module is provided by `setuptools`, which is itself a
@@ -50,11 +49,40 @@ def create(self):
50
49
self ._working_set = None
51
50
call (* self .virtualenv , self .path )
52
51
52
+ def get_paths (self ):
53
+ """Wrapper around sysconfig.get_paths(), returning the appropriate paths for the env."""
54
+ if "venv" in sysconfig .get_scheme_names ():
55
+ # This should always be used on Python 3.11 and above.
56
+ scheme = "venv"
57
+ elif os .name == "nt" :
58
+ # This matches nt_venv, unless sysconfig has been modified.
59
+ scheme = "nt"
60
+ elif os .name == "posix" :
61
+ # This matches posix_venv, unless sysconfig has been modified.
62
+ scheme = "posix_prefix"
63
+ elif sys .version_info >= (3 , 10 ):
64
+ # Using the default scheme is somewhat fragile, as various Python
65
+ # distributors (e.g., what Debian and Fedora package, and what Xcode
66
+ # includes) change the default scheme away from the upstream
67
+ # defaults, but it's about as good as we can do.
68
+ scheme = sysconfig .get_default_scheme ()
69
+ else :
70
+ # This is explicitly documented as having previously existed in the 3.10
71
+ # docs, and has existed since CPython 2.7 and 3.1 (but not 3.0).
72
+ scheme = sysconfig ._get_default_scheme ()
73
+
74
+ vars = {
75
+ "base" : self .path ,
76
+ "platbase" : self .path ,
77
+ "installed_base" : self .path ,
78
+ "installed_platbase" : self .path ,
79
+ }
80
+
81
+ return sysconfig .get_paths (scheme , vars )
82
+
53
83
@property
54
84
def bin_path (self ):
55
- if sys .platform in ("win32" , "cygwin" ):
56
- return os .path .join (self .path , "Scripts" )
57
- return os .path .join (self .path , "bin" )
85
+ return self .get_paths ()["scripts" ]
58
86
59
87
@property
60
88
def pip_path (self ):
@@ -67,24 +95,10 @@ def pip_path(self):
67
95
68
96
@property
69
97
def lib_path (self ):
70
- base = self .path
71
-
72
- # this block is literally taken from virtualenv 16.4.3
73
- IS_PYPY = hasattr (sys , "pypy_version_info" )
74
- IS_JYTHON = sys .platform .startswith ("java" )
75
- if IS_JYTHON :
76
- site_packages = os .path .join (base , "Lib" , "site-packages" )
77
- elif IS_PYPY :
78
- site_packages = os .path .join (base , "site-packages" )
79
- else :
80
- IS_WIN = sys .platform == "win32"
81
- if IS_WIN :
82
- site_packages = os .path .join (base , "Lib" , "site-packages" )
83
- else :
84
- version = f"{ sys .version_info .major } .{ sys .version_info .minor } "
85
- site_packages = os .path .join (base , "lib" , f"python{ version } " , "site-packages" )
86
-
87
- return site_packages
98
+ # We always return platlib here, even if it differs to purelib, because we can
99
+ # always install pure-Python code into the platlib safely too. It's also very
100
+ # unlikely to differ for a venv.
101
+ return self .get_paths ()["platlib" ]
88
102
89
103
@property
90
104
def working_set (self ):
@@ -97,43 +111,35 @@ def working_set(self):
97
111
return self ._working_set
98
112
99
113
def activate (self ):
100
- if sys .platform == ' darwin' :
114
+ if sys .platform == " darwin" :
101
115
# The default Python on macOS sets a __PYVENV_LAUNCHER__ environment
102
116
# variable which affects invocation of python (e.g. via pip) in a
103
117
# virtualenv. Unset it if present to avoid this. More background:
104
118
# https://github.com/web-platform-tests/wpt/issues/27377
105
119
# https://github.com/python/cpython/pull/9516
106
- os .environ .pop ('__PYVENV_LAUNCHER__' , None )
120
+ os .environ .pop ("__PYVENV_LAUNCHER__" , None )
121
+
122
+ paths = self .get_paths ()
107
123
108
124
# Setup the path and site packages as if we'd launched with the virtualenv active
109
- bin_dir = os . path . join ( self . path , "bin" )
125
+ bin_dir = paths [ "scripts" ]
110
126
os .environ ["PATH" ] = os .pathsep .join ([bin_dir ] + os .environ .get ("PATH" , "" ).split (os .pathsep ))
127
+
128
+ # While not required (`./venv/bin/python3` won't set it, but
129
+ # `source ./venv/bin/activate && python3` will), we have historically set this.
111
130
os .environ ["VIRTUAL_ENV" ] = self .path
112
131
113
132
prev_length = len (sys .path )
114
133
115
- schemes = sysconfig .get_scheme_names ()
116
- if "venv" in schemes :
117
- scheme = "venv"
118
- else :
119
- scheme = "nt" if os .name == "nt" else "posix_user"
120
- sys_paths = sysconfig .get_paths (scheme )
121
- data_path = sys_paths ["data" ]
122
- added = set ()
123
134
# Add the venv library paths as sitedirs.
124
- # This converts system paths like /usr/local/lib/python3.10/site-packages
125
- # to venv-relative paths like {self.path}/lib/python3.10/site-packages and adds
126
- # those paths as site dirs to be used for module import.
127
135
for key in ["purelib" , "platlib" ]:
128
- host_path = Path (sys_paths [key ])
129
- relative_path = host_path .relative_to (data_path )
130
- site_dir = os .path .normpath (os .path .normcase (Path (self .path ) / relative_path ))
131
- if site_dir not in added :
132
- site .addsitedir (site_dir )
133
- added .add (site_dir )
136
+ site .addsitedir (paths [key ])
137
+
138
+ # Rearrange the path
134
139
sys .path [:] = sys .path [prev_length :] + sys .path [0 :prev_length ]
135
140
136
- sys .real_prefix = sys .prefix
141
+ # Change prefixes, similar to what initconfig/site does for venvs.
142
+ sys .exec_prefix = self .path
137
143
sys .prefix = self .path
138
144
139
145
def start (self ):
0 commit comments