1
1
import compileall
2
2
import os
3
3
import shutil
4
- import subprocess
5
- import sys
4
+ import sysconfig
6
5
import textwrap
7
6
import venv as _venv
8
7
from pathlib import Path
@@ -47,15 +46,16 @@ def __init__(
47
46
self ._create ()
48
47
49
48
def _update_paths (self ) -> None :
50
- home , lib , inc , bin = _virtualenv .path_locations (self .location )
51
- self .bin = Path (bin )
52
- self .site = Path (lib ) / "site-packages"
53
- # Workaround for https://github.com/pypa/virtualenv/issues/306
54
- if hasattr (sys , "pypy_version_info" ):
55
- version_dir = str (sys .version_info .major )
56
- self .lib = Path (home , "lib-python" , version_dir )
57
- else :
58
- self .lib = Path (lib )
49
+ bases = {
50
+ "installed_base" : self .location ,
51
+ "installed_platbase" : self .location ,
52
+ "base" : self .location ,
53
+ "platbase" : self .location ,
54
+ }
55
+ paths = sysconfig .get_paths (vars = bases )
56
+ self .bin = Path (paths ["scripts" ])
57
+ self .site = Path (paths ["purelib" ])
58
+ self .lib = Path (paths ["stdlib" ])
59
59
60
60
def __repr__ (self ) -> str :
61
61
return f"<VirtualEnvironment { self .location } >"
@@ -64,29 +64,21 @@ def _create(self, clear: bool = False) -> None:
64
64
if clear :
65
65
shutil .rmtree (self .location )
66
66
if self ._template :
67
- # On Windows, calling `_virtualenv.path_locations(target)`
68
- # will have created the `target` directory...
69
- if sys .platform == "win32" and self .location .exists ():
70
- self .location .rmdir ()
71
67
# Clone virtual environment from template.
72
68
shutil .copytree (self ._template .location , self .location , symlinks = True )
73
69
self ._sitecustomize = self ._template .sitecustomize
74
70
self ._user_site_packages = self ._template .user_site_packages
75
71
else :
76
72
# Create a new virtual environment.
77
73
if self ._venv_type == "virtualenv" :
78
- subprocess . check_call (
74
+ _virtualenv . cli_run (
79
75
[
80
- sys .executable ,
81
- "-m" ,
82
- "virtualenv" ,
83
76
"--no-pip" ,
84
77
"--no-wheel" ,
85
78
"--no-setuptools" ,
86
- str (self .location ),
87
- ]
79
+ os . fspath (self .location ),
80
+ ],
88
81
)
89
- self ._fix_virtualenv_site_module ()
90
82
elif self ._venv_type == "venv" :
91
83
builder = _venv .EnvBuilder ()
92
84
context = builder .ensure_directories (self .location )
@@ -96,71 +88,30 @@ def _create(self, clear: bool = False) -> None:
96
88
self .sitecustomize = self ._sitecustomize
97
89
self .user_site_packages = self ._user_site_packages
98
90
99
- def _fix_virtualenv_site_module (self ) -> None :
100
- # Patch `site.py` so user site work as expected.
101
- site_py = self .lib / "site.py"
102
- with open (site_py ) as fp :
103
- site_contents = fp .read ()
104
- for pattern , replace in (
105
- (
106
- # Ensure enabling user site does not result in adding
107
- # the real site-packages' directory to `sys.path`.
108
- ("\n def virtual_addsitepackages(known_paths):\n " ),
109
- (
110
- "\n def virtual_addsitepackages(known_paths):\n "
111
- " return known_paths\n "
112
- ),
113
- ),
114
- (
115
- # Fix sites ordering: user site must be added before system.
116
- (
117
- "\n paths_in_sys = addsitepackages(paths_in_sys)"
118
- "\n paths_in_sys = addusersitepackages(paths_in_sys)\n "
119
- ),
120
- (
121
- "\n paths_in_sys = addusersitepackages(paths_in_sys)"
122
- "\n paths_in_sys = addsitepackages(paths_in_sys)\n "
123
- ),
124
- ),
125
- ):
126
- assert pattern in site_contents
127
- site_contents = site_contents .replace (pattern , replace )
128
- with open (site_py , "w" ) as fp :
129
- fp .write (site_contents )
130
- # Make sure bytecode is up-to-date too.
131
- assert compileall .compile_file (str (site_py ), quiet = 1 , force = True )
132
-
133
91
def _customize_site (self ) -> None :
134
- contents = ""
135
- if self ._venv_type == "venv" :
136
- # Enable user site (before system).
137
- contents += textwrap .dedent (
138
- """
139
- import os, site, sys
140
-
141
- if not os.environ.get('PYTHONNOUSERSITE', False):
142
-
143
- site.ENABLE_USER_SITE = True
144
-
145
- # First, drop system-sites related paths.
146
- original_sys_path = sys.path[:]
147
- known_paths = set()
148
- for path in site.getsitepackages():
149
- site.addsitedir(path, known_paths=known_paths)
150
- system_paths = sys.path[len(original_sys_path):]
151
- for path in system_paths:
152
- if path in original_sys_path:
153
- original_sys_path.remove(path)
154
- sys.path = original_sys_path
155
-
156
- # Second, add user-site.
157
- site.addsitedir(site.getusersitepackages())
158
-
159
- # Third, add back system-sites related paths.
160
- for path in site.getsitepackages():
161
- site.addsitedir(path)
162
- """
163
- ).strip ()
92
+ # Enable user site (before system).
93
+ contents = textwrap .dedent (
94
+ """
95
+ import os, site, sys
96
+ if not os.environ.get('PYTHONNOUSERSITE', False):
97
+ site.ENABLE_USER_SITE = True
98
+ # First, drop system-sites related paths.
99
+ original_sys_path = sys.path[:]
100
+ known_paths = set()
101
+ for path in site.getsitepackages():
102
+ site.addsitedir(path, known_paths=known_paths)
103
+ system_paths = sys.path[len(original_sys_path):]
104
+ for path in system_paths:
105
+ if path in original_sys_path:
106
+ original_sys_path.remove(path)
107
+ sys.path = original_sys_path
108
+ # Second, add user-site.
109
+ site.addsitedir(site.getusersitepackages())
110
+ # Third, add back system-sites related paths.
111
+ for path in site.getsitepackages():
112
+ site.addsitedir(path)
113
+ """
114
+ ).strip ()
164
115
if self ._sitecustomize is not None :
165
116
contents += "\n " + self ._sitecustomize
166
117
sitecustomize = self .site / "sitecustomize.py"
@@ -191,12 +142,12 @@ def user_site_packages(self) -> bool:
191
142
192
143
@user_site_packages .setter
193
144
def user_site_packages (self , value : bool ) -> None :
194
- self ._user_site_packages = value
195
- if self . _venv_type == "virtualenv" :
196
- marker = self . lib / "no-global-site-packages.txt"
197
- if self . _user_site_packages :
198
- marker . unlink ( )
199
- else :
200
- marker . touch ()
201
- elif self . _venv_type == "venv" :
202
- self . _customize_site ( )
145
+ self ._customize_site ()
146
+ pyvenv_cfg = self . location . joinpath ( "pyvenv.cfg" )
147
+ modified_lines = []
148
+ for line in pyvenv_cfg . read_text (). splitlines () :
149
+ k , v = line . split ( "=" , 1 )
150
+ if k . strip () == "include-system-site-packages" :
151
+ line = f"include-system-site-packages = { str ( bool ( value )). lower () } "
152
+ modified_lines . append ( line )
153
+ pyvenv_cfg . write_text ( " \n " . join ( modified_lines ) )
0 commit comments