source: python/trunk/Lib/site.py@ 383

Last change on this file since 383 was 383, checked in by dmik, 11 years ago

Restore original dynamic 'sys.prefix' detection.

This in particular reverts r20 and parts of r10. These hacks are not
necessary after properly defining 'sys.path' entries in 'site.py'.

  • Property svn:eol-style set to native
File size: 18.4 KB
Line 
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__
64
65# Prefixes for site-packages; add additional prefixes like /usr/local here
66PREFIXES = [sys.prefix, sys.exec_prefix]
67# Enable per user site-packages directory
68# set it to False to disable the feature or True to force the feature
69ENABLE_USER_SITE = None
70# for distutils.commands.install
71USER_SITE = None
72USER_BASE = None
73
74
75def makepath(*paths):
76 dir = os.path.abspath(os.path.join(*paths))
77 return dir, os.path.normcase(dir)
78
79
80def abs__file__():
81 """Set all module' __file__ attribute to an absolute path"""
82 for m in sys.modules.values():
83 if hasattr(m, '__loader__'):
84 continue # don't mess with a PEP 302-supplied __file__
85 try:
86 m.__file__ = os.path.abspath(m.__file__)
87 except AttributeError:
88 continue
89
90
91def removeduppaths():
92 """ Remove duplicate entries from sys.path along with making them
93 absolute"""
94 # This ensures that the initial path provided by the interpreter contains
95 # only absolute pathnames, even if we're running from the build directory.
96 L = []
97 known_paths = set()
98 for dir in sys.path:
99 # Filter out duplicate paths (on case-insensitive file systems also
100 # if they only differ in case); turn relative paths into absolute
101 # paths.
102 dir, dircase = makepath(dir)
103 if not dircase in known_paths:
104 L.append(dir)
105 known_paths.add(dircase)
106 sys.path[:] = L
107 return known_paths
108
109# XXX This should not be part of site.py, since it is needed even when
110# using the -S option for Python. See http://www.python.org/sf/586680
111def addbuilddir():
112 """Append ./build/lib.<platform> in case we're running in the build dir
113 (especially for Guido :-)"""
114 from distutils.util import get_platform
115 s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
116 if hasattr(sys, 'gettotalrefcount'):
117 s += '-pydebug'
118 s = os.path.join(os.path.dirname(sys.path[-1]), s)
119 sys.path.append(s)
120
121
122def _init_pathinfo():
123 """Return a set containing all existing directory entries from sys.path"""
124 d = set()
125 for dir in sys.path:
126 try:
127 if os.path.isdir(dir):
128 dir, dircase = makepath(dir)
129 d.add(dircase)
130 except TypeError:
131 continue
132 return d
133
134
135def addpackage(sitedir, name, known_paths):
136 """Process a .pth file within the site-packages directory:
137 For each line in the file, either combine it with sitedir to a path
138 and add that to known_paths, or execute it if it starts with 'import '.
139 """
140 if known_paths is None:
141 _init_pathinfo()
142 reset = 1
143 else:
144 reset = 0
145 fullname = os.path.join(sitedir, name)
146 try:
147 f = open(fullname, "rU")
148 except IOError:
149 return
150 with f:
151 for line in f:
152 if line.startswith("#"):
153 continue
154 if line.startswith(("import ", "import\t")):
155 exec line
156 continue
157 line = line.rstrip()
158 dir, dircase = makepath(sitedir, line)
159 if not dircase in known_paths and os.path.exists(dir):
160 sys.path.append(dir)
161 known_paths.add(dircase)
162 if reset:
163 known_paths = None
164 return known_paths
165
166
167def addsitedir(sitedir, known_paths=None):
168 """Add 'sitedir' argument to sys.path if missing and handle .pth files in
169 'sitedir'"""
170 if known_paths is None:
171 known_paths = _init_pathinfo()
172 reset = 1
173 else:
174 reset = 0
175 sitedir, sitedircase = makepath(sitedir)
176 if not sitedircase in known_paths:
177 sys.path.append(sitedir) # Add path component
178 try:
179 names = os.listdir(sitedir)
180 except os.error:
181 return
182 dotpth = os.extsep + "pth"
183 names = [name for name in names if name.endswith(dotpth)]
184 for name in sorted(names):
185 addpackage(sitedir, name, known_paths)
186 if reset:
187 known_paths = None
188 return known_paths
189
190
191def check_enableusersite():
192 """Check if user site directory is safe for inclusion
193
194 The function tests for the command line flag (including environment var),
195 process uid/gid equal to effective uid/gid.
196
197 None: Disabled for security reasons
198 False: Disabled by user (command line option)
199 True: Safe and enabled
200 """
201 if sys.flags.no_user_site:
202 return False
203
204 if hasattr(os, "getuid") and hasattr(os, "geteuid"):
205 # check process uid == effective uid
206 if os.geteuid() != os.getuid():
207 return None
208 if hasattr(os, "getgid") and hasattr(os, "getegid"):
209 # check process gid == effective gid
210 if os.getegid() != os.getgid():
211 return None
212
213 return True
214
215
216def addusersitepackages(known_paths):
217 """Add a per user site-package to sys.path
218
219 Each user has its own python directory with site-packages in the
220 home directory.
221
222 USER_BASE is the root directory for all Python versions
223
224 USER_SITE is the user specific site-packages directory
225
226 USER_SITE/.. can be used for data.
227 """
228 global USER_BASE, USER_SITE, ENABLE_USER_SITE
229 env_base = os.environ.get("PYTHONUSERBASE", None)
230
231 def joinuser(*args):
232 return os.path.expanduser(os.path.join(*args))
233
234 #if sys.platform in ('os2emx', 'os2knix', 'riscos'):
235 # # Don't know what to put here
236 # USER_BASE = ''
237 # USER_SITE = ''
238 if os.name == "nt":
239 base = os.environ.get("APPDATA") or "~"
240 USER_BASE = env_base if env_base else joinuser(base, "Python")
241 USER_SITE = os.path.join(USER_BASE,
242 "Python" + sys.version[0] + sys.version[2],
243 "site-packages")
244 else:
245 USER_BASE = env_base if env_base else joinuser("~", ".local")
246 USER_SITE = os.path.join(USER_BASE, "lib",
247 "python" + sys.version[:3],
248 "site-packages")
249
250 if ENABLE_USER_SITE and os.path.isdir(USER_SITE):
251 addsitedir(USER_SITE, known_paths)
252 return known_paths
253
254
255def addsitepackages(known_paths):
256 """Add site-packages (and possibly site-python) to sys.path"""
257 sitedirs = []
258 seen = []
259
260 for prefix in PREFIXES:
261 if not prefix or prefix in seen:
262 continue
263 seen.append(prefix)
264
265 if sys.platform in ('os2emx', 'riscos'):
266 sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
267 elif sys.platform == 'os2knix':
268 sitedirs.append(os.path.join(prefix, "lib",
269 "python" + sys.version[:3],
270 "site-packages"))
271 sitedirs.append(os.path.join(prefix, "lib", "site-packages"))
272 elif os.sep == '/':
273 sitedirs.append(os.path.join(prefix, "lib",
274 "python" + sys.version[:3],
275 "site-packages"))
276 sitedirs.append(os.path.join(prefix, "lib", "site-python"))
277 else:
278 sitedirs.append(prefix)
279 sitedirs.append(os.path.join(prefix, "lib", "site-packages"))
280
281 if sys.platform == "darwin":
282 # for framework builds *only* we add the standard Apple
283 # locations. Currently only per-user, but /Library and
284 # /Network/Library could be added too
285 if 'Python.framework' in prefix:
286 sitedirs.append(
287 os.path.expanduser(
288 os.path.join("~", "Library", "Python",
289 sys.version[:3], "site-packages")))
290
291 for sitedir in sitedirs:
292 if os.path.isdir(sitedir):
293 addsitedir(sitedir, known_paths)
294
295 return known_paths
296
297
298def setBEGINLIBPATH():
299 """The OS/2 EMX port has optional extension modules that do double duty
300 as DLLs (and must use the .DLL file extension) for other extensions.
301 The library search path needs to be amended so these will be found
302 during module import. Use BEGINLIBPATH so that these are at the start
303 of the library search path.
304
305 """
306 dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
307 libpath = os.environ['BEGINLIBPATH'].split(';')
308 if libpath[-1]:
309 libpath.append(dllpath)
310 else:
311 libpath[-1] = dllpath
312 os.environ['BEGINLIBPATH'] = ';'.join(libpath)
313
314
315def setquit():
316 """Define new built-ins 'quit' and 'exit'.
317 These are simply strings that display a hint on how to exit.
318
319 """
320 if os.sep == ':':
321 eof = 'Cmd-Q'
322 elif os.sep == '\\':
323 eof = 'Ctrl-Z plus Return'
324 else:
325 eof = 'Ctrl-D (i.e. EOF)'
326
327 class Quitter(object):
328 def __init__(self, name):
329 self.name = name
330 def __repr__(self):
331 return 'Use %s() or %s to exit' % (self.name, eof)
332 def __call__(self, code=None):
333 # Shells like IDLE catch the SystemExit, but listen when their
334 # stdin wrapper is closed.
335 try:
336 sys.stdin.close()
337 except:
338 pass
339 raise SystemExit(code)
340 __builtin__.quit = Quitter('quit')
341 __builtin__.exit = Quitter('exit')
342
343
344class _Printer(object):
345 """interactive prompt objects for printing the license text, a list of
346 contributors and the copyright notice."""
347
348 MAXLINES = 23
349
350 def __init__(self, name, data, files=(), dirs=()):
351 self.__name = name
352 self.__data = data
353 self.__files = files
354 self.__dirs = dirs
355 self.__lines = None
356
357 def __setup(self):
358 if self.__lines:
359 return
360 data = None
361 for dir in self.__dirs:
362 for filename in self.__files:
363 filename = os.path.join(dir, filename)
364 try:
365 fp = file(filename, "rU")
366 data = fp.read()
367 fp.close()
368 break
369 except IOError:
370 pass
371 if data:
372 break
373 if not data:
374 data = self.__data
375 self.__lines = data.split('\n')
376 self.__linecnt = len(self.__lines)
377
378 def __repr__(self):
379 self.__setup()
380 if len(self.__lines) <= self.MAXLINES:
381 return "\n".join(self.__lines)
382 else:
383 return "Type %s() to see the full %s text" % ((self.__name,)*2)
384
385 def __call__(self):
386 self.__setup()
387 prompt = 'Hit Return for more, or q (and Return) to quit: '
388 lineno = 0
389 while 1:
390 try:
391 for i in range(lineno, lineno + self.MAXLINES):
392 print self.__lines[i]
393 except IndexError:
394 break
395 else:
396 lineno += self.MAXLINES
397 key = None
398 while key is None:
399 key = raw_input(prompt)
400 if key not in ('', 'q'):
401 key = None
402 if key == 'q':
403 break
404
405def setcopyright():
406 """Set 'copyright' and 'credits' in __builtin__"""
407 __builtin__.copyright = _Printer("copyright", sys.copyright)
408 if sys.platform[:4] == 'java':
409 __builtin__.credits = _Printer(
410 "credits",
411 "Jython is maintained by the Jython developers (www.jython.org).")
412 else:
413 __builtin__.credits = _Printer("credits", """\
414 Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
415 for supporting Python development. See www.python.org for more information.""")
416 here = os.path.dirname(os.__file__)
417 __builtin__.license = _Printer(
418 "license", "See http://www.python.org/%.3s/license.html" % sys.version,
419 ["LICENSE.txt", "LICENSE"],
420 [os.path.join(here, os.pardir), here, os.curdir])
421
422
423class _Helper(object):
424 """Define the built-in 'help'.
425 This is a wrapper around pydoc.help (with a twist).
426
427 """
428
429 def __repr__(self):
430 return "Type help() for interactive help, " \
431 "or help(object) for help about object."
432 def __call__(self, *args, **kwds):
433 import pydoc
434 return pydoc.help(*args, **kwds)
435
436def sethelper():
437 __builtin__.help = _Helper()
438
439def aliasmbcs():
440 """On Windows, some default encodings are not provided by Python,
441 while they are always available as "mbcs" in each locale. Make
442 them usable by aliasing to "mbcs" in such a case."""
443 if sys.platform == 'win32':
444 import locale, codecs
445 enc = locale.getdefaultlocale()[1]
446 if enc.startswith('cp'): # "cp***" ?
447 try:
448 codecs.lookup(enc)
449 except LookupError:
450 import encodings
451 encodings._cache[enc] = encodings._unknown
452 encodings.aliases.aliases[enc] = 'mbcs'
453
454def setencoding():
455 """Set the string encoding used by the Unicode implementation. The
456 default is 'ascii', but if you're willing to experiment, you can
457 change this."""
458 encoding = "ascii" # Default value set by _PyUnicode_Init()
459 if 1:
460 # Enable to support locale aware default string encodings.
461 import locale
462 loc = locale.getdefaultlocale()
463 if loc[1]:
464 encoding = loc[1]
465 if 0:
466 # Enable to switch off string to Unicode coercion and implicit
467 # Unicode to string conversion.
468 encoding = "undefined"
469 if encoding != "ascii":
470 # On Non-Unicode builds this will raise an AttributeError...
471 sys.setdefaultencoding(encoding) # Needs Python Unicode build !
472
473
474def execsitecustomize():
475 """Run custom site specific code, if available."""
476 try:
477 import sitecustomize
478 except ImportError:
479 pass
480
481
482def execusercustomize():
483 """Run custom user specific code, if available."""
484 try:
485 import usercustomize
486 except ImportError:
487 pass
488
489
490def main():
491 global ENABLE_USER_SITE
492
493 abs__file__()
494 known_paths = removeduppaths()
495 if ((os.name == "posix" or os.name == "os2") and
496 sys.path and os.path.basename(sys.path[-1]) == "Modules"):
497 addbuilddir()
498 if (os.name == "os2"):
499 setBEGINLIBPATH()
500 if ENABLE_USER_SITE is None:
501 ENABLE_USER_SITE = check_enableusersite()
502 known_paths = addusersitepackages(known_paths)
503 known_paths = addsitepackages(known_paths)
504 setquit()
505 setcopyright()
506 sethelper()
507 aliasmbcs()
508 setencoding()
509 execsitecustomize()
510 if ENABLE_USER_SITE:
511 execusercustomize()
512 # Remove sys.setdefaultencoding() so that users cannot change the
513 # encoding after initialization. The test for presence is needed when
514 # this module is run as a script, because this code is executed twice.
515 if hasattr(sys, "setdefaultencoding"):
516 del sys.setdefaultencoding
517
518main()
519
520def _script():
521 help = """\
522 %s [--user-base] [--user-site]
523
524 Without arguments print some useful information
525 With arguments print the value of USER_BASE and/or USER_SITE separated
526 by '%s'.
527
528 Exit codes with --user-base or --user-site:
529 0 - user site directory is enabled
530 1 - user site directory is disabled by user
531 2 - uses site directory is disabled by super user
532 or for security reasons
533 >2 - unknown error
534 """
535 args = sys.argv[1:]
536 if not args:
537 print "sys.path = ["
538 for dir in sys.path:
539 print " %r," % (dir,)
540 print "]"
541 print "USER_BASE: %r (%s)" % (USER_BASE,
542 "exists" if os.path.isdir(USER_BASE) else "doesn't exist")
543 print "USER_SITE: %r (%s)" % (USER_SITE,
544 "exists" if os.path.isdir(USER_SITE) else "doesn't exist")
545 print "ENABLE_USER_SITE: %r" % ENABLE_USER_SITE
546 sys.exit(0)
547
548 buffer = []
549 if '--user-base' in args:
550 buffer.append(USER_BASE)
551 if '--user-site' in args:
552 buffer.append(USER_SITE)
553
554 if buffer:
555 print os.pathsep.join(buffer)
556 if ENABLE_USER_SITE:
557 sys.exit(0)
558 elif ENABLE_USER_SITE is False:
559 sys.exit(1)
560 elif ENABLE_USER_SITE is None:
561 sys.exit(2)
562 else:
563 sys.exit(3)
564 else:
565 import textwrap
566 print textwrap.dedent(help % (sys.argv[0], os.pathsep))
567 sys.exit(10)
568
569if __name__ == '__main__':
570 _script()
Note: See TracBrowser for help on using the repository browser.