1"""Append module search paths for third-party packages to sys.path.
2
3****************************************************************
4* This module is automatically imported during initialization. *
5****************************************************************
6
7In earlier versions of Python (up to 1.5a3), scripts or modules that
8needed to use site-specific modules would place ``import site''
9somewhere near the top of their code.  Because of the automatic
10import, this is no longer necessary (but code that does it still
11works).
12
13This will append site-specific paths to the module search path.  On
14Unix (including Mac OSX), it starts with sys.prefix and
15sys.exec_prefix (if different) and appends
16lib/python<version>/site-packages as well as lib/site-python.
17On other platforms (such as Windows), it tries each of the
18prefixes directly, as well as with lib/site-packages appended.  The
19resulting directories, if they exist, are appended to sys.path, and
20also inspected for path configuration files.
21
22A path configuration file is a file whose name has the form
23<package>.pth; its contents are additional directories (one per line)
24to be added to sys.path.  Non-existing directories (or
25non-directories) are never added to sys.path; no directory is added to
26sys.path more than once.  Blank lines and lines beginning with
27'#' are skipped. Lines starting with 'import' are executed.
28
29For 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
31with three subdirectories, foo, bar and spam, and two path
32configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
33following:
34
35  # foo package configuration
36  foo
37  bar
38  bletch
39
40and bar.pth contains:
41
42  # bar package configuration
43  bar
44
45Then 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
50Note that bletch is omitted because it doesn't exist; bar precedes foo
51because bar.pth comes alphabetically before foo.pth; and spam is
52omitted because it is not mentioned in either path configuration file.
53
54After these path manipulations, an attempt is made to import a module
55named sitecustomize, which can perform arbitrary additional
56site-specific customizations.  If this import fails with an
57ImportError exception, it is silently ignored.
58
59"""
60
61import sys
62import os
63import __builtin__
64import traceback
65
66# Prefixes for site-packages; add additional prefixes like /usr/local here
67PREFIXES = [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
70ENABLE_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.
75USER_SITE = None
76USER_BASE = None
77
78
79def 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
88def 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
99def 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
118def _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
131def 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
172def 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
196def 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
220def 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
234def 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
258def 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
272def 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" + "-legacy",
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
300def 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
308def 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
325def 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
356class _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
417def 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
435class _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
448def sethelper():
449    __builtin__.help = _Helper()
450
451def 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
466def 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
486def 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
500def 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
514def 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
539main()
540
541def _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
590if __name__ == '__main__':
591    _script()
592