(root)/
Python-3.12.0/
Lib/
site.py
       1  """Append module search paths for third-party packages to sys.path.
       2  
       3  ****************************************************************
       4  * This module is automatically imported during initialization. *
       5  ****************************************************************
       6  
       7  This will append site-specific paths to the module search path.  On
       8  Unix (including Mac OSX), it starts with sys.prefix and
       9  sys.exec_prefix (if different) and appends
      10  lib/python<version>/site-packages.
      11  On other platforms (such as Windows), it tries each of the
      12  prefixes directly, as well as with lib/site-packages appended.  The
      13  resulting directories, if they exist, are appended to sys.path, and
      14  also inspected for path configuration files.
      15  
      16  If a file named "pyvenv.cfg" exists one directory above sys.executable,
      17  sys.prefix and sys.exec_prefix are set to that directory and
      18  it is also checked for site-packages (sys.base_prefix and
      19  sys.base_exec_prefix will always be the "real" prefixes of the Python
      20  installation). If "pyvenv.cfg" (a bootstrap configuration file) contains
      21  the key "include-system-site-packages" set to anything other than "false"
      22  (case-insensitive), the system-level prefixes will still also be
      23  searched for site-packages; otherwise they won't.
      24  
      25  All of the resulting site-specific directories, if they exist, are
      26  appended to sys.path, and also inspected for path configuration
      27  files.
      28  
      29  A path configuration file is a file whose name has the form
      30  <package>.pth; its contents are additional directories (one per line)
      31  to be added to sys.path.  Non-existing directories (or
      32  non-directories) are never added to sys.path; no directory is added to
      33  sys.path more than once.  Blank lines and lines beginning with
      34  '#' are skipped. Lines starting with 'import' are executed.
      35  
      36  For 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
      38  with three subdirectories, foo, bar and spam, and two path
      39  configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
      40  following:
      41  
      42    # foo package configuration
      43    foo
      44    bar
      45    bletch
      46  
      47  and bar.pth contains:
      48  
      49    # bar package configuration
      50    bar
      51  
      52  Then 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  
      57  Note that bletch is omitted because it doesn't exist; bar precedes foo
      58  because bar.pth comes alphabetically before foo.pth; and spam is
      59  omitted because it is not mentioned in either path configuration file.
      60  
      61  The readline module is also automatically configured to enable
      62  completion for systems that support it.  This can be overridden in
      63  sitecustomize, usercustomize or PYTHONSTARTUP.  Starting Python in
      64  isolated mode (-I) disables automatic readline configuration.
      65  
      66  After these operations, an attempt is made to import a module
      67  named sitecustomize, which can perform arbitrary additional
      68  site-specific customizations.  If this import fails with an
      69  ImportError exception, it is silently ignored.
      70  """
      71  
      72  import sys
      73  import os
      74  import builtins
      75  import _sitebuiltins
      76  import io
      77  
      78  # Prefixes for site-packages; add additional prefixes like /usr/local here
      79  PREFIXES = [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
      82  ENABLE_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.
      87  USER_SITE = None
      88  USER_BASE = None
      89  
      90  
      91  def _trace(message):
      92      if sys.flags.verbose:
      93          print(message, file=sys.stderr)
      94  
      95  
      96  def 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  
     105  def 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  
     128  def 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  
     147  def _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  
     160  def 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 as exc:
     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(exc):
     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  
     207  def 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  
     232  def 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()
     264  def _getuserbase():
     265      env_base = os.environ.get("PYTHONUSERBASE", None)
     266      if env_base:
     267          return env_base
     268  
     269      # Emscripten, VxWorks, and WASI have no home directories
     270      if sys.platform in {"emscripten", "vxworks", "wasi"}:
     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')
     288  def _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  
     301  def 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  
     314  def 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  
     331  def 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  
     346  def 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          if os.sep == '/':
     365              libdirs = [sys.platlibdir]
     366              if sys.platlibdir != "lib":
     367                  libdirs.append("lib")
     368  
     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              sitepackages.append(os.path.join(prefix, "Lib", "site-packages"))
     377      return sitepackages
     378  
     379  def addsitepackages(known_paths, prefixes=None):
     380      """Add site-packages to sys.path"""
     381      _trace("Processing global site-packages")
     382      for sitedir in getsitepackages(prefixes):
     383          if os.path.isdir(sitedir):
     384              addsitedir(sitedir, known_paths)
     385  
     386      return known_paths
     387  
     388  def setquit():
     389      """Define new builtins 'quit' and 'exit'.
     390  
     391      These are objects which make the interpreter exit when called.
     392      The repr of each object contains a hint at how it works.
     393  
     394      """
     395      if os.sep == '\\':
     396          eof = 'Ctrl-Z plus Return'
     397      else:
     398          eof = 'Ctrl-D (i.e. EOF)'
     399  
     400      builtins.quit = _sitebuiltins.Quitter('quit', eof)
     401      builtins.exit = _sitebuiltins.Quitter('exit', eof)
     402  
     403  
     404  def setcopyright():
     405      """Set 'copyright' and 'credits' in builtins"""
     406      builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
     407      builtins.credits = _sitebuiltins._Printer("credits", """\
     408      Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
     409      for supporting Python development.  See www.python.org for more information.""")
     410      files, dirs = [], []
     411      # Not all modules are required to have a __file__ attribute.  See
     412      # PEP 420 for more details.
     413      here = getattr(sys, '_stdlib_dir', None)
     414      if not here and hasattr(os, '__file__'):
     415          here = os.path.dirname(os.__file__)
     416      if here:
     417          files.extend(["LICENSE.txt", "LICENSE"])
     418          dirs.extend([os.path.join(here, os.pardir), here, os.curdir])
     419      builtins.license = _sitebuiltins._Printer(
     420          "license",
     421          "See https://www.python.org/psf/license/",
     422          files, dirs)
     423  
     424  
     425  def sethelper():
     426      builtins.help = _sitebuiltins._Helper()
     427  
     428  def enablerlcompleter():
     429      """Enable default readline configuration on interactive prompts, by
     430      registering a sys.__interactivehook__.
     431  
     432      If the readline module can be imported, the hook will set the Tab key
     433      as completion key and register ~/.python_history as history file.
     434      This can be overridden in the sitecustomize or usercustomize module,
     435      or in a PYTHONSTARTUP file.
     436      """
     437      def register_readline():
     438          import atexit
     439          try:
     440              import readline
     441              import rlcompleter
     442          except ImportError:
     443              return
     444  
     445          # Reading the initialization (config) file may not be enough to set a
     446          # completion key, so we set one first and then read the file.
     447          readline_doc = getattr(readline, '__doc__', '')
     448          if readline_doc is not None and 'libedit' in readline_doc:
     449              readline.parse_and_bind('bind ^I rl_complete')
     450          else:
     451              readline.parse_and_bind('tab: complete')
     452  
     453          try:
     454              readline.read_init_file()
     455          except OSError:
     456              # An OSError here could have many causes, but the most likely one
     457              # is that there's no .inputrc file (or .editrc file in the case of
     458              # Mac OS X + libedit) in the expected location.  In that case, we
     459              # want to ignore the exception.
     460              pass
     461  
     462          if readline.get_current_history_length() == 0:
     463              # If no history was loaded, default to .python_history.
     464              # The guard is necessary to avoid doubling history size at
     465              # each interpreter exit when readline was already configured
     466              # through a PYTHONSTARTUP hook, see:
     467              # http://bugs.python.org/issue5845#msg198636
     468              history = os.path.join(os.path.expanduser('~'),
     469                                     '.python_history')
     470              try:
     471                  readline.read_history_file(history)
     472              except OSError:
     473                  pass
     474  
     475              def write_history():
     476                  try:
     477                      readline.write_history_file(history)
     478                  except OSError:
     479                      # bpo-19891, bpo-41193: Home directory does not exist
     480                      # or is not writable, or the filesystem is read-only.
     481                      pass
     482  
     483              atexit.register(write_history)
     484  
     485      sys.__interactivehook__ = register_readline
     486  
     487  def venv(known_paths):
     488      global PREFIXES, ENABLE_USER_SITE
     489  
     490      env = os.environ
     491      if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
     492          executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__']
     493      else:
     494          executable = sys.executable
     495      exe_dir = os.path.dirname(os.path.abspath(executable))
     496      site_prefix = os.path.dirname(exe_dir)
     497      sys._home = None
     498      conf_basename = 'pyvenv.cfg'
     499      candidate_conf = next(
     500          (
     501              conffile for conffile in (
     502                  os.path.join(exe_dir, conf_basename),
     503                  os.path.join(site_prefix, conf_basename)
     504              )
     505              if os.path.isfile(conffile)
     506          ),
     507          None
     508      )
     509  
     510      if candidate_conf:
     511          virtual_conf = candidate_conf
     512          system_site = "true"
     513          # Issue 25185: Use UTF-8, as that's what the venv module uses when
     514          # writing the file.
     515          with open(virtual_conf, encoding='utf-8') as f:
     516              for line in f:
     517                  if '=' in line:
     518                      key, _, value = line.partition('=')
     519                      key = key.strip().lower()
     520                      value = value.strip()
     521                      if key == 'include-system-site-packages':
     522                          system_site = value.lower()
     523                      elif key == 'home':
     524                          sys._home = value
     525  
     526          sys.prefix = sys.exec_prefix = site_prefix
     527  
     528          # Doing this here ensures venv takes precedence over user-site
     529          addsitepackages(known_paths, [sys.prefix])
     530  
     531          # addsitepackages will process site_prefix again if its in PREFIXES,
     532          # but that's ok; known_paths will prevent anything being added twice
     533          if system_site == "true":
     534              PREFIXES.insert(0, sys.prefix)
     535          else:
     536              PREFIXES = [sys.prefix]
     537              ENABLE_USER_SITE = False
     538  
     539      return known_paths
     540  
     541  
     542  def execsitecustomize():
     543      """Run custom site specific code, if available."""
     544      try:
     545          try:
     546              import sitecustomize
     547          except ImportError as exc:
     548              if exc.name == 'sitecustomize':
     549                  pass
     550              else:
     551                  raise
     552      except Exception as err:
     553          if sys.flags.verbose:
     554              sys.excepthook(*sys.exc_info())
     555          else:
     556              sys.stderr.write(
     557                  "Error in sitecustomize; set PYTHONVERBOSE for traceback:\n"
     558                  "%s: %s\n" %
     559                  (err.__class__.__name__, err))
     560  
     561  
     562  def execusercustomize():
     563      """Run custom user specific code, if available."""
     564      try:
     565          try:
     566              import usercustomize
     567          except ImportError as exc:
     568              if exc.name == 'usercustomize':
     569                  pass
     570              else:
     571                  raise
     572      except Exception as err:
     573          if sys.flags.verbose:
     574              sys.excepthook(*sys.exc_info())
     575          else:
     576              sys.stderr.write(
     577                  "Error in usercustomize; set PYTHONVERBOSE for traceback:\n"
     578                  "%s: %s\n" %
     579                  (err.__class__.__name__, err))
     580  
     581  
     582  def main():
     583      """Add standard site-specific directories to the module search path.
     584  
     585      This function is called automatically when this module is imported,
     586      unless the python interpreter was started with the -S flag.
     587      """
     588      global ENABLE_USER_SITE
     589  
     590      orig_path = sys.path[:]
     591      known_paths = removeduppaths()
     592      if orig_path != sys.path:
     593          # removeduppaths() might make sys.path absolute.
     594          # fix __file__ and __cached__ of already imported modules too.
     595          abs_paths()
     596  
     597      known_paths = venv(known_paths)
     598      if ENABLE_USER_SITE is None:
     599          ENABLE_USER_SITE = check_enableusersite()
     600      known_paths = addusersitepackages(known_paths)
     601      known_paths = addsitepackages(known_paths)
     602      setquit()
     603      setcopyright()
     604      sethelper()
     605      if not sys.flags.isolated:
     606          enablerlcompleter()
     607      execsitecustomize()
     608      if ENABLE_USER_SITE:
     609          execusercustomize()
     610  
     611  # Prevent extending of sys.path when python was started with -S and
     612  # site is imported later.
     613  if not sys.flags.no_site:
     614      main()
     615  
     616  def _script():
     617      help = """\
     618      %s [--user-base] [--user-site]
     619  
     620      Without arguments print some useful information
     621      With arguments print the value of USER_BASE and/or USER_SITE separated
     622      by '%s'.
     623  
     624      Exit codes with --user-base or --user-site:
     625        0 - user site directory is enabled
     626        1 - user site directory is disabled by user
     627        2 - user site directory is disabled by super user
     628            or for security reasons
     629       >2 - unknown error
     630      """
     631      args = sys.argv[1:]
     632      if not args:
     633          user_base = getuserbase()
     634          user_site = getusersitepackages()
     635          print("sys.path = [")
     636          for dir in sys.path:
     637              print("    %r," % (dir,))
     638          print("]")
     639          def exists(path):
     640              if path is not None and os.path.isdir(path):
     641                  return "exists"
     642              else:
     643                  return "doesn't exist"
     644          print(f"USER_BASE: {user_base!r} ({exists(user_base)})")
     645          print(f"USER_SITE: {user_site!r} ({exists(user_site)})")
     646          print(f"ENABLE_USER_SITE: {ENABLE_USER_SITE!r}")
     647          sys.exit(0)
     648  
     649      buffer = []
     650      if '--user-base' in args:
     651          buffer.append(USER_BASE)
     652      if '--user-site' in args:
     653          buffer.append(USER_SITE)
     654  
     655      if buffer:
     656          print(os.pathsep.join(buffer))
     657          if ENABLE_USER_SITE:
     658              sys.exit(0)
     659          elif ENABLE_USER_SITE is False:
     660              sys.exit(1)
     661          elif ENABLE_USER_SITE is None:
     662              sys.exit(2)
     663          else:
     664              sys.exit(3)
     665      else:
     666          import textwrap
     667          print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
     668          sys.exit(10)
     669  
     670  if __name__ == '__main__':
     671      _script()