Skip to content

Commit 7bfd444

Browse files
authored
Fix site.getsitepackages() broken on python2 on debian (#2108)
1 parent 2a080a0 commit 7bfd444

File tree

3 files changed

+71
-15
lines changed

3 files changed

+71
-15
lines changed

docs/changelog/2105.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``site.getsitepackages()`` broken on python2 on debian - by :user:`freundTech`.

src/virtualenv/create/via_global_ref/builtin/python2/site.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@
99

1010
def main():
1111
"""Patch what needed, and invoke the original site.py"""
12+
here = __file__ # the distutils.install patterns will be injected relative to this site.py, save it here
1213
config = read_pyvenv()
1314
sys.real_prefix = sys.base_prefix = config["base-prefix"]
1415
sys.base_exec_prefix = config["base-exec-prefix"]
1516
sys.base_executable = config["base-executable"]
1617
global_site_package_enabled = config.get("include-system-site-packages", False) == "true"
1718
rewrite_standard_library_sys_path()
1819
disable_user_site_package()
19-
load_host_site()
20+
load_host_site(here)
2021
if global_site_package_enabled:
2122
add_global_site_package()
23+
rewrite_getsitepackages(here)
2224

2325

24-
def load_host_site():
26+
def load_host_site(here):
2527
"""trigger reload of site.py - now it will use the standard library instance that will take care of init"""
2628
# we have a duality here, we generate the platform and pure library path based on what distutils.install specifies
2729
# because this is what pip will be using; the host site.py though may contain it's own pattern for where the
@@ -36,23 +38,26 @@ def load_host_site():
3638
# to facilitate when the two match, or not we first reload the site.py, now triggering the import of host site.py,
3739
# as this will ensure that initialization code within host site.py runs
3840

39-
here = __file__ # the distutils.install patterns will be injected relative to this site.py, save it here
40-
4141
# ___RELOAD_CODE___
4242

4343
# and then if the distutils site packages are not on the sys.path we add them via add_site_dir; note we must add
4444
# them by invoking add_site_dir to trigger the processing of pth files
45+
46+
add_site_dir = sys.modules["site"].addsitedir
47+
for path in get_site_packages_dirs(here):
48+
add_site_dir(path)
49+
50+
51+
def get_site_packages_dirs(here):
52+
import json
4553
import os
4654

4755
site_packages = r"""
4856
___EXPECTED_SITE_PACKAGES___
4957
"""
50-
import json
5158

52-
add_site_dir = sys.modules["site"].addsitedir
5359
for path in json.loads(site_packages):
54-
full_path = os.path.abspath(os.path.join(here, path.encode("utf-8")))
55-
add_site_dir(full_path)
60+
yield os.path.abspath(os.path.join(here, path.encode("utf-8")))
5661

5762

5863
sep = "\\" if sys.platform == "win32" else "/" # no os module here yet - poor mans version
@@ -161,4 +166,25 @@ def add_global_site_package():
161166
site.PREFIXES = orig_prefixes + site.PREFIXES
162167

163168

169+
# Debian and it's derivatives patch this function. We undo the damage
170+
def rewrite_getsitepackages(here):
171+
site = sys.modules["site"]
172+
173+
site_package_dirs = get_site_packages_dirs(here)
174+
orig_getsitepackages = site.getsitepackages
175+
176+
def getsitepackages():
177+
sitepackages = orig_getsitepackages()
178+
if sys.prefix not in site.PREFIXES or sys.exec_prefix not in site.PREFIXES:
179+
# Someone messed with the prefixes, so we stop patching
180+
return sitepackages
181+
for path in site_package_dirs:
182+
if path not in sitepackages:
183+
sitepackages.insert(0, path)
184+
185+
return sitepackages
186+
187+
site.getsitepackages = getsitepackages
188+
189+
164190
main()

tests/unit/create/test_creator.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import logging
88
import os
99
import shutil
10+
import site
1011
import stat
1112
import subprocess
1213
import sys
@@ -625,15 +626,11 @@ def test_pth_in_site_vs_PYTHONPATH(tmp_path):
625626

626627

627628
def test_getsitepackages_system_site(tmp_path):
628-
import site
629-
630-
old_prefixes = site.PREFIXES
631-
site.PREFIXES = [sys.base_prefix, sys.base_exec_prefix]
632-
system_site_packages = site.getsitepackages()
633-
site.PREFIXES = old_prefixes
634-
635629
# Test without --system-site-packages
636630
session = cli_run([ensure_text(str(tmp_path))])
631+
632+
system_site_packages = get_expected_system_site_packages(session)
633+
637634
out = subprocess.check_output(
638635
[str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"],
639636
universal_newlines=True,
@@ -645,6 +642,9 @@ def test_getsitepackages_system_site(tmp_path):
645642

646643
# Test with --system-site-packages
647644
session = cli_run([ensure_text(str(tmp_path)), "--system-site-packages"])
645+
646+
system_site_packages = get_expected_system_site_packages(session)
647+
648648
out = subprocess.check_output(
649649
[str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"],
650650
universal_newlines=True,
@@ -653,3 +653,32 @@ def test_getsitepackages_system_site(tmp_path):
653653

654654
for system_site_package in system_site_packages:
655655
assert system_site_package in site_packages
656+
657+
658+
def get_expected_system_site_packages(session):
659+
base_prefix = session.creator.pyenv_cfg["base-prefix"]
660+
base_exec_prefix = session.creator.pyenv_cfg["base-exec-prefix"]
661+
old_prefixes = site.PREFIXES
662+
site.PREFIXES = [base_prefix, base_exec_prefix]
663+
system_site_packages = site.getsitepackages()
664+
site.PREFIXES = old_prefixes
665+
666+
return system_site_packages
667+
668+
669+
def test_get_site_packages(tmp_path):
670+
case_sensitive = fs_is_case_sensitive()
671+
session = cli_run([ensure_text(str(tmp_path))])
672+
env_site_packages = [str(session.creator.purelib), str(session.creator.platlib)]
673+
out = subprocess.check_output(
674+
[str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"],
675+
universal_newlines=True,
676+
)
677+
site_packages = ast.literal_eval(out)
678+
679+
if not case_sensitive:
680+
env_site_packages = [x.lower() for x in env_site_packages]
681+
site_packages = [x.lower() for x in site_packages]
682+
683+
for env_site_package in env_site_packages:
684+
assert env_site_package in site_packages

0 commit comments

Comments
 (0)