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 if os.sep == '/': 338 sitepackages.append(os.path.join(prefix, "lib", 339 "python%d.%d" % sys.version_info[:2], 340 "site-packages")) 341 else: 342 sitepackages.append(prefix) 343 sitepackages.append(os.path.join(prefix, "lib", "site-packages")) 344 return sitepackages 345 346def addsitepackages(known_paths, prefixes=None): 347 """Add site-packages to sys.path""" 348 for sitedir in getsitepackages(prefixes): 349 if os.path.isdir(sitedir): 350 addsitedir(sitedir, known_paths) 351 352 return known_paths 353 354def setquit(): 355 """Define new builtins 'quit' and 'exit'. 356 357 These are objects which make the interpreter exit when called. 358 The repr of each object contains a hint at how it works. 359 360 """ 361 if os.sep == '\\': 362 eof = 'Ctrl-Z plus Return' 363 else: 364 eof = 'Ctrl-D (i.e. EOF)' 365 366 builtins.quit = _sitebuiltins.Quitter('quit', eof) 367 builtins.exit = _sitebuiltins.Quitter('exit', eof) 368 369 370def setcopyright(): 371 """Set 'copyright' and 'credits' in builtins""" 372 builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright) 373 if sys.platform[:4] == 'java': 374 builtins.credits = _sitebuiltins._Printer( 375 "credits", 376 "Jython is maintained by the Jython developers (www.jython.org).") 377 else: 378 builtins.credits = _sitebuiltins._Printer("credits", """\ 379 Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands 380 for supporting Python development. See www.python.org for more information.""") 381 files, dirs = [], [] 382 # Not all modules are required to have a __file__ attribute. See 383 # PEP 420 for more details. 384 if hasattr(os, '__file__'): 385 here = os.path.dirname(os.__file__) 386 files.extend(["LICENSE.txt", "LICENSE"]) 387 dirs.extend([os.path.join(here, os.pardir), here, os.curdir]) 388 builtins.license = _sitebuiltins._Printer( 389 "license", 390 "See https://www.python.org/psf/license/", 391 files, dirs) 392 393 394def sethelper(): 395 builtins.help = _sitebuiltins._Helper() 396 397def enablerlcompleter(): 398 """Enable default readline configuration on interactive prompts, by 399 registering a sys.__interactivehook__. 400 401 If the readline module can be imported, the hook will set the Tab key 402 as completion key and register ~/.python_history as history file. 403 This can be overridden in the sitecustomize or usercustomize module, 404 or in a PYTHONSTARTUP file. 405 """ 406 def register_readline(): 407 import atexit 408 try: 409 import readline 410 import rlcompleter 411 except ImportError: 412 return 413 414 # Reading the initialization (config) file may not be enough to set a 415 # completion key, so we set one first and then read the file. 416 readline_doc = getattr(readline, '__doc__', '') 417 if readline_doc is not None and 'libedit' in readline_doc: 418 readline.parse_and_bind('bind ^I rl_complete') 419 else: 420 readline.parse_and_bind('tab: complete') 421 422 try: 423 readline.read_init_file() 424 except OSError: 425 # An OSError here could have many causes, but the most likely one 426 # is that there's no .inputrc file (or .editrc file in the case of 427 # Mac OS X + libedit) in the expected location. In that case, we 428 # want to ignore the exception. 429 pass 430 431 if readline.get_current_history_length() == 0: 432 # If no history was loaded, default to .python_history. 433 # The guard is necessary to avoid doubling history size at 434 # each interpreter exit when readline was already configured 435 # through a PYTHONSTARTUP hook, see: 436 # http://bugs.python.org/issue5845#msg198636 437 history = os.path.join(os.path.expanduser('~'), 438 '.python_history') 439 try: 440 readline.read_history_file(history) 441 except OSError: 442 pass 443 444 def write_history(): 445 try: 446 readline.write_history_file(history) 447 except (FileNotFoundError, PermissionError): 448 # home directory does not exist or is not writable 449 # https://bugs.python.org/issue19891 450 pass 451 452 atexit.register(write_history) 453 454 sys.__interactivehook__ = register_readline 455 456def venv(known_paths): 457 global PREFIXES, ENABLE_USER_SITE 458 459 env = os.environ 460 if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env: 461 executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__'] 462 else: 463 executable = sys.executable 464 exe_dir, _ = os.path.split(os.path.abspath(executable)) 465 site_prefix = os.path.dirname(exe_dir) 466 sys._home = None 467 conf_basename = 'pyvenv.cfg' 468 candidate_confs = [ 469 conffile for conffile in ( 470 os.path.join(exe_dir, conf_basename), 471 os.path.join(site_prefix, conf_basename) 472 ) 473 if os.path.isfile(conffile) 474 ] 475 476 if candidate_confs: 477 virtual_conf = candidate_confs[0] 478 system_site = "true" 479 # Issue 25185: Use UTF-8, as that's what the venv module uses when 480 # writing the file. 481 with open(virtual_conf, encoding='utf-8') as f: 482 for line in f: 483 if '=' in line: 484 key, _, value = line.partition('=') 485 key = key.strip().lower() 486 value = value.strip() 487 if key == 'include-system-site-packages': 488 system_site = value.lower() 489 elif key == 'home': 490 sys._home = value 491 492 sys.prefix = sys.exec_prefix = site_prefix 493 494 # Doing this here ensures venv takes precedence over user-site 495 addsitepackages(known_paths, [sys.prefix]) 496 497 # addsitepackages will process site_prefix again if its in PREFIXES, 498 # but that's ok; known_paths will prevent anything being added twice 499 if system_site == "true": 500 PREFIXES.insert(0, sys.prefix) 501 else: 502 PREFIXES = [sys.prefix] 503 ENABLE_USER_SITE = False 504 505 return known_paths 506 507 508def execsitecustomize(): 509 """Run custom site specific code, if available.""" 510 try: 511 try: 512 import sitecustomize 513 except ImportError as exc: 514 if exc.name == 'sitecustomize': 515 pass 516 else: 517 raise 518 except Exception as err: 519 if sys.flags.verbose: 520 sys.excepthook(*sys.exc_info()) 521 else: 522 sys.stderr.write( 523 "Error in sitecustomize; set PYTHONVERBOSE for traceback:\n" 524 "%s: %s\n" % 525 (err.__class__.__name__, err)) 526 527 528def execusercustomize(): 529 """Run custom user specific code, if available.""" 530 try: 531 try: 532 import usercustomize 533 except ImportError as exc: 534 if exc.name == 'usercustomize': 535 pass 536 else: 537 raise 538 except Exception as err: 539 if sys.flags.verbose: 540 sys.excepthook(*sys.exc_info()) 541 else: 542 sys.stderr.write( 543 "Error in usercustomize; set PYTHONVERBOSE for traceback:\n" 544 "%s: %s\n" % 545 (err.__class__.__name__, err)) 546 547 548def main(): 549 """Add standard site-specific directories to the module search path. 550 551 This function is called automatically when this module is imported, 552 unless the python interpreter was started with the -S flag. 553 """ 554 global ENABLE_USER_SITE 555 556 orig_path = sys.path[:] 557 known_paths = removeduppaths() 558 if orig_path != sys.path: 559 # removeduppaths() might make sys.path absolute. 560 # fix __file__ and __cached__ of already imported modules too. 561 abs_paths() 562 563 known_paths = venv(known_paths) 564 if ENABLE_USER_SITE is None: 565 ENABLE_USER_SITE = check_enableusersite() 566 known_paths = addusersitepackages(known_paths) 567 known_paths = addsitepackages(known_paths) 568 setquit() 569 setcopyright() 570 sethelper() 571 if not sys.flags.isolated: 572 enablerlcompleter() 573 execsitecustomize() 574 if ENABLE_USER_SITE: 575 execusercustomize() 576 577# Prevent extending of sys.path when python was started with -S and 578# site is imported later. 579if not sys.flags.no_site: 580 main() 581 582def _script(): 583 help = """\ 584 %s [--user-base] [--user-site] 585 586 Without arguments print some useful information 587 With arguments print the value of USER_BASE and/or USER_SITE separated 588 by '%s'. 589 590 Exit codes with --user-base or --user-site: 591 0 - user site directory is enabled 592 1 - user site directory is disabled by user 593 2 - uses site directory is disabled by super user 594 or for security reasons 595 >2 - unknown error 596 """ 597 args = sys.argv[1:] 598 if not args: 599 user_base = getuserbase() 600 user_site = getusersitepackages() 601 print("sys.path = [") 602 for dir in sys.path: 603 print(" %r," % (dir,)) 604 print("]") 605 print("USER_BASE: %r (%s)" % (user_base, 606 "exists" if os.path.isdir(user_base) else "doesn't exist")) 607 print("USER_SITE: %r (%s)" % (user_site, 608 "exists" if os.path.isdir(user_site) else "doesn't exist")) 609 print("ENABLE_USER_SITE: %r" % ENABLE_USER_SITE) 610 sys.exit(0) 611 612 buffer = [] 613 if '--user-base' in args: 614 buffer.append(USER_BASE) 615 if '--user-site' in args: 616 buffer.append(USER_SITE) 617 618 if buffer: 619 print(os.pathsep.join(buffer)) 620 if ENABLE_USER_SITE: 621 sys.exit(0) 622 elif ENABLE_USER_SITE is False: 623 sys.exit(1) 624 elif ENABLE_USER_SITE is None: 625 sys.exit(2) 626 else: 627 sys.exit(3) 628 else: 629 import textwrap 630 print(textwrap.dedent(help % (sys.argv[0], os.pathsep))) 631 sys.exit(10) 632 633if __name__ == '__main__': 634 _script() 635