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