6 from typing
import List
, Optional
8 logger
= logging
.getLogger(__name__
)
9 _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX
= re
.compile(
10 r
"include-system-site-packages\s*=\s*(?P<value>true|false)"
14 def _running_under_venv() -> bool:
15 """Checks if sys.base_prefix and sys.prefix match.
17 This handles PEP 405 compliant virtual environments.
19 return sys
.prefix
!= getattr(sys
, "base_prefix", sys
.prefix
)
22 def _running_under_legacy_virtualenv() -> bool:
23 """Checks if sys.real_prefix is set.
25 This handles virtual environments created with pypa's virtualenv.
27 # pypa/virtualenv case
28 return hasattr(sys
, "real_prefix")
31 def running_under_virtualenv() -> bool:
32 """True if we're running inside a virtual environment, False otherwise."""
33 return _running_under_venv() or _running_under_legacy_virtualenv()
36 def _get_pyvenv_cfg_lines() -> Optional
[List
[str]]:
37 """Reads {sys.prefix}/pyvenv.cfg and returns its contents as list of lines
39 Returns None, if it could not read/access the file.
41 pyvenv_cfg_file
= os
.path
.join(sys
.prefix
, "pyvenv.cfg")
43 # Although PEP 405 does not specify, the built-in venv module always
44 # writes with UTF-8. (pypa/pip#8717)
45 with open(pyvenv_cfg_file
, encoding
="utf-8") as f
:
46 return f
.read().splitlines() # avoids trailing newlines
51 def _no_global_under_venv() -> bool:
52 """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion
54 PEP 405 specifies that when system site-packages are not supposed to be
55 visible from a virtual environment, `pyvenv.cfg` must contain the following
58 include-system-site-packages = false
60 Additionally, log a warning if accessing the file fails.
62 cfg_lines
= _get_pyvenv_cfg_lines()
64 # We're not in a "sane" venv, so assume there is no system
65 # site-packages access (since that's PEP 405's default state).
67 "Could not access 'pyvenv.cfg' despite a virtual environment "
68 "being active. Assuming global site-packages is not accessible "
69 "in this environment."
73 for line
in cfg_lines
:
74 match
= _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX
.match(line
)
75 if match
is not None and match
.group("value") == "false":
80 def _no_global_under_legacy_virtualenv() -> bool:
81 """Check if "no-global-site-packages.txt" exists beside site.py
83 This mirrors logic in pypa/virtualenv for determining whether system
84 site-packages are visible in the virtual environment.
86 site_mod_dir
= os
.path
.dirname(os
.path
.abspath(site
.__file
__))
87 no_global_site_packages_file
= os
.path
.join(
89 "no-global-site-packages.txt",
91 return os
.path
.exists(no_global_site_packages_file
)
94 def virtualenv_no_global() -> bool:
95 """Returns a boolean, whether running in venv with no system site-packages."""
96 # PEP 405 compliance needs to be checked first since virtualenv >=20 would
97 # return True for both checks, but is only able to use the PEP 405 config.
98 if _running_under_venv():
99 return _no_global_under_venv()
101 if _running_under_legacy_virtualenv():
102 return _no_global_under_legacy_virtualenv()