diff options
Diffstat (limited to 'Lib/site.py')
-rw-r--r-- | Lib/site.py | 108 |
1 files changed, 94 insertions, 14 deletions
diff --git a/Lib/site.py b/Lib/site.py index a2c0bec..b751006 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -13,6 +13,19 @@ prefixes directly, as well as with lib/site-packages appended. The resulting directories, if they exist, are appended to sys.path, and also inspected for path configuration files. +If a file named "pyvenv.cfg" exists one directory above sys.executable, +sys.prefix and sys.exec_prefix are set to that directory and +it is also checked for site-packages and site-python (sys.base_prefix and +sys.base_exec_prefix will always be the "real" prefixes of the Python +installation). If "pyvenv.cfg" (a bootstrap configuration file) contains +the key "include-system-site-packages" set to anything other than "false" +(case-insensitive), the system-level prefixes will still also be +searched for site-packages; otherwise they won't. + +All of the resulting site-specific directories, if they exist, are +appended to sys.path, and also inspected for path configuration +files. + A path configuration file is a file whose name has the form <package>.pth; its contents are additional directories (one per line) to be added to sys.path. Non-existing directories (or @@ -54,8 +67,8 @@ ImportError exception, it is silently ignored. import sys import os +import re import builtins -import traceback # Prefixes for site-packages; add additional prefixes like /usr/local here PREFIXES = [sys.prefix, sys.exec_prefix] @@ -82,7 +95,8 @@ def makepath(*paths): def abs_paths(): """Set all module __file__ and __cached__ attributes to an absolute path""" for m in set(sys.modules.values()): - if hasattr(m, '__loader__'): + if (getattr(getattr(m, '__loader__', None), '__module__', None) != + '_frozen_importlib'): continue # don't mess with a PEP 302-supplied __file__ try: m.__file__ = os.path.abspath(m.__file__) @@ -138,7 +152,7 @@ def addpackage(sitedir, name, known_paths): reset = 0 fullname = os.path.join(sitedir, name) try: - f = open(fullname, "rU") + f = open(fullname, "r") except IOError: return with f: @@ -154,9 +168,10 @@ def addpackage(sitedir, name, known_paths): if not dircase in known_paths and os.path.exists(dir): sys.path.append(dir) known_paths.add(dircase) - except Exception as err: + except Exception: print("Error processing line {:d} of {}:\n".format(n+1, fullname), file=sys.stderr) + import traceback for record in traceback.format_exception(*sys.exc_info()): for line in record.splitlines(): print(' '+line, file=sys.stderr) @@ -178,6 +193,7 @@ def addsitedir(sitedir, known_paths=None): sitedir, sitedircase = makepath(sitedir) if not sitedircase in known_paths: sys.path.append(sitedir) # Add path component + known_paths.add(sitedircase) try: names = os.listdir(sitedir) except os.error: @@ -241,7 +257,6 @@ def getusersitepackages(): return USER_SITE from sysconfig import get_path - import os if sys.platform == 'darwin': from sysconfig import get_config_var @@ -266,18 +281,21 @@ def addusersitepackages(known_paths): addsitedir(user_site, known_paths) return known_paths -def getsitepackages(): +def getsitepackages(prefixes=None): """Returns a list containing all global site-packages directories (and possibly site-python). - For each directory present in the global ``PREFIXES``, this function - will find its `site-packages` subdirectory depending on the system - environment, and will return a list of full paths. + For each directory present in ``prefixes`` (or the global ``PREFIXES``), + this function will find its `site-packages` subdirectory depending on the + system environment, and will return a list of full paths. """ sitepackages = [] seen = set() - for prefix in PREFIXES: + if prefixes is None: + prefixes = PREFIXES + + for prefix in prefixes: if not prefix or prefix in seen: continue seen.add(prefix) @@ -303,9 +321,9 @@ def getsitepackages(): sys.version[:3], "site-packages")) return sitepackages -def addsitepackages(known_paths): +def addsitepackages(known_paths, prefixes=None): """Add site-packages (and possibly site-python) to sys.path""" - for sitedir in getsitepackages(): + for sitedir in getsitepackages(prefixes): if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) @@ -385,7 +403,7 @@ class _Printer(object): for filename in self.__files: filename = os.path.join(dir, filename) try: - fp = open(filename, "rU") + fp = open(filename, "r") data = fp.read() fp.close() break @@ -475,6 +493,59 @@ def aliasmbcs(): encodings.aliases.aliases[enc] = 'mbcs' +CONFIG_LINE = re.compile(r'^(?P<key>(\w|[-_])+)\s*=\s*(?P<value>.*)\s*$') + +def venv(known_paths): + global PREFIXES, ENABLE_USER_SITE + + env = os.environ + if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env: + executable = os.environ['__PYVENV_LAUNCHER__'] + else: + executable = sys.executable + exe_dir, _ = os.path.split(os.path.abspath(executable)) + site_prefix = os.path.dirname(exe_dir) + sys._home = None + conf_basename = 'pyvenv.cfg' + candidate_confs = [ + conffile for conffile in ( + os.path.join(exe_dir, conf_basename), + os.path.join(site_prefix, conf_basename) + ) + if os.path.isfile(conffile) + ] + + if candidate_confs: + virtual_conf = candidate_confs[0] + system_site = "true" + with open(virtual_conf) as f: + for line in f: + line = line.strip() + m = CONFIG_LINE.match(line) + if m: + d = m.groupdict() + key, value = d['key'].lower(), d['value'] + if key == 'include-system-site-packages': + system_site = value.lower() + elif key == 'home': + sys._home = value + + sys.prefix = sys.exec_prefix = site_prefix + + # Doing this here ensures venv takes precedence over user-site + addsitepackages(known_paths, [sys.prefix]) + + # addsitepackages will process site_prefix again if its in PREFIXES, + # but that's ok; known_paths will prevent anything being added twice + if system_site == "true": + PREFIXES.insert(0, sys.prefix) + else: + PREFIXES = [sys.prefix] + ENABLE_USER_SITE = False + + return known_paths + + def execsitecustomize(): """Run custom site specific code, if available.""" try: @@ -508,10 +579,16 @@ def execusercustomize(): def main(): + """Add standard site-specific directories to the module search path. + + This function is called automatically when this module is imported, + unless the python interpreter was started with the -S flag. + """ global ENABLE_USER_SITE abs_paths() known_paths = removeduppaths() + known_paths = venv(known_paths) if ENABLE_USER_SITE is None: ENABLE_USER_SITE = check_enableusersite() known_paths = addusersitepackages(known_paths) @@ -526,7 +603,10 @@ def main(): if ENABLE_USER_SITE: execusercustomize() -main() +# Prevent edition of sys.path when python was started with -S and +# site is imported later. +if not sys.flags.no_site: + main() def _script(): help = """\ |