• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Append module search paths for third-party packages to sys.path.
2
3****************************************************************
4* This module is automatically imported during initialization. *
5****************************************************************
6
7This will append site-specific paths to the module search path.  On
8Unix (including Mac OSX), it starts with sys.prefix and
9sys.exec_prefix (if different) and appends
10lib/python<version>/site-packages.
11On other platforms (such as Windows), it tries each of the
12prefixes directly, as well as with lib/site-packages appended.  The
13resulting directories, if they exist, are appended to sys.path, and
14also inspected for path configuration files.
15
16If a file named "pyvenv.cfg" exists one directory above sys.executable,
17sys.prefix and sys.exec_prefix are set to that directory and
18it is also checked for site-packages (sys.base_prefix and
19sys.base_exec_prefix will always be the "real" prefixes of the Python
20installation). If "pyvenv.cfg" (a bootstrap configuration file) contains
21the key "include-system-site-packages" set to anything other than "false"
22(case-insensitive), the system-level prefixes will still also be
23searched for site-packages; otherwise they won't.
24
25All of the resulting site-specific directories, if they exist, are
26appended to sys.path, and also inspected for path configuration
27files.
28
29A path configuration file is a file whose name has the form
30<package>.pth; its contents are additional directories (one per line)
31to be added to sys.path.  Non-existing directories (or
32non-directories) are never added to sys.path; no directory is added to
33sys.path more than once.  Blank lines and lines beginning with
34'#' are skipped. Lines starting with 'import' are executed.
35
36For example, suppose sys.prefix and sys.exec_prefix are set to
37/usr/local and there is a directory /usr/local/lib/python2.5/site-packages
38with three subdirectories, foo, bar and spam, and two path
39configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
40following:
41
42  # foo package configuration
43  foo
44  bar
45  bletch
46
47and bar.pth contains:
48
49  # bar package configuration
50  bar
51
52Then the following directories are added to sys.path, in this order:
53
54  /usr/local/lib/python2.5/site-packages/bar
55  /usr/local/lib/python2.5/site-packages/foo
56
57Note that bletch is omitted because it doesn't exist; bar precedes foo
58because bar.pth comes alphabetically before foo.pth; and spam is
59omitted because it is not mentioned in either path configuration file.
60
61The readline module is also automatically configured to enable
62completion for systems that support it.  This can be overridden in
63sitecustomize, usercustomize or PYTHONSTARTUP.  Starting Python in
64isolated mode (-I) disables automatic readline configuration.
65
66After these operations, an attempt is made to import a module
67named sitecustomize, which can perform arbitrary additional
68site-specific customizations.  If this import fails with an
69ImportError exception, it is silently ignored.
70"""
71
72import sys
73import os
74import builtins
75import _sitebuiltins
76import io
77import stat
78
79# Prefixes for site-packages; add additional prefixes like /usr/local here
80PREFIXES = [sys.prefix, sys.exec_prefix]
81# Enable per user site-packages directory
82# set it to False to disable the feature or True to force the feature
83ENABLE_USER_SITE = None
84
85# for distutils.commands.install
86# These values are initialized by the getuserbase() and getusersitepackages()
87# functions, through the main() function when Python starts.
88USER_SITE = None
89USER_BASE = None
90
91
92def _trace(message):
93    if sys.flags.verbose:
94        print(message, file=sys.stderr)
95
96
97def makepath(*paths):
98    dir = os.path.join(*paths)
99    try:
100        dir = os.path.abspath(dir)
101    except OSError:
102        pass
103    return dir, os.path.normcase(dir)
104
105
106def abs_paths():
107    """Set all module __file__ and __cached__ attributes to an absolute path"""
108    for m in set(sys.modules.values()):
109        loader_module = None
110        try:
111            loader_module = m.__loader__.__module__
112        except AttributeError:
113            try:
114                loader_module = m.__spec__.loader.__module__
115            except AttributeError:
116                pass
117        if loader_module not in {'_frozen_importlib', '_frozen_importlib_external'}:
118            continue   # don't mess with a PEP 302-supplied __file__
119        try:
120            m.__file__ = os.path.abspath(m.__file__)
121        except (AttributeError, OSError, TypeError):
122            pass
123        try:
124            m.__cached__ = os.path.abspath(m.__cached__)
125        except (AttributeError, OSError, TypeError):
126            pass
127
128
129def removeduppaths():
130    """ Remove duplicate entries from sys.path along with making them
131    absolute"""
132    # This ensures that the initial path provided by the interpreter contains
133    # only absolute pathnames, even if we're running from the build directory.
134    L = []
135    known_paths = set()
136    for dir in sys.path:
137        # Filter out duplicate paths (on case-insensitive file systems also
138        # if they only differ in case); turn relative paths into absolute
139        # paths.
140        dir, dircase = makepath(dir)
141        if dircase not in known_paths:
142            L.append(dir)
143            known_paths.add(dircase)
144    sys.path[:] = L
145    return known_paths
146
147
148def _init_pathinfo():
149    """Return a set containing all existing file system items from sys.path."""
150    d = set()
151    for item in sys.path:
152        try:
153            if os.path.exists(item):
154                _, itemcase = makepath(item)
155                d.add(itemcase)
156        except TypeError:
157            continue
158    return d
159
160
161def addpackage(sitedir, name, known_paths):
162    """Process a .pth file within the site-packages directory:
163       For each line in the file, either combine it with sitedir to a path
164       and add that to known_paths, or execute it if it starts with 'import '.
165    """
166    if known_paths is None:
167        known_paths = _init_pathinfo()
168        reset = True
169    else:
170        reset = False
171    fullname = os.path.join(sitedir, name)
172    try:
173        st = os.lstat(fullname)
174    except OSError:
175        return
176    if ((getattr(st, 'st_flags', 0) & stat.UF_HIDDEN) or
177        (getattr(st, 'st_file_attributes', 0) & stat.FILE_ATTRIBUTE_HIDDEN)):
178        _trace(f"Skipping hidden .pth file: {fullname!r}")
179        return
180    _trace(f"Processing .pth file: {fullname!r}")
181    try:
182        with io.open_code(fullname) as f:
183            pth_content = f.read()
184    except OSError:
185        return
186
187    try:
188        # Accept BOM markers in .pth files as we do in source files
189        # (Windows PowerShell 5.1 makes it hard to emit UTF-8 files without a BOM)
190        pth_content = pth_content.decode("utf-8-sig")
191    except UnicodeDecodeError:
192        # Fallback to locale encoding for backward compatibility.
193        # We will deprecate this fallback in the future.
194        import locale
195        pth_content = pth_content.decode(locale.getencoding())
196        _trace(f"Cannot read {fullname!r} as UTF-8. "
197               f"Using fallback encoding {locale.getencoding()!r}")
198
199    for n, line in enumerate(pth_content.splitlines(), 1):
200        if line.startswith("#"):
201            continue
202        if line.strip() == "":
203            continue
204        try:
205            if line.startswith(("import ", "import\t")):
206                exec(line)
207                continue
208            line = line.rstrip()
209            dir, dircase = makepath(sitedir, line)
210            if dircase not in known_paths and os.path.exists(dir):
211                sys.path.append(dir)
212                known_paths.add(dircase)
213        except Exception as exc:
214            print(f"Error processing line {n:d} of {fullname}:\n",
215                  file=sys.stderr)
216            import traceback
217            for record in traceback.format_exception(exc):
218                for line in record.splitlines():
219                    print('  '+line, file=sys.stderr)
220            print("\nRemainder of file ignored", file=sys.stderr)
221            break
222    if reset:
223        known_paths = None
224    return known_paths
225
226
227def addsitedir(sitedir, known_paths=None):
228    """Add 'sitedir' argument to sys.path if missing and handle .pth files in
229    'sitedir'"""
230    _trace(f"Adding directory: {sitedir!r}")
231    if known_paths is None:
232        known_paths = _init_pathinfo()
233        reset = True
234    else:
235        reset = False
236    sitedir, sitedircase = makepath(sitedir)
237    if not sitedircase in known_paths:
238        sys.path.append(sitedir)        # Add path component
239        known_paths.add(sitedircase)
240    try:
241        names = os.listdir(sitedir)
242    except OSError:
243        return
244    names = [name for name in names
245             if name.endswith(".pth") and not name.startswith(".")]
246    for name in sorted(names):
247        addpackage(sitedir, name, known_paths)
248    if reset:
249        known_paths = None
250    return known_paths
251
252
253def check_enableusersite():
254    """Check if user site directory is safe for inclusion
255
256    The function tests for the command line flag (including environment var),
257    process uid/gid equal to effective uid/gid.
258
259    None: Disabled for security reasons
260    False: Disabled by user (command line option)
261    True: Safe and enabled
262    """
263    if sys.flags.no_user_site:
264        return False
265
266    if hasattr(os, "getuid") and hasattr(os, "geteuid"):
267        # check process uid == effective uid
268        if os.geteuid() != os.getuid():
269            return None
270    if hasattr(os, "getgid") and hasattr(os, "getegid"):
271        # check process gid == effective gid
272        if os.getegid() != os.getgid():
273            return None
274
275    return True
276
277
278# NOTE: sysconfig and it's dependencies are relatively large but site module
279# needs very limited part of them.
280# To speedup startup time, we have copy of them.
281#
282# See https://bugs.python.org/issue29585
283
284# Copy of sysconfig._get_implementation()
285def _get_implementation():
286    return 'Python'
287
288# Copy of sysconfig._getuserbase()
289def _getuserbase():
290    env_base = os.environ.get("PYTHONUSERBASE", None)
291    if env_base:
292        return env_base
293
294    # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
295    if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
296        return None
297
298    def joinuser(*args):
299        return os.path.expanduser(os.path.join(*args))
300
301    if os.name == "nt":
302        base = os.environ.get("APPDATA") or "~"
303        return joinuser(base, _get_implementation())
304
305    if sys.platform == "darwin" and sys._framework:
306        return joinuser("~", "Library", sys._framework,
307                        "%d.%d" % sys.version_info[:2])
308
309    return joinuser("~", ".local")
310
311
312# Same to sysconfig.get_path('purelib', os.name+'_user')
313def _get_path(userbase):
314    version = sys.version_info
315    if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
316        abi_thread = 't'
317    else:
318        abi_thread = ''
319
320    implementation = _get_implementation()
321    implementation_lower = implementation.lower()
322    if os.name == 'nt':
323        ver_nodot = sys.winver.replace('.', '')
324        return f'{userbase}\\{implementation}{ver_nodot}\\site-packages'
325
326    if sys.platform == 'darwin' and sys._framework:
327        return f'{userbase}/lib/{implementation_lower}/site-packages'
328
329    return f'{userbase}/lib/python{version[0]}.{version[1]}{abi_thread}/site-packages'
330
331
332def getuserbase():
333    """Returns the `user base` directory path.
334
335    The `user base` directory can be used to store data. If the global
336    variable ``USER_BASE`` is not initialized yet, this function will also set
337    it.
338    """
339    global USER_BASE
340    if USER_BASE is None:
341        USER_BASE = _getuserbase()
342    return USER_BASE
343
344
345def getusersitepackages():
346    """Returns the user-specific site-packages directory path.
347
348    If the global variable ``USER_SITE`` is not initialized yet, this
349    function will also set it.
350    """
351    global USER_SITE, ENABLE_USER_SITE
352    userbase = getuserbase() # this will also set USER_BASE
353
354    if USER_SITE is None:
355        if userbase is None:
356            ENABLE_USER_SITE = False # disable user site and return None
357        else:
358            USER_SITE = _get_path(userbase)
359
360    return USER_SITE
361
362def addusersitepackages(known_paths):
363    """Add a per user site-package to sys.path
364
365    Each user has its own python directory with site-packages in the
366    home directory.
367    """
368    # get the per user site-package path
369    # this call will also make sure USER_BASE and USER_SITE are set
370    _trace("Processing user site-packages")
371    user_site = getusersitepackages()
372
373    if ENABLE_USER_SITE and os.path.isdir(user_site):
374        addsitedir(user_site, known_paths)
375    return known_paths
376
377def getsitepackages(prefixes=None):
378    """Returns a list containing all global site-packages directories.
379
380    For each directory present in ``prefixes`` (or the global ``PREFIXES``),
381    this function will find its `site-packages` subdirectory depending on the
382    system environment, and will return a list of full paths.
383    """
384    sitepackages = []
385    seen = set()
386
387    if prefixes is None:
388        prefixes = PREFIXES
389
390    for prefix in prefixes:
391        if not prefix or prefix in seen:
392            continue
393        seen.add(prefix)
394
395        implementation = _get_implementation().lower()
396        ver = sys.version_info
397        if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
398            abi_thread = 't'
399        else:
400            abi_thread = ''
401        if os.sep == '/':
402            libdirs = [sys.platlibdir]
403            if sys.platlibdir != "lib":
404                libdirs.append("lib")
405
406            for libdir in libdirs:
407                path = os.path.join(prefix, libdir,
408                                    f"{implementation}{ver[0]}.{ver[1]}{abi_thread}",
409                                    "site-packages")
410                sitepackages.append(path)
411        else:
412            sitepackages.append(prefix)
413            sitepackages.append(os.path.join(prefix, "Lib", "site-packages"))
414    return sitepackages
415
416def addsitepackages(known_paths, prefixes=None):
417    """Add site-packages to sys.path"""
418    _trace("Processing global site-packages")
419    for sitedir in getsitepackages(prefixes):
420        if os.path.isdir(sitedir):
421            addsitedir(sitedir, known_paths)
422
423    return known_paths
424
425def setquit():
426    """Define new builtins 'quit' and 'exit'.
427
428    These are objects which make the interpreter exit when called.
429    The repr of each object contains a hint at how it works.
430
431    """
432    if os.sep == '\\':
433        eof = 'Ctrl-Z plus Return'
434    else:
435        eof = 'Ctrl-D (i.e. EOF)'
436
437    builtins.quit = _sitebuiltins.Quitter('quit', eof)
438    builtins.exit = _sitebuiltins.Quitter('exit', eof)
439
440
441def setcopyright():
442    """Set 'copyright' and 'credits' in builtins"""
443    builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
444    builtins.credits = _sitebuiltins._Printer("credits", """\
445    Thanks to CWI, CNRI, BeOpen, Zope Corporation, the Python Software
446    Foundation, and a cast of thousands for supporting Python
447    development.  See www.python.org for more information.""")
448    files, dirs = [], []
449    # Not all modules are required to have a __file__ attribute.  See
450    # PEP 420 for more details.
451    here = getattr(sys, '_stdlib_dir', None)
452    if not here and hasattr(os, '__file__'):
453        here = os.path.dirname(os.__file__)
454    if here:
455        files.extend(["LICENSE.txt", "LICENSE"])
456        dirs.extend([os.path.join(here, os.pardir), here, os.curdir])
457    builtins.license = _sitebuiltins._Printer(
458        "license",
459        "See https://www.python.org/psf/license/",
460        files, dirs)
461
462
463def sethelper():
464    builtins.help = _sitebuiltins._Helper()
465
466
467def gethistoryfile():
468    """Check if the PYTHON_HISTORY environment variable is set and define
469    it as the .python_history file.  If PYTHON_HISTORY is not set, use the
470    default .python_history file.
471    """
472    if not sys.flags.ignore_environment:
473        history = os.environ.get("PYTHON_HISTORY")
474        if history:
475            return history
476    return os.path.join(os.path.expanduser('~'),
477        '.python_history')
478
479
480def enablerlcompleter():
481    """Enable default readline configuration on interactive prompts, by
482    registering a sys.__interactivehook__.
483    """
484    sys.__interactivehook__ = register_readline
485
486
487def register_readline():
488    """Configure readline completion on interactive prompts.
489
490    If the readline module can be imported, the hook will set the Tab key
491    as completion key and register ~/.python_history as history file.
492    This can be overridden in the sitecustomize or usercustomize module,
493    or in a PYTHONSTARTUP file.
494    """
495    if not sys.flags.ignore_environment:
496        PYTHON_BASIC_REPL = os.getenv("PYTHON_BASIC_REPL")
497    else:
498        PYTHON_BASIC_REPL = False
499
500    import atexit
501
502    try:
503        try:
504            import readline
505        except ImportError:
506            readline = None
507        else:
508            import rlcompleter  # noqa: F401
509    except ImportError:
510        return
511
512    try:
513        if PYTHON_BASIC_REPL:
514            CAN_USE_PYREPL = False
515        else:
516            original_path = sys.path
517            sys.path = [p for p in original_path if p != '']
518            try:
519                import _pyrepl.readline
520                if os.name == "nt":
521                    import _pyrepl.windows_console
522                    console_errors = (_pyrepl.windows_console._error,)
523                else:
524                    import _pyrepl.unix_console
525                    console_errors = _pyrepl.unix_console._error
526                from _pyrepl.main import CAN_USE_PYREPL
527            finally:
528                sys.path = original_path
529    except ImportError:
530        return
531
532    if readline is not None:
533        # Reading the initialization (config) file may not be enough to set a
534        # completion key, so we set one first and then read the file.
535        if readline.backend == 'editline':
536            readline.parse_and_bind('bind ^I rl_complete')
537        else:
538            readline.parse_and_bind('tab: complete')
539
540        try:
541            readline.read_init_file()
542        except OSError:
543            # An OSError here could have many causes, but the most likely one
544            # is that there's no .inputrc file (or .editrc file in the case of
545            # Mac OS X + libedit) in the expected location.  In that case, we
546            # want to ignore the exception.
547            pass
548
549    if readline is None or readline.get_current_history_length() == 0:
550        # If no history was loaded, default to .python_history,
551        # or PYTHON_HISTORY.
552        # The guard is necessary to avoid doubling history size at
553        # each interpreter exit when readline was already configured
554        # through a PYTHONSTARTUP hook, see:
555        # http://bugs.python.org/issue5845#msg198636
556        history = gethistoryfile()
557
558        if CAN_USE_PYREPL:
559            readline_module = _pyrepl.readline
560            exceptions = (OSError, *console_errors)
561        else:
562            if readline is None:
563                return
564            readline_module = readline
565            exceptions = OSError
566
567        try:
568            readline_module.read_history_file(history)
569        except exceptions:
570            pass
571
572        def write_history():
573            try:
574                readline_module.write_history_file(history)
575            except (FileNotFoundError, PermissionError):
576                # home directory does not exist or is not writable
577                # https://bugs.python.org/issue19891
578                pass
579
580        atexit.register(write_history)
581
582
583def venv(known_paths):
584    global PREFIXES, ENABLE_USER_SITE
585
586    env = os.environ
587    if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
588        executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__']
589    else:
590        executable = sys.executable
591    exe_dir = os.path.dirname(os.path.abspath(executable))
592    site_prefix = os.path.dirname(exe_dir)
593    sys._home = None
594    conf_basename = 'pyvenv.cfg'
595    candidate_conf = next(
596        (
597            conffile for conffile in (
598                os.path.join(exe_dir, conf_basename),
599                os.path.join(site_prefix, conf_basename)
600            )
601            if os.path.isfile(conffile)
602        ),
603        None
604    )
605
606    if candidate_conf:
607        virtual_conf = candidate_conf
608        system_site = "true"
609        # Issue 25185: Use UTF-8, as that's what the venv module uses when
610        # writing the file.
611        with open(virtual_conf, encoding='utf-8') as f:
612            for line in f:
613                if '=' in line:
614                    key, _, value = line.partition('=')
615                    key = key.strip().lower()
616                    value = value.strip()
617                    if key == 'include-system-site-packages':
618                        system_site = value.lower()
619                    elif key == 'home':
620                        sys._home = value
621
622        sys.prefix = sys.exec_prefix = site_prefix
623
624        # Doing this here ensures venv takes precedence over user-site
625        addsitepackages(known_paths, [sys.prefix])
626
627        # addsitepackages will process site_prefix again if its in PREFIXES,
628        # but that's ok; known_paths will prevent anything being added twice
629        if system_site == "true":
630            PREFIXES.insert(0, sys.prefix)
631        else:
632            PREFIXES = [sys.prefix]
633            ENABLE_USER_SITE = False
634
635    return known_paths
636
637
638def execsitecustomize():
639    """Run custom site specific code, if available."""
640    try:
641        try:
642            import sitecustomize
643        except ImportError as exc:
644            if exc.name == 'sitecustomize':
645                pass
646            else:
647                raise
648    except Exception as err:
649        if sys.flags.verbose:
650            sys.excepthook(*sys.exc_info())
651        else:
652            sys.stderr.write(
653                "Error in sitecustomize; set PYTHONVERBOSE for traceback:\n"
654                "%s: %s\n" %
655                (err.__class__.__name__, err))
656
657
658def execusercustomize():
659    """Run custom user specific code, if available."""
660    try:
661        try:
662            import usercustomize
663        except ImportError as exc:
664            if exc.name == 'usercustomize':
665                pass
666            else:
667                raise
668    except Exception as err:
669        if sys.flags.verbose:
670            sys.excepthook(*sys.exc_info())
671        else:
672            sys.stderr.write(
673                "Error in usercustomize; set PYTHONVERBOSE for traceback:\n"
674                "%s: %s\n" %
675                (err.__class__.__name__, err))
676
677
678def main():
679    """Add standard site-specific directories to the module search path.
680
681    This function is called automatically when this module is imported,
682    unless the python interpreter was started with the -S flag.
683    """
684    global ENABLE_USER_SITE
685
686    orig_path = sys.path[:]
687    known_paths = removeduppaths()
688    if orig_path != sys.path:
689        # removeduppaths() might make sys.path absolute.
690        # fix __file__ and __cached__ of already imported modules too.
691        abs_paths()
692
693    known_paths = venv(known_paths)
694    if ENABLE_USER_SITE is None:
695        ENABLE_USER_SITE = check_enableusersite()
696    known_paths = addusersitepackages(known_paths)
697    known_paths = addsitepackages(known_paths)
698    setquit()
699    setcopyright()
700    sethelper()
701    if not sys.flags.isolated:
702        enablerlcompleter()
703    execsitecustomize()
704    if ENABLE_USER_SITE:
705        execusercustomize()
706
707# Prevent extending of sys.path when python was started with -S and
708# site is imported later.
709if not sys.flags.no_site:
710    main()
711
712def _script():
713    help = """\
714    %s [--user-base] [--user-site]
715
716    Without arguments print some useful information
717    With arguments print the value of USER_BASE and/or USER_SITE separated
718    by '%s'.
719
720    Exit codes with --user-base or --user-site:
721      0 - user site directory is enabled
722      1 - user site directory is disabled by user
723      2 - user site directory is disabled by super user
724          or for security reasons
725     >2 - unknown error
726    """
727    args = sys.argv[1:]
728    if not args:
729        user_base = getuserbase()
730        user_site = getusersitepackages()
731        print("sys.path = [")
732        for dir in sys.path:
733            print("    %r," % (dir,))
734        print("]")
735        def exists(path):
736            if path is not None and os.path.isdir(path):
737                return "exists"
738            else:
739                return "doesn't exist"
740        print(f"USER_BASE: {user_base!r} ({exists(user_base)})")
741        print(f"USER_SITE: {user_site!r} ({exists(user_site)})")
742        print(f"ENABLE_USER_SITE: {ENABLE_USER_SITE!r}")
743        sys.exit(0)
744
745    buffer = []
746    if '--user-base' in args:
747        buffer.append(USER_BASE)
748    if '--user-site' in args:
749        buffer.append(USER_SITE)
750
751    if buffer:
752        print(os.pathsep.join(buffer))
753        if ENABLE_USER_SITE:
754            sys.exit(0)
755        elif ENABLE_USER_SITE is False:
756            sys.exit(1)
757        elif ENABLE_USER_SITE is None:
758            sys.exit(2)
759        else:
760            sys.exit(3)
761    else:
762        import textwrap
763        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
764        sys.exit(10)
765
766if __name__ == '__main__':
767    _script()
768