Skip to content

Commit 6601dd5

Browse files
Rewrite virtualenv tool in tests for 20+ support
Co-Authored-By: Lumir Balhar <[email protected]>
1 parent c4c28f3 commit 6601dd5

File tree

1 file changed

+46
-95
lines changed

1 file changed

+46
-95
lines changed

tests/lib/venv.py

Lines changed: 46 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import compileall
22
import os
33
import shutil
4-
import subprocess
5-
import sys
4+
import sysconfig
65
import textwrap
76
import venv as _venv
87
from pathlib import Path
@@ -47,15 +46,16 @@ def __init__(
4746
self._create()
4847

4948
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"])
5959

6060
def __repr__(self) -> str:
6161
return f"<VirtualEnvironment {self.location}>"
@@ -64,29 +64,21 @@ def _create(self, clear: bool = False) -> None:
6464
if clear:
6565
shutil.rmtree(self.location)
6666
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()
7167
# Clone virtual environment from template.
7268
shutil.copytree(self._template.location, self.location, symlinks=True)
7369
self._sitecustomize = self._template.sitecustomize
7470
self._user_site_packages = self._template.user_site_packages
7571
else:
7672
# Create a new virtual environment.
7773
if self._venv_type == "virtualenv":
78-
subprocess.check_call(
74+
_virtualenv.cli_run(
7975
[
80-
sys.executable,
81-
"-m",
82-
"virtualenv",
8376
"--no-pip",
8477
"--no-wheel",
8578
"--no-setuptools",
86-
str(self.location),
87-
]
79+
os.fspath(self.location),
80+
],
8881
)
89-
self._fix_virtualenv_site_module()
9082
elif self._venv_type == "venv":
9183
builder = _venv.EnvBuilder()
9284
context = builder.ensure_directories(self.location)
@@ -96,71 +88,30 @@ def _create(self, clear: bool = False) -> None:
9688
self.sitecustomize = self._sitecustomize
9789
self.user_site_packages = self._user_site_packages
9890

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-
("\ndef virtual_addsitepackages(known_paths):\n"),
109-
(
110-
"\ndef 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-
13391
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()
164115
if self._sitecustomize is not None:
165116
contents += "\n" + self._sitecustomize
166117
sitecustomize = self.site / "sitecustomize.py"
@@ -191,12 +142,12 @@ def user_site_packages(self) -> bool:
191142

192143
@user_site_packages.setter
193144
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

Comments
 (0)