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