Home | History | Annotate | Download | only in Lib
      1 """Append module search paths for third-party packages to sys.path.
      2 
      3 ****************************************************************
      4 * This module is automatically imported during initialization. *
      5 ****************************************************************
      6 
      7 This will append site-specific paths to the module search path.  On
      8 Unix (including Mac OSX), it starts with sys.prefix and
      9 sys.exec_prefix (if different) and appends
     10 lib/python<version>/site-packages.
     11 On other platforms (such as Windows), it tries each of the
     12 prefixes directly, as well as with lib/site-packages appended.  The
     13 resulting directories, if they exist, are appended to sys.path, and
     14 also inspected for path configuration files.
     15 
     16 If a file named "pyvenv.cfg" exists one directory above sys.executable,
     17 sys.prefix and sys.exec_prefix are set to that directory and
     18 it is also checked for site-packages (sys.base_prefix and
     19 sys.base_exec_prefix will always be the "real" prefixes of the Python
     20 installation). If "pyvenv.cfg" (a bootstrap configuration file) contains
     21 the key "include-system-site-packages" set to anything other than "false"
     22 (case-insensitive), the system-level prefixes will still also be
     23 searched for site-packages; otherwise they won't.
     24 
     25 All of the resulting site-specific directories, if they exist, are
     26 appended to sys.path, and also inspected for path configuration
     27 files.
     28 
     29 A path configuration file is a file whose name has the form
     30 <package>.pth; its contents are additional directories (one per line)
     31 to be added to sys.path.  Non-existing directories (or
     32 non-directories) are never added to sys.path; no directory is added to
     33 sys.path more than once.  Blank lines and lines beginning with
     34 '#' are skipped. Lines starting with 'import' are executed.
     35 
     36 For 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
     38 with three subdirectories, foo, bar and spam, and two path
     39 configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
     40 following:
     41 
     42   # foo package configuration
     43   foo
     44   bar
     45   bletch
     46 
     47 and bar.pth contains:
     48 
     49   # bar package configuration
     50   bar
     51 
     52 Then 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 
     57 Note that bletch is omitted because it doesn't exist; bar precedes foo
     58 because bar.pth comes alphabetically before foo.pth; and spam is
     59 omitted because it is not mentioned in either path configuration file.
     60 
     61 The readline module is also automatically configured to enable
     62 completion for systems that support it.  This can be overridden in
     63 sitecustomize, usercustomize or PYTHONSTARTUP.  Starting Python in
     64 isolated mode (-I) disables automatic readline configuration.
     65 
     66 After these operations, an attempt is made to import a module
     67 named sitecustomize, which can perform arbitrary additional
     68 site-specific customizations.  If this import fails with an
     69 ImportError exception, it is silently ignored.
     70 """
     71 
     72 import sys
     73 import os
     74 import builtins
     75 import _sitebuiltins
     76 
     77 # Prefixes for site-packages; add additional prefixes like /usr/local here
     78 PREFIXES = [sys.prefix, sys.exec_prefix]
     79 # Enable per user site-packages directory
     80 # set it to False to disable the feature or True to force the feature
     81 ENABLE_USER_SITE = None
     82 
     83 # for distutils.commands.install
     84 # These values are initialized by the getuserbase() and getusersitepackages()
     85 # functions, through the main() function when Python starts.
     86 USER_SITE = None
     87 USER_BASE = None
     88 
     89 
     90 def makepath(*paths):
     91     dir = os.path.join(*paths)
     92     try:
     93         dir = os.path.abspath(dir)
     94     except OSError:
     95         pass
     96     return dir, os.path.normcase(dir)
     97 
     98 
     99 def abs_paths():
    100     """Set all module __file__ and __cached__ attributes to an absolute path"""
    101     for m in set(sys.modules.values()):
    102         if (getattr(getattr(m, '__loader__', None), '__module__', None) not in
    103                 ('_frozen_importlib', '_frozen_importlib_external')):
    104             continue   # don't mess with a PEP 302-supplied __file__
    105         try:
    106             m.__file__ = os.path.abspath(m.__file__)
    107         except (AttributeError, OSError):
    108             pass
    109         try:
    110             m.__cached__ = os.path.abspath(m.__cached__)
    111         except (AttributeError, OSError):
    112             pass
    113 
    114 
    115 def removeduppaths():
    116     """ Remove duplicate entries from sys.path along with making them
    117     absolute"""
    118     # This ensures that the initial path provided by the interpreter contains
    119     # only absolute pathnames, even if we're running from the build directory.
    120     L = []
    121     known_paths = set()
    122     for dir in sys.path:
    123         # Filter out duplicate paths (on case-insensitive file systems also
    124         # if they only differ in case); turn relative paths into absolute
    125         # paths.
    126         dir, dircase = makepath(dir)
    127         if not dircase in known_paths:
    128             L.append(dir)
    129             known_paths.add(dircase)
    130     sys.path[:] = L
    131     return known_paths
    132 
    133 
    134 def _init_pathinfo():
    135     """Return a set containing all existing file system items from sys.path."""
    136     d = set()
    137     for item in sys.path:
    138         try:
    139             if os.path.exists(item):
    140                 _, itemcase = makepath(item)
    141                 d.add(itemcase)
    142         except TypeError:
    143             continue
    144     return d
    145 
    146 
    147 def addpackage(sitedir, name, known_paths):
    148     """Process a .pth file within the site-packages directory:
    149        For each line in the file, either combine it with sitedir to a path
    150        and add that to known_paths, or execute it if it starts with 'import '.
    151     """
    152     if known_paths is None:
    153         known_paths = _init_pathinfo()
    154         reset = True
    155     else:
    156         reset = False
    157     fullname = os.path.join(sitedir, name)
    158     try:
    159         f = open(fullname, "r")
    160     except OSError:
    161         return
    162     with f:
    163         for n, line in enumerate(f):
    164             if line.startswith("#"):
    165                 continue
    166             try:
    167                 if line.startswith(("import ", "import\t")):
    168                     exec(line)
    169                     continue
    170                 line = line.rstrip()
    171                 dir, dircase = makepath(sitedir, line)
    172                 if not dircase in known_paths and os.path.exists(dir):
    173                     sys.path.append(dir)
    174                     known_paths.add(dircase)
    175             except Exception:
    176                 print("Error processing line {:d} of {}:\n".format(n+1, fullname),
    177                       file=sys.stderr)
    178                 import traceback
    179                 for record in traceback.format_exception(*sys.exc_info()):
    180                     for line in record.splitlines():
    181                         print('  '+line, file=sys.stderr)
    182                 print("\nRemainder of file ignored", file=sys.stderr)
    183                 break
    184     if reset:
    185         known_paths = None
    186     return known_paths
    187 
    188 
    189 def addsitedir(sitedir, known_paths=None):
    190     """Add 'sitedir' argument to sys.path if missing and handle .pth files in
    191     'sitedir'"""
    192     if known_paths is None:
    193         known_paths = _init_pathinfo()
    194         reset = True
    195     else:
    196         reset = False
    197     sitedir, sitedircase = makepath(sitedir)
    198     if not sitedircase in known_paths:
    199         sys.path.append(sitedir)        # Add path component
    200         known_paths.add(sitedircase)
    201     try:
    202         names = os.listdir(sitedir)
    203     except OSError:
    204         return
    205     names = [name for name in names if name.endswith(".pth")]
    206     for name in sorted(names):
    207         addpackage(sitedir, name, known_paths)
    208     if reset:
    209         known_paths = None
    210     return known_paths
    211 
    212 
    213 def check_enableusersite():
    214     """Check if user site directory is safe for inclusion
    215 
    216     The function tests for the command line flag (including environment var),
    217     process uid/gid equal to effective uid/gid.
    218 
    219     None: Disabled for security reasons
    220     False: Disabled by user (command line option)
    221     True: Safe and enabled
    222     """
    223     if sys.flags.no_user_site:
    224         return False
    225 
    226     if hasattr(os, "getuid") and hasattr(os, "geteuid"):
    227         # check process uid == effective uid
    228         if os.geteuid() != os.getuid():
    229             return None
    230     if hasattr(os, "getgid") and hasattr(os, "getegid"):
    231         # check process gid == effective gid
    232         if os.getegid() != os.getgid():
    233             return None
    234 
    235     return True
    236 
    237 def getuserbase():
    238     """Returns the `user base` directory path.
    239 
    240     The `user base` directory can be used to store data. If the global
    241     variable ``USER_BASE`` is not initialized yet, this function will also set
    242     it.
    243     """
    244     global USER_BASE
    245     if USER_BASE is not None:
    246         return USER_BASE
    247     from sysconfig import get_config_var
    248     USER_BASE = get_config_var('userbase')
    249     return USER_BASE
    250 
    251 def getusersitepackages():
    252     """Returns the user-specific site-packages directory path.
    253 
    254     If the global variable ``USER_SITE`` is not initialized yet, this
    255     function will also set it.
    256     """
    257     global USER_SITE
    258     user_base = getuserbase() # this will also set USER_BASE
    259 
    260     if USER_SITE is not None:
    261         return USER_SITE
    262 
    263     from sysconfig import get_path
    264 
    265     if sys.platform == 'darwin':
    266         from sysconfig import get_config_var
    267         if get_config_var('PYTHONFRAMEWORK'):
    268             USER_SITE = get_path('purelib', 'osx_framework_user')
    269             return USER_SITE
    270 
    271     USER_SITE = get_path('purelib', '%s_user' % os.name)
    272     return USER_SITE
    273 
    274 def addusersitepackages(known_paths):
    275     """Add a per user site-package to sys.path
    276 
    277     Each user has its own python directory with site-packages in the
    278     home directory.
    279     """
    280     # get the per user site-package path
    281     # this call will also make sure USER_BASE and USER_SITE are set
    282     user_site = getusersitepackages()
    283 
    284     if ENABLE_USER_SITE and os.path.isdir(user_site):
    285         addsitedir(user_site, known_paths)
    286     return known_paths
    287 
    288 def getsitepackages(prefixes=None):
    289     """Returns a list containing all global site-packages directories.
    290 
    291     For each directory present in ``prefixes`` (or the global ``PREFIXES``),
    292     this function will find its `site-packages` subdirectory depending on the
    293     system environment, and will return a list of full paths.
    294     """
    295     sitepackages = []
    296     seen = set()
    297 
    298     if prefixes is None:
    299         prefixes = PREFIXES
    300 
    301     for prefix in prefixes:
    302         if not prefix or prefix in seen:
    303             continue
    304         seen.add(prefix)
    305 
    306         if os.sep == '/':
    307             sitepackages.append(os.path.join(prefix, "lib",
    308                                         "python%d.%d" % sys.version_info[:2],
    309                                         "site-packages"))
    310         else:
    311             sitepackages.append(prefix)
    312             sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
    313         if sys.platform == "darwin":
    314             # for framework builds *only* we add the standard Apple
    315             # locations.
    316             from sysconfig import get_config_var
    317             framework = get_config_var("PYTHONFRAMEWORK")
    318             if framework:
    319                 sitepackages.append(
    320                         os.path.join("/Library", framework,
    321                             '%d.%d' % sys.version_info[:2], "site-packages"))
    322     return sitepackages
    323 
    324 def addsitepackages(known_paths, prefixes=None):
    325     """Add site-packages to sys.path"""
    326     for sitedir in getsitepackages(prefixes):
    327         if os.path.isdir(sitedir):
    328             addsitedir(sitedir, known_paths)
    329 
    330     return known_paths
    331 
    332 def setquit():
    333     """Define new builtins 'quit' and 'exit'.
    334 
    335     These are objects which make the interpreter exit when called.
    336     The repr of each object contains a hint at how it works.
    337 
    338     """
    339     if os.sep == '\\':
    340         eof = 'Ctrl-Z plus Return'
    341     else:
    342         eof = 'Ctrl-D (i.e. EOF)'
    343 
    344     builtins.quit = _sitebuiltins.Quitter('quit', eof)
    345     builtins.exit = _sitebuiltins.Quitter('exit', eof)
    346 
    347 
    348 def setcopyright():
    349     """Set 'copyright' and 'credits' in builtins"""
    350     builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
    351     if sys.platform[:4] == 'java':
    352         builtins.credits = _sitebuiltins._Printer(
    353             "credits",
    354             "Jython is maintained by the Jython developers (www.jython.org).")
    355     else:
    356         builtins.credits = _sitebuiltins._Printer("credits", """\
    357     Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
    358     for supporting Python development.  See www.python.org for more information.""")
    359     files, dirs = [], []
    360     # Not all modules are required to have a __file__ attribute.  See
    361     # PEP 420 for more details.
    362     if hasattr(os, '__file__'):
    363         here = os.path.dirname(os.__file__)
    364         files.extend(["LICENSE.txt", "LICENSE"])
    365         dirs.extend([os.path.join(here, os.pardir), here, os.curdir])
    366     builtins.license = _sitebuiltins._Printer(
    367         "license",
    368         "See https://www.python.org/psf/license/",
    369         files, dirs)
    370 
    371 
    372 def sethelper():
    373     builtins.help = _sitebuiltins._Helper()
    374 
    375 def enablerlcompleter():
    376     """Enable default readline configuration on interactive prompts, by
    377     registering a sys.__interactivehook__.
    378 
    379     If the readline module can be imported, the hook will set the Tab key
    380     as completion key and register ~/.python_history as history file.
    381     This can be overridden in the sitecustomize or usercustomize module,
    382     or in a PYTHONSTARTUP file.
    383     """
    384     def register_readline():
    385         import atexit
    386         try:
    387             import readline
    388             import rlcompleter
    389         except ImportError:
    390             return
    391 
    392         # Reading the initialization (config) file may not be enough to set a
    393         # completion key, so we set one first and then read the file.
    394         readline_doc = getattr(readline, '__doc__', '')
    395         if readline_doc is not None and 'libedit' in readline_doc:
    396             readline.parse_and_bind('bind ^I rl_complete')
    397         else:
    398             readline.parse_and_bind('tab: complete')
    399 
    400         try:
    401             readline.read_init_file()
    402         except OSError:
    403             # An OSError here could have many causes, but the most likely one
    404             # is that there's no .inputrc file (or .editrc file in the case of
    405             # Mac OS X + libedit) in the expected location.  In that case, we
    406             # want to ignore the exception.
    407             pass
    408 
    409         if readline.get_current_history_length() == 0:
    410             # If no history was loaded, default to .python_history.
    411             # The guard is necessary to avoid doubling history size at
    412             # each interpreter exit when readline was already configured
    413             # through a PYTHONSTARTUP hook, see:
    414             # http://bugs.python.org/issue5845#msg198636
    415             history = os.path.join(os.path.expanduser('~'),
    416                                    '.python_history')
    417             try:
    418                 readline.read_history_file(history)
    419             except IOError:
    420                 pass
    421             atexit.register(readline.write_history_file, history)
    422 
    423     sys.__interactivehook__ = register_readline
    424 
    425 def venv(known_paths):
    426     global PREFIXES, ENABLE_USER_SITE
    427 
    428     env = os.environ
    429     if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
    430         executable = os.environ['__PYVENV_LAUNCHER__']
    431     else:
    432         executable = sys.executable
    433     exe_dir, _ = os.path.split(os.path.abspath(executable))
    434     site_prefix = os.path.dirname(exe_dir)
    435     sys._home = None
    436     conf_basename = 'pyvenv.cfg'
    437     candidate_confs = [
    438         conffile for conffile in (
    439             os.path.join(exe_dir, conf_basename),
    440             os.path.join(site_prefix, conf_basename)
    441             )
    442         if os.path.isfile(conffile)
    443         ]
    444 
    445     if candidate_confs:
    446         virtual_conf = candidate_confs[0]
    447         system_site = "true"
    448         # Issue 25185: Use UTF-8, as that's what the venv module uses when
    449         # writing the file.
    450         with open(virtual_conf, encoding='utf-8') as f:
    451             for line in f:
    452                 if '=' in line:
    453                     key, _, value = line.partition('=')
    454                     key = key.strip().lower()
    455                     value = value.strip()
    456                     if key == 'include-system-site-packages':
    457                         system_site = value.lower()
    458                     elif key == 'home':
    459                         sys._home = value
    460 
    461         sys.prefix = sys.exec_prefix = site_prefix
    462 
    463         # Doing this here ensures venv takes precedence over user-site
    464         addsitepackages(known_paths, [sys.prefix])
    465 
    466         # addsitepackages will process site_prefix again if its in PREFIXES,
    467         # but that's ok; known_paths will prevent anything being added twice
    468         if system_site == "true":
    469             PREFIXES.insert(0, sys.prefix)
    470         else:
    471             PREFIXES = [sys.prefix]
    472             ENABLE_USER_SITE = False
    473 
    474     return known_paths
    475 
    476 
    477 def execsitecustomize():
    478     """Run custom site specific code, if available."""
    479     try:
    480         try:
    481             import sitecustomize
    482         except ImportError as exc:
    483             if exc.name == 'sitecustomize':
    484                 pass
    485             else:
    486                 raise
    487     except Exception as err:
    488         if sys.flags.verbose:
    489             sys.excepthook(*sys.exc_info())
    490         else:
    491             sys.stderr.write(
    492                 "Error in sitecustomize; set PYTHONVERBOSE for traceback:\n"
    493                 "%s: %s\n" %
    494                 (err.__class__.__name__, err))
    495 
    496 
    497 def execusercustomize():
    498     """Run custom user specific code, if available."""
    499     try:
    500         try:
    501             import usercustomize
    502         except ImportError as exc:
    503             if exc.name == 'usercustomize':
    504                 pass
    505             else:
    506                 raise
    507     except Exception as err:
    508         if sys.flags.verbose:
    509             sys.excepthook(*sys.exc_info())
    510         else:
    511             sys.stderr.write(
    512                 "Error in usercustomize; set PYTHONVERBOSE for traceback:\n"
    513                 "%s: %s\n" %
    514                 (err.__class__.__name__, err))
    515 
    516 
    517 def main():
    518     """Add standard site-specific directories to the module search path.
    519 
    520     This function is called automatically when this module is imported,
    521     unless the python interpreter was started with the -S flag.
    522     """
    523     global ENABLE_USER_SITE
    524 
    525     abs_paths()
    526     known_paths = removeduppaths()
    527     known_paths = venv(known_paths)
    528     if ENABLE_USER_SITE is None:
    529         ENABLE_USER_SITE = check_enableusersite()
    530     known_paths = addusersitepackages(known_paths)
    531     known_paths = addsitepackages(known_paths)
    532     setquit()
    533     setcopyright()
    534     sethelper()
    535     if not sys.flags.isolated:
    536         enablerlcompleter()
    537     execsitecustomize()
    538     if ENABLE_USER_SITE:
    539         execusercustomize()
    540 
    541 # Prevent extending of sys.path when python was started with -S and
    542 # site is imported later.
    543 if not sys.flags.no_site:
    544     main()
    545 
    546 def _script():
    547     help = """\
    548     %s [--user-base] [--user-site]
    549 
    550     Without arguments print some useful information
    551     With arguments print the value of USER_BASE and/or USER_SITE separated
    552     by '%s'.
    553 
    554     Exit codes with --user-base or --user-site:
    555       0 - user site directory is enabled
    556       1 - user site directory is disabled by user
    557       2 - uses site directory is disabled by super user
    558           or for security reasons
    559      >2 - unknown error
    560     """
    561     args = sys.argv[1:]
    562     if not args:
    563         user_base = getuserbase()
    564         user_site = getusersitepackages()
    565         print("sys.path = [")
    566         for dir in sys.path:
    567             print("    %r," % (dir,))
    568         print("]")
    569         print("USER_BASE: %r (%s)" % (user_base,
    570             "exists" if os.path.isdir(user_base) else "doesn't exist"))
    571         print("USER_SITE: %r (%s)" % (user_site,
    572             "exists" if os.path.isdir(user_site) else "doesn't exist"))
    573         print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
    574         sys.exit(0)
    575 
    576     buffer = []
    577     if '--user-base' in args:
    578         buffer.append(USER_BASE)
    579     if '--user-site' in args:
    580         buffer.append(USER_SITE)
    581 
    582     if buffer:
    583         print(os.pathsep.join(buffer))
    584         if ENABLE_USER_SITE:
    585             sys.exit(0)
    586         elif ENABLE_USER_SITE is False:
    587             sys.exit(1)
    588         elif ENABLE_USER_SITE is None:
    589             sys.exit(2)
    590         else:
    591             sys.exit(3)
    592     else:
    593         import textwrap
    594         print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
    595         sys.exit(10)
    596 
    597 if __name__ == '__main__':
    598     _script()
    599