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