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 In earlier versions of Python (up to 1.5a3), scripts or modules that
      8 needed to use site-specific modules would place ``import site''
      9 somewhere near the top of their code.  Because of the automatic
     10 import, this is no longer necessary (but code that does it still
     11 works).
     12 
     13 This will append site-specific paths to the module search path.  On
     14 Unix (including Mac OSX), it starts with sys.prefix and
     15 sys.exec_prefix (if different) and appends
     16 lib/python<version>/site-packages as well as lib/site-python.
     17 On other platforms (such as Windows), it tries each of the
     18 prefixes directly, as well as with lib/site-packages appended.  The
     19 resulting directories, if they exist, are appended to sys.path, and
     20 also inspected for path configuration files.
     21 
     22 A path configuration file is a file whose name has the form
     23 <package>.pth; its contents are additional directories (one per line)
     24 to be added to sys.path.  Non-existing directories (or
     25 non-directories) are never added to sys.path; no directory is added to
     26 sys.path more than once.  Blank lines and lines beginning with
     27 '#' are skipped. Lines starting with 'import' are executed.
     28 
     29 For example, suppose sys.prefix and sys.exec_prefix are set to
     30 /usr/local and there is a directory /usr/local/lib/python2.5/site-packages
     31 with three subdirectories, foo, bar and spam, and two path
     32 configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
     33 following:
     34 
     35   # foo package configuration
     36   foo
     37   bar
     38   bletch
     39 
     40 and bar.pth contains:
     41 
     42   # bar package configuration
     43   bar
     44 
     45 Then the following directories are added to sys.path, in this order:
     46 
     47   /usr/local/lib/python2.5/site-packages/bar
     48   /usr/local/lib/python2.5/site-packages/foo
     49 
     50 Note that bletch is omitted because it doesn't exist; bar precedes foo
     51 because bar.pth comes alphabetically before foo.pth; and spam is
     52 omitted because it is not mentioned in either path configuration file.
     53 
     54 After these path manipulations, an attempt is made to import a module
     55 named sitecustomize, which can perform arbitrary additional
     56 site-specific customizations.  If this import fails with an
     57 ImportError exception, it is silently ignored.
     58 
     59 """
     60 
     61 import sys
     62 import os
     63 import __builtin__
     64 import traceback
     65 
     66 # Prefixes for site-packages; add additional prefixes like /usr/local here
     67 PREFIXES = [sys.prefix, sys.exec_prefix]
     68 # Enable per user site-packages directory
     69 # set it to False to disable the feature or True to force the feature
     70 ENABLE_USER_SITE = None
     71 
     72 # for distutils.commands.install
     73 # These values are initialized by the getuserbase() and getusersitepackages()
     74 # functions, through the main() function when Python starts.
     75 USER_SITE = None
     76 USER_BASE = None
     77 
     78 
     79 def makepath(*paths):
     80     dir = os.path.join(*paths)
     81     try:
     82         dir = os.path.abspath(dir)
     83     except OSError:
     84         pass
     85     return dir, os.path.normcase(dir)
     86 
     87 
     88 def abs__file__():
     89     """Set all module' __file__ attribute to an absolute path"""
     90     for m in sys.modules.values():
     91         if hasattr(m, '__loader__'):
     92             continue   # don't mess with a PEP 302-supplied __file__
     93         try:
     94             m.__file__ = os.path.abspath(m.__file__)
     95         except (AttributeError, OSError):
     96             pass
     97 
     98 
     99 def removeduppaths():
    100     """ Remove duplicate entries from sys.path along with making them
    101     absolute"""
    102     # This ensures that the initial path provided by the interpreter contains
    103     # only absolute pathnames, even if we're running from the build directory.
    104     L = []
    105     known_paths = set()
    106     for dir in sys.path:
    107         # Filter out duplicate paths (on case-insensitive file systems also
    108         # if they only differ in case); turn relative paths into absolute
    109         # paths.
    110         dir, dircase = makepath(dir)
    111         if not dircase in known_paths:
    112             L.append(dir)
    113             known_paths.add(dircase)
    114     sys.path[:] = L
    115     return known_paths
    116 
    117 
    118 def _init_pathinfo():
    119     """Return a set containing all existing directory entries from sys.path"""
    120     d = set()
    121     for dir in sys.path:
    122         try:
    123             if os.path.isdir(dir):
    124                 dir, dircase = makepath(dir)
    125                 d.add(dircase)
    126         except TypeError:
    127             continue
    128     return d
    129 
    130 
    131 def addpackage(sitedir, name, known_paths):
    132     """Process a .pth file within the site-packages directory:
    133        For each line in the file, either combine it with sitedir to a path
    134        and add that to known_paths, or execute it if it starts with 'import '.
    135     """
    136     if known_paths is None:
    137         _init_pathinfo()
    138         reset = 1
    139     else:
    140         reset = 0
    141     fullname = os.path.join(sitedir, name)
    142     try:
    143         f = open(fullname, "rU")
    144     except IOError:
    145         return
    146     with f:
    147         for n, line in enumerate(f):
    148             if line.startswith("#"):
    149                 continue
    150             try:
    151                 if line.startswith(("import ", "import\t")):
    152                     exec line
    153                     continue
    154                 line = line.rstrip()
    155                 dir, dircase = makepath(sitedir, line)
    156                 if not dircase in known_paths and os.path.exists(dir):
    157                     sys.path.append(dir)
    158                     known_paths.add(dircase)
    159             except Exception as err:
    160                 print >>sys.stderr, "Error processing line {:d} of {}:\n".format(
    161                     n+1, fullname)
    162                 for record in traceback.format_exception(*sys.exc_info()):
    163                     for line in record.splitlines():
    164                         print >>sys.stderr, '  '+line
    165                 print >>sys.stderr, "\nRemainder of file ignored"
    166                 break
    167     if reset:
    168         known_paths = None
    169     return known_paths
    170 
    171 
    172 def addsitedir(sitedir, known_paths=None):
    173     """Add 'sitedir' argument to sys.path if missing and handle .pth files in
    174     'sitedir'"""
    175     if known_paths is None:
    176         known_paths = _init_pathinfo()
    177         reset = 1
    178     else:
    179         reset = 0
    180     sitedir, sitedircase = makepath(sitedir)
    181     if not sitedircase in known_paths:
    182         sys.path.append(sitedir)        # Add path component
    183     try:
    184         names = os.listdir(sitedir)
    185     except os.error:
    186         return
    187     dotpth = os.extsep + "pth"
    188     names = [name for name in names if name.endswith(dotpth)]
    189     for name in sorted(names):
    190         addpackage(sitedir, name, known_paths)
    191     if reset:
    192         known_paths = None
    193     return known_paths
    194 
    195 
    196 def check_enableusersite():
    197     """Check if user site directory is safe for inclusion
    198 
    199     The function tests for the command line flag (including environment var),
    200     process uid/gid equal to effective uid/gid.
    201 
    202     None: Disabled for security reasons
    203     False: Disabled by user (command line option)
    204     True: Safe and enabled
    205     """
    206     if sys.flags.no_user_site:
    207         return False
    208 
    209     if hasattr(os, "getuid") and hasattr(os, "geteuid"):
    210         # check process uid == effective uid
    211         if os.geteuid() != os.getuid():
    212             return None
    213     if hasattr(os, "getgid") and hasattr(os, "getegid"):
    214         # check process gid == effective gid
    215         if os.getegid() != os.getgid():
    216             return None
    217 
    218     return True
    219 
    220 def getuserbase():
    221     """Returns the `user base` directory path.
    222 
    223     The `user base` directory can be used to store data. If the global
    224     variable ``USER_BASE`` is not initialized yet, this function will also set
    225     it.
    226     """
    227     global USER_BASE
    228     if USER_BASE is not None:
    229         return USER_BASE
    230     from sysconfig import get_config_var
    231     USER_BASE = get_config_var('userbase')
    232     return USER_BASE
    233 
    234 def getusersitepackages():
    235     """Returns the user-specific site-packages directory path.
    236 
    237     If the global variable ``USER_SITE`` is not initialized yet, this
    238     function will also set it.
    239     """
    240     global USER_SITE
    241     user_base = getuserbase() # this will also set USER_BASE
    242 
    243     if USER_SITE is not None:
    244         return USER_SITE
    245 
    246     from sysconfig import get_path
    247     import os
    248 
    249     if sys.platform == 'darwin':
    250         from sysconfig import get_config_var
    251         if get_config_var('PYTHONFRAMEWORK'):
    252             USER_SITE = get_path('purelib', 'osx_framework_user')
    253             return USER_SITE
    254 
    255     USER_SITE = get_path('purelib', '%s_user' % os.name)
    256     return USER_SITE
    257 
    258 def addusersitepackages(known_paths):
    259     """Add a per user site-package to sys.path
    260 
    261     Each user has its own python directory with site-packages in the
    262     home directory.
    263     """
    264     # get the per user site-package path
    265     # this call will also make sure USER_BASE and USER_SITE are set
    266     user_site = getusersitepackages()
    267 
    268     if ENABLE_USER_SITE and os.path.isdir(user_site):
    269         addsitedir(user_site, known_paths)
    270     return known_paths
    271 
    272 def getsitepackages():
    273     """Returns a list containing all global site-packages directories
    274     (and possibly site-python).
    275 
    276     For each directory present in the global ``PREFIXES``, this function
    277     will find its `site-packages` subdirectory depending on the system
    278     environment, and will return a list of full paths.
    279     """
    280     sitepackages = []
    281     seen = set()
    282 
    283     for prefix in PREFIXES:
    284         if not prefix or prefix in seen:
    285             continue
    286         seen.add(prefix)
    287 
    288         if sys.platform in ('os2emx', 'riscos'):
    289             sitepackages.append(os.path.join(prefix, "Lib", "site-packages"))
    290         elif os.sep == '/':
    291             sitepackages.append(os.path.join(prefix, "lib",
    292                                         "python" + sys.version[:3],
    293                                         "site-packages"))
    294             sitepackages.append(os.path.join(prefix, "lib", "site-python"))
    295         else:
    296             sitepackages.append(prefix)
    297             sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
    298     return sitepackages
    299 
    300 def addsitepackages(known_paths):
    301     """Add site-packages (and possibly site-python) to sys.path"""
    302     for sitedir in getsitepackages():
    303         if os.path.isdir(sitedir):
    304             addsitedir(sitedir, known_paths)
    305 
    306     return known_paths
    307 
    308 def setBEGINLIBPATH():
    309     """The OS/2 EMX port has optional extension modules that do double duty
    310     as DLLs (and must use the .DLL file extension) for other extensions.
    311     The library search path needs to be amended so these will be found
    312     during module import.  Use BEGINLIBPATH so that these are at the start
    313     of the library search path.
    314 
    315     """
    316     dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
    317     libpath = os.environ['BEGINLIBPATH'].split(';')
    318     if libpath[-1]:
    319         libpath.append(dllpath)
    320     else:
    321         libpath[-1] = dllpath
    322     os.environ['BEGINLIBPATH'] = ';'.join(libpath)
    323 
    324 
    325 def setquit():
    326     """Define new builtins 'quit' and 'exit'.
    327 
    328     These are objects which make the interpreter exit when called.
    329     The repr of each object contains a hint at how it works.
    330 
    331     """
    332     if os.sep == ':':
    333         eof = 'Cmd-Q'
    334     elif os.sep == '\\':
    335         eof = 'Ctrl-Z plus Return'
    336     else:
    337         eof = 'Ctrl-D (i.e. EOF)'
    338 
    339     class Quitter(object):
    340         def __init__(self, name):
    341             self.name = name
    342         def __repr__(self):
    343             return 'Use %s() or %s to exit' % (self.name, eof)
    344         def __call__(self, code=None):
    345             # Shells like IDLE catch the SystemExit, but listen when their
    346             # stdin wrapper is closed.
    347             try:
    348                 sys.stdin.close()
    349             except:
    350                 pass
    351             raise SystemExit(code)
    352     __builtin__.quit = Quitter('quit')
    353     __builtin__.exit = Quitter('exit')
    354 
    355 
    356 class _Printer(object):
    357     """interactive prompt objects for printing the license text, a list of
    358     contributors and the copyright notice."""
    359 
    360     MAXLINES = 23
    361 
    362     def __init__(self, name, data, files=(), dirs=()):
    363         self.__name = name
    364         self.__data = data
    365         self.__files = files
    366         self.__dirs = dirs
    367         self.__lines = None
    368 
    369     def __setup(self):
    370         if self.__lines:
    371             return
    372         data = None
    373         for dir in self.__dirs:
    374             for filename in self.__files:
    375                 filename = os.path.join(dir, filename)
    376                 try:
    377                     fp = file(filename, "rU")
    378                     data = fp.read()
    379                     fp.close()
    380                     break
    381                 except IOError:
    382                     pass
    383             if data:
    384                 break
    385         if not data:
    386             data = self.__data
    387         self.__lines = data.split('\n')
    388         self.__linecnt = len(self.__lines)
    389 
    390     def __repr__(self):
    391         self.__setup()
    392         if len(self.__lines) <= self.MAXLINES:
    393             return "\n".join(self.__lines)
    394         else:
    395             return "Type %s() to see the full %s text" % ((self.__name,)*2)
    396 
    397     def __call__(self):
    398         self.__setup()
    399         prompt = 'Hit Return for more, or q (and Return) to quit: '
    400         lineno = 0
    401         while 1:
    402             try:
    403                 for i in range(lineno, lineno + self.MAXLINES):
    404                     print self.__lines[i]
    405             except IndexError:
    406                 break
    407             else:
    408                 lineno += self.MAXLINES
    409                 key = None
    410                 while key is None:
    411                     key = raw_input(prompt)
    412                     if key not in ('', 'q'):
    413                         key = None
    414                 if key == 'q':
    415                     break
    416 
    417 def setcopyright():
    418     """Set 'copyright' and 'credits' in __builtin__"""
    419     __builtin__.copyright = _Printer("copyright", sys.copyright)
    420     if sys.platform[:4] == 'java':
    421         __builtin__.credits = _Printer(
    422             "credits",
    423             "Jython is maintained by the Jython developers (www.jython.org).")
    424     else:
    425         __builtin__.credits = _Printer("credits", """\
    426     Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
    427     for supporting Python development.  See www.python.org for more information.""")
    428     here = os.path.dirname(os.__file__)
    429     __builtin__.license = _Printer(
    430         "license", "See https://www.python.org/psf/license/",
    431         ["LICENSE.txt", "LICENSE"],
    432         [os.path.join(here, os.pardir), here, os.curdir])
    433 
    434 
    435 class _Helper(object):
    436     """Define the builtin 'help'.
    437     This is a wrapper around pydoc.help (with a twist).
    438 
    439     """
    440 
    441     def __repr__(self):
    442         return "Type help() for interactive help, " \
    443                "or help(object) for help about object."
    444     def __call__(self, *args, **kwds):
    445         import pydoc
    446         return pydoc.help(*args, **kwds)
    447 
    448 def sethelper():
    449     __builtin__.help = _Helper()
    450 
    451 def aliasmbcs():
    452     """On Windows, some default encodings are not provided by Python,
    453     while they are always available as "mbcs" in each locale. Make
    454     them usable by aliasing to "mbcs" in such a case."""
    455     if sys.platform == 'win32':
    456         import locale, codecs
    457         enc = locale.getdefaultlocale()[1]
    458         if enc.startswith('cp'):            # "cp***" ?
    459             try:
    460                 codecs.lookup(enc)
    461             except LookupError:
    462                 import encodings
    463                 encodings._cache[enc] = encodings._unknown
    464                 encodings.aliases.aliases[enc] = 'mbcs'
    465 
    466 def setencoding():
    467     """Set the string encoding used by the Unicode implementation.  The
    468     default is 'ascii', but if you're willing to experiment, you can
    469     change this."""
    470     encoding = "ascii" # Default value set by _PyUnicode_Init()
    471     if 0:
    472         # Enable to support locale aware default string encodings.
    473         import locale
    474         loc = locale.getdefaultlocale()
    475         if loc[1]:
    476             encoding = loc[1]
    477     if 0:
    478         # Enable to switch off string to Unicode coercion and implicit
    479         # Unicode to string conversion.
    480         encoding = "undefined"
    481     if encoding != "ascii":
    482         # On Non-Unicode builds this will raise an AttributeError...
    483         sys.setdefaultencoding(encoding) # Needs Python Unicode build !
    484 
    485 
    486 def execsitecustomize():
    487     """Run custom site specific code, if available."""
    488     try:
    489         import sitecustomize
    490     except ImportError:
    491         pass
    492     except Exception:
    493         if sys.flags.verbose:
    494             sys.excepthook(*sys.exc_info())
    495         else:
    496             print >>sys.stderr, \
    497                 "'import sitecustomize' failed; use -v for traceback"
    498 
    499 
    500 def execusercustomize():
    501     """Run custom user specific code, if available."""
    502     try:
    503         import usercustomize
    504     except ImportError:
    505         pass
    506     except Exception:
    507         if sys.flags.verbose:
    508             sys.excepthook(*sys.exc_info())
    509         else:
    510             print>>sys.stderr, \
    511                 "'import usercustomize' failed; use -v for traceback"
    512 
    513 
    514 def main():
    515     global ENABLE_USER_SITE
    516 
    517     abs__file__()
    518     known_paths = removeduppaths()
    519     if ENABLE_USER_SITE is None:
    520         ENABLE_USER_SITE = check_enableusersite()
    521     known_paths = addusersitepackages(known_paths)
    522     known_paths = addsitepackages(known_paths)
    523     if sys.platform == 'os2emx':
    524         setBEGINLIBPATH()
    525     setquit()
    526     setcopyright()
    527     sethelper()
    528     aliasmbcs()
    529     setencoding()
    530     execsitecustomize()
    531     if ENABLE_USER_SITE:
    532         execusercustomize()
    533     # Remove sys.setdefaultencoding() so that users cannot change the
    534     # encoding after initialization.  The test for presence is needed when
    535     # this module is run as a script, because this code is executed twice.
    536     if hasattr(sys, "setdefaultencoding"):
    537         del sys.setdefaultencoding
    538 
    539 main()
    540 
    541 def _script():
    542     help = """\
    543     %s [--user-base] [--user-site]
    544 
    545     Without arguments print some useful information
    546     With arguments print the value of USER_BASE and/or USER_SITE separated
    547     by '%s'.
    548 
    549     Exit codes with --user-base or --user-site:
    550       0 - user site directory is enabled
    551       1 - user site directory is disabled by user
    552       2 - uses site directory is disabled by super user
    553           or for security reasons
    554      >2 - unknown error
    555     """
    556     args = sys.argv[1:]
    557     if not args:
    558         print "sys.path = ["
    559         for dir in sys.path:
    560             print "    %r," % (dir,)
    561         print "]"
    562         print "USER_BASE: %r (%s)" % (USER_BASE,
    563             "exists" if os.path.isdir(USER_BASE) else "doesn't exist")
    564         print "USER_SITE: %r (%s)" % (USER_SITE,
    565             "exists" if os.path.isdir(USER_SITE) else "doesn't exist")
    566         print "ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE
    567         sys.exit(0)
    568 
    569     buffer = []
    570     if '--user-base' in args:
    571         buffer.append(USER_BASE)
    572     if '--user-site' in args:
    573         buffer.append(USER_SITE)
    574 
    575     if buffer:
    576         print os.pathsep.join(buffer)
    577         if ENABLE_USER_SITE:
    578             sys.exit(0)
    579         elif ENABLE_USER_SITE is False:
    580             sys.exit(1)
    581         elif ENABLE_USER_SITE is None:
    582             sys.exit(2)
    583         else:
    584             sys.exit(3)
    585     else:
    586         import textwrap
    587         print textwrap.dedent(help % (sys.argv[0], os.pathsep))
    588         sys.exit(10)
    589 
    590 if __name__ == '__main__':
    591     _script()
    592