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