(root)/
Python-3.11.7/
Lib/
os.py
       1  r"""OS routines for NT or Posix depending on what system we're on.
       2  
       3  This exports:
       4    - all functions from posix or nt, e.g. unlink, stat, etc.
       5    - os.path is either posixpath or ntpath
       6    - os.name is either 'posix' or 'nt'
       7    - os.curdir is a string representing the current directory (always '.')
       8    - os.pardir is a string representing the parent directory (always '..')
       9    - os.sep is the (or a most common) pathname separator ('/' or '\\')
      10    - os.extsep is the extension separator (always '.')
      11    - os.altsep is the alternate pathname separator (None or '/')
      12    - os.pathsep is the component separator used in $PATH etc
      13    - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
      14    - os.defpath is the default search path for executables
      15    - os.devnull is the file path of the null device ('/dev/null', etc.)
      16  
      17  Programs that import and use 'os' stand a better chance of being
      18  portable between different platforms.  Of course, they must then
      19  only use functions that are defined by all platforms (e.g., unlink
      20  and opendir), and leave all pathname manipulation to os.path
      21  (e.g., split and join).
      22  """
      23  
      24  #'
      25  import abc
      26  import sys
      27  import stat as st
      28  
      29  from _collections_abc import _check_methods
      30  
      31  GenericAlias = type(list[int])
      32  
      33  _names = sys.builtin_module_names
      34  
      35  # Note:  more names are added to __all__ later.
      36  __all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep",
      37             "defpath", "name", "path", "devnull", "SEEK_SET", "SEEK_CUR",
      38             "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen",
      39             "extsep"]
      40  
      41  def _exists(name):
      42      return name in globals()
      43  
      44  def _get_exports_list(module):
      45      try:
      46          return list(module.__all__)
      47      except AttributeError:
      48          return [n for n in dir(module) if n[0] != '_']
      49  
      50  # Any new dependencies of the os module and/or changes in path separator
      51  # requires updating importlib as well.
      52  if 'posix' in _names:
      53      name = 'posix'
      54      linesep = '\n'
      55      from posix import *
      56      try:
      57          from posix import _exit
      58          __all__.append('_exit')
      59      except ImportError:
      60          pass
      61      import posixpath as path
      62  
      63      try:
      64          from posix import _have_functions
      65      except ImportError:
      66          pass
      67  
      68      import posix
      69      __all__.extend(_get_exports_list(posix))
      70      del posix
      71  
      72  elif 'nt' in _names:
      73      name = 'nt'
      74      linesep = '\r\n'
      75      from nt import *
      76      try:
      77          from nt import _exit
      78          __all__.append('_exit')
      79      except ImportError:
      80          pass
      81      import ntpath as path
      82  
      83      import nt
      84      __all__.extend(_get_exports_list(nt))
      85      del nt
      86  
      87      try:
      88          from nt import _have_functions
      89      except ImportError:
      90          pass
      91  
      92  else:
      93      raise ImportError('no os specific module found')
      94  
      95  sys.modules['os.path'] = path
      96  from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep,
      97      devnull)
      98  
      99  del _names
     100  
     101  
     102  if _exists("_have_functions"):
     103      _globals = globals()
     104      def _add(str, fn):
     105          if (fn in _globals) and (str in _have_functions):
     106              _set.add(_globals[fn])
     107  
     108      _set = set()
     109      _add("HAVE_FACCESSAT",  "access")
     110      _add("HAVE_FCHMODAT",   "chmod")
     111      _add("HAVE_FCHOWNAT",   "chown")
     112      _add("HAVE_FSTATAT",    "stat")
     113      _add("HAVE_FUTIMESAT",  "utime")
     114      _add("HAVE_LINKAT",     "link")
     115      _add("HAVE_MKDIRAT",    "mkdir")
     116      _add("HAVE_MKFIFOAT",   "mkfifo")
     117      _add("HAVE_MKNODAT",    "mknod")
     118      _add("HAVE_OPENAT",     "open")
     119      _add("HAVE_READLINKAT", "readlink")
     120      _add("HAVE_RENAMEAT",   "rename")
     121      _add("HAVE_SYMLINKAT",  "symlink")
     122      _add("HAVE_UNLINKAT",   "unlink")
     123      _add("HAVE_UNLINKAT",   "rmdir")
     124      _add("HAVE_UTIMENSAT",  "utime")
     125      supports_dir_fd = _set
     126  
     127      _set = set()
     128      _add("HAVE_FACCESSAT",  "access")
     129      supports_effective_ids = _set
     130  
     131      _set = set()
     132      _add("HAVE_FCHDIR",     "chdir")
     133      _add("HAVE_FCHMOD",     "chmod")
     134      _add("HAVE_FCHOWN",     "chown")
     135      _add("HAVE_FDOPENDIR",  "listdir")
     136      _add("HAVE_FDOPENDIR",  "scandir")
     137      _add("HAVE_FEXECVE",    "execve")
     138      _set.add(stat) # fstat always works
     139      _add("HAVE_FTRUNCATE",  "truncate")
     140      _add("HAVE_FUTIMENS",   "utime")
     141      _add("HAVE_FUTIMES",    "utime")
     142      _add("HAVE_FPATHCONF",  "pathconf")
     143      if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3
     144          _add("HAVE_FSTATVFS", "statvfs")
     145      supports_fd = _set
     146  
     147      _set = set()
     148      _add("HAVE_FACCESSAT",  "access")
     149      # Some platforms don't support lchmod().  Often the function exists
     150      # anyway, as a stub that always returns ENOSUP or perhaps EOPNOTSUPP.
     151      # (No, I don't know why that's a good design.)  ./configure will detect
     152      # this and reject it--so HAVE_LCHMOD still won't be defined on such
     153      # platforms.  This is Very Helpful.
     154      #
     155      # However, sometimes platforms without a working lchmod() *do* have
     156      # fchmodat().  (Examples: Linux kernel 3.2 with glibc 2.15,
     157      # OpenIndiana 3.x.)  And fchmodat() has a flag that theoretically makes
     158      # it behave like lchmod().  So in theory it would be a suitable
     159      # replacement for lchmod().  But when lchmod() doesn't work, fchmodat()'s
     160      # flag doesn't work *either*.  Sadly ./configure isn't sophisticated
     161      # enough to detect this condition--it only determines whether or not
     162      # fchmodat() minimally works.
     163      #
     164      # Therefore we simply ignore fchmodat() when deciding whether or not
     165      # os.chmod supports follow_symlinks.  Just checking lchmod() is
     166      # sufficient.  After all--if you have a working fchmodat(), your
     167      # lchmod() almost certainly works too.
     168      #
     169      # _add("HAVE_FCHMODAT",   "chmod")
     170      _add("HAVE_FCHOWNAT",   "chown")
     171      _add("HAVE_FSTATAT",    "stat")
     172      _add("HAVE_LCHFLAGS",   "chflags")
     173      _add("HAVE_LCHMOD",     "chmod")
     174      if _exists("lchown"): # mac os x10.3
     175          _add("HAVE_LCHOWN", "chown")
     176      _add("HAVE_LINKAT",     "link")
     177      _add("HAVE_LUTIMES",    "utime")
     178      _add("HAVE_LSTAT",      "stat")
     179      _add("HAVE_FSTATAT",    "stat")
     180      _add("HAVE_UTIMENSAT",  "utime")
     181      _add("MS_WINDOWS",      "stat")
     182      supports_follow_symlinks = _set
     183  
     184      del _set
     185      del _have_functions
     186      del _globals
     187      del _add
     188  
     189  
     190  # Python uses fixed values for the SEEK_ constants; they are mapped
     191  # to native constants if necessary in posixmodule.c
     192  # Other possible SEEK values are directly imported from posixmodule.c
     193  SEEK_SET = 0
     194  SEEK_CUR = 1
     195  SEEK_END = 2
     196  
     197  # Super directory utilities.
     198  # (Inspired by Eric Raymond; the doc strings are mostly his)
     199  
     200  def makedirs(name, mode=0o777, exist_ok=False):
     201      """makedirs(name [, mode=0o777][, exist_ok=False])
     202  
     203      Super-mkdir; create a leaf directory and all intermediate ones.  Works like
     204      mkdir, except that any intermediate path segment (not just the rightmost)
     205      will be created if it does not exist. If the target directory already
     206      exists, raise an OSError if exist_ok is False. Otherwise no exception is
     207      raised.  This is recursive.
     208  
     209      """
     210      head, tail = path.split(name)
     211      if not tail:
     212          head, tail = path.split(head)
     213      if head and tail and not path.exists(head):
     214          try:
     215              makedirs(head, exist_ok=exist_ok)
     216          except FileExistsError:
     217              # Defeats race condition when another thread created the path
     218              pass
     219          cdir = curdir
     220          if isinstance(tail, bytes):
     221              cdir = bytes(curdir, 'ASCII')
     222          if tail == cdir:           # xxx/newdir/. exists if xxx/newdir exists
     223              return
     224      try:
     225          mkdir(name, mode)
     226      except OSError:
     227          # Cannot rely on checking for EEXIST, since the operating system
     228          # could give priority to other errors like EACCES or EROFS
     229          if not exist_ok or not path.isdir(name):
     230              raise
     231  
     232  def removedirs(name):
     233      """removedirs(name)
     234  
     235      Super-rmdir; remove a leaf directory and all empty intermediate
     236      ones.  Works like rmdir except that, if the leaf directory is
     237      successfully removed, directories corresponding to rightmost path
     238      segments will be pruned away until either the whole path is
     239      consumed or an error occurs.  Errors during this latter phase are
     240      ignored -- they generally mean that a directory was not empty.
     241  
     242      """
     243      rmdir(name)
     244      head, tail = path.split(name)
     245      if not tail:
     246          head, tail = path.split(head)
     247      while head and tail:
     248          try:
     249              rmdir(head)
     250          except OSError:
     251              break
     252          head, tail = path.split(head)
     253  
     254  def renames(old, new):
     255      """renames(old, new)
     256  
     257      Super-rename; create directories as necessary and delete any left
     258      empty.  Works like rename, except creation of any intermediate
     259      directories needed to make the new pathname good is attempted
     260      first.  After the rename, directories corresponding to rightmost
     261      path segments of the old name will be pruned until either the
     262      whole path is consumed or a nonempty directory is found.
     263  
     264      Note: this function can fail with the new directory structure made
     265      if you lack permissions needed to unlink the leaf directory or
     266      file.
     267  
     268      """
     269      head, tail = path.split(new)
     270      if head and tail and not path.exists(head):
     271          makedirs(head)
     272      rename(old, new)
     273      head, tail = path.split(old)
     274      if head and tail:
     275          try:
     276              removedirs(head)
     277          except OSError:
     278              pass
     279  
     280  __all__.extend(["makedirs", "removedirs", "renames"])
     281  
     282  def walk(top, topdown=True, onerror=None, followlinks=False):
     283      """Directory tree generator.
     284  
     285      For each directory in the directory tree rooted at top (including top
     286      itself, but excluding '.' and '..'), yields a 3-tuple
     287  
     288          dirpath, dirnames, filenames
     289  
     290      dirpath is a string, the path to the directory.  dirnames is a list of
     291      the names of the subdirectories in dirpath (including symlinks to directories,
     292      and excluding '.' and '..').
     293      filenames is a list of the names of the non-directory files in dirpath.
     294      Note that the names in the lists are just names, with no path components.
     295      To get a full path (which begins with top) to a file or directory in
     296      dirpath, do os.path.join(dirpath, name).
     297  
     298      If optional arg 'topdown' is true or not specified, the triple for a
     299      directory is generated before the triples for any of its subdirectories
     300      (directories are generated top down).  If topdown is false, the triple
     301      for a directory is generated after the triples for all of its
     302      subdirectories (directories are generated bottom up).
     303  
     304      When topdown is true, the caller can modify the dirnames list in-place
     305      (e.g., via del or slice assignment), and walk will only recurse into the
     306      subdirectories whose names remain in dirnames; this can be used to prune the
     307      search, or to impose a specific order of visiting.  Modifying dirnames when
     308      topdown is false has no effect on the behavior of os.walk(), since the
     309      directories in dirnames have already been generated by the time dirnames
     310      itself is generated. No matter the value of topdown, the list of
     311      subdirectories is retrieved before the tuples for the directory and its
     312      subdirectories are generated.
     313  
     314      By default errors from the os.scandir() call are ignored.  If
     315      optional arg 'onerror' is specified, it should be a function; it
     316      will be called with one argument, an OSError instance.  It can
     317      report the error to continue with the walk, or raise the exception
     318      to abort the walk.  Note that the filename is available as the
     319      filename attribute of the exception object.
     320  
     321      By default, os.walk does not follow symbolic links to subdirectories on
     322      systems that support them.  In order to get this functionality, set the
     323      optional argument 'followlinks' to true.
     324  
     325      Caution:  if you pass a relative pathname for top, don't change the
     326      current working directory between resumptions of walk.  walk never
     327      changes the current directory, and assumes that the client doesn't
     328      either.
     329  
     330      Example:
     331  
     332      import os
     333      from os.path import join, getsize
     334      for root, dirs, files in os.walk('python/Lib/email'):
     335          print(root, "consumes ")
     336          print(sum(getsize(join(root, name)) for name in files), end=" ")
     337          print("bytes in", len(files), "non-directory files")
     338          if 'CVS' in dirs:
     339              dirs.remove('CVS')  # don't visit CVS directories
     340  
     341      """
     342      sys.audit("os.walk", top, topdown, onerror, followlinks)
     343      return _walk(fspath(top), topdown, onerror, followlinks)
     344  
     345  def _walk(top, topdown, onerror, followlinks):
     346      dirs = []
     347      nondirs = []
     348      walk_dirs = []
     349  
     350      # We may not have read permission for top, in which case we can't
     351      # get a list of the files the directory contains.  os.walk
     352      # always suppressed the exception then, rather than blow up for a
     353      # minor reason when (say) a thousand readable directories are still
     354      # left to visit.  That logic is copied here.
     355      try:
     356          # Note that scandir is global in this module due
     357          # to earlier import-*.
     358          scandir_it = scandir(top)
     359      except OSError as error:
     360          if onerror is not None:
     361              onerror(error)
     362          return
     363  
     364      with scandir_it:
     365          while True:
     366              try:
     367                  try:
     368                      entry = next(scandir_it)
     369                  except StopIteration:
     370                      break
     371              except OSError as error:
     372                  if onerror is not None:
     373                      onerror(error)
     374                  return
     375  
     376              try:
     377                  is_dir = entry.is_dir()
     378              except OSError:
     379                  # If is_dir() raises an OSError, consider that the entry is not
     380                  # a directory, same behaviour than os.path.isdir().
     381                  is_dir = False
     382  
     383              if is_dir:
     384                  dirs.append(entry.name)
     385              else:
     386                  nondirs.append(entry.name)
     387  
     388              if not topdown and is_dir:
     389                  # Bottom-up: recurse into sub-directory, but exclude symlinks to
     390                  # directories if followlinks is False
     391                  if followlinks:
     392                      walk_into = True
     393                  else:
     394                      try:
     395                          is_symlink = entry.is_symlink()
     396                      except OSError:
     397                          # If is_symlink() raises an OSError, consider that the
     398                          # entry is not a symbolic link, same behaviour than
     399                          # os.path.islink().
     400                          is_symlink = False
     401                      walk_into = not is_symlink
     402  
     403                  if walk_into:
     404                      walk_dirs.append(entry.path)
     405  
     406      # Yield before recursion if going top down
     407      if topdown:
     408          yield top, dirs, nondirs
     409  
     410          # Recurse into sub-directories
     411          islink, join = path.islink, path.join
     412          for dirname in dirs:
     413              new_path = join(top, dirname)
     414              # Issue #23605: os.path.islink() is used instead of caching
     415              # entry.is_symlink() result during the loop on os.scandir() because
     416              # the caller can replace the directory entry during the "yield"
     417              # above.
     418              if followlinks or not islink(new_path):
     419                  yield from _walk(new_path, topdown, onerror, followlinks)
     420      else:
     421          # Recurse into sub-directories
     422          for new_path in walk_dirs:
     423              yield from _walk(new_path, topdown, onerror, followlinks)
     424          # Yield after recursion if going bottom up
     425          yield top, dirs, nondirs
     426  
     427  __all__.append("walk")
     428  
     429  if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
     430  
     431      def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None):
     432          """Directory tree generator.
     433  
     434          This behaves exactly like walk(), except that it yields a 4-tuple
     435  
     436              dirpath, dirnames, filenames, dirfd
     437  
     438          `dirpath`, `dirnames` and `filenames` are identical to walk() output,
     439          and `dirfd` is a file descriptor referring to the directory `dirpath`.
     440  
     441          The advantage of fwalk() over walk() is that it's safe against symlink
     442          races (when follow_symlinks is False).
     443  
     444          If dir_fd is not None, it should be a file descriptor open to a directory,
     445            and top should be relative; top will then be relative to that directory.
     446            (dir_fd is always supported for fwalk.)
     447  
     448          Caution:
     449          Since fwalk() yields file descriptors, those are only valid until the
     450          next iteration step, so you should dup() them if you want to keep them
     451          for a longer period.
     452  
     453          Example:
     454  
     455          import os
     456          for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
     457              print(root, "consumes", end="")
     458              print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files),
     459                    end="")
     460              print("bytes in", len(files), "non-directory files")
     461              if 'CVS' in dirs:
     462                  dirs.remove('CVS')  # don't visit CVS directories
     463          """
     464          sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
     465          top = fspath(top)
     466          # Note: To guard against symlink races, we use the standard
     467          # lstat()/open()/fstat() trick.
     468          if not follow_symlinks:
     469              orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
     470          topfd = open(top, O_RDONLY, dir_fd=dir_fd)
     471          try:
     472              if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
     473                                      path.samestat(orig_st, stat(topfd)))):
     474                  yield from _fwalk(topfd, top, isinstance(top, bytes),
     475                                    topdown, onerror, follow_symlinks)
     476          finally:
     477              close(topfd)
     478  
     479      def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
     480          # Note: This uses O(depth of the directory tree) file descriptors: if
     481          # necessary, it can be adapted to only require O(1) FDs, see issue
     482          # #13734.
     483  
     484          scandir_it = scandir(topfd)
     485          dirs = []
     486          nondirs = []
     487          entries = None if topdown or follow_symlinks else []
     488          for entry in scandir_it:
     489              name = entry.name
     490              if isbytes:
     491                  name = fsencode(name)
     492              try:
     493                  if entry.is_dir():
     494                      dirs.append(name)
     495                      if entries is not None:
     496                          entries.append(entry)
     497                  else:
     498                      nondirs.append(name)
     499              except OSError:
     500                  try:
     501                      # Add dangling symlinks, ignore disappeared files
     502                      if entry.is_symlink():
     503                          nondirs.append(name)
     504                  except OSError:
     505                      pass
     506  
     507          if topdown:
     508              yield toppath, dirs, nondirs, topfd
     509  
     510          for name in dirs if entries is None else zip(dirs, entries):
     511              try:
     512                  if not follow_symlinks:
     513                      if topdown:
     514                          orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
     515                      else:
     516                          assert entries is not None
     517                          name, entry = name
     518                          orig_st = entry.stat(follow_symlinks=False)
     519                  dirfd = open(name, O_RDONLY, dir_fd=topfd)
     520              except OSError as err:
     521                  if onerror is not None:
     522                      onerror(err)
     523                  continue
     524              try:
     525                  if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
     526                      dirpath = path.join(toppath, name)
     527                      yield from _fwalk(dirfd, dirpath, isbytes,
     528                                        topdown, onerror, follow_symlinks)
     529              finally:
     530                  close(dirfd)
     531  
     532          if not topdown:
     533              yield toppath, dirs, nondirs, topfd
     534  
     535      __all__.append("fwalk")
     536  
     537  def execl(file, *args):
     538      """execl(file, *args)
     539  
     540      Execute the executable file with argument list args, replacing the
     541      current process. """
     542      execv(file, args)
     543  
     544  def execle(file, *args):
     545      """execle(file, *args, env)
     546  
     547      Execute the executable file with argument list args and
     548      environment env, replacing the current process. """
     549      env = args[-1]
     550      execve(file, args[:-1], env)
     551  
     552  def execlp(file, *args):
     553      """execlp(file, *args)
     554  
     555      Execute the executable file (which is searched for along $PATH)
     556      with argument list args, replacing the current process. """
     557      execvp(file, args)
     558  
     559  def execlpe(file, *args):
     560      """execlpe(file, *args, env)
     561  
     562      Execute the executable file (which is searched for along $PATH)
     563      with argument list args and environment env, replacing the current
     564      process. """
     565      env = args[-1]
     566      execvpe(file, args[:-1], env)
     567  
     568  def execvp(file, args):
     569      """execvp(file, args)
     570  
     571      Execute the executable file (which is searched for along $PATH)
     572      with argument list args, replacing the current process.
     573      args may be a list or tuple of strings. """
     574      _execvpe(file, args)
     575  
     576  def execvpe(file, args, env):
     577      """execvpe(file, args, env)
     578  
     579      Execute the executable file (which is searched for along $PATH)
     580      with argument list args and environment env, replacing the
     581      current process.
     582      args may be a list or tuple of strings. """
     583      _execvpe(file, args, env)
     584  
     585  __all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
     586  
     587  def _execvpe(file, args, env=None):
     588      if env is not None:
     589          exec_func = execve
     590          argrest = (args, env)
     591      else:
     592          exec_func = execv
     593          argrest = (args,)
     594          env = environ
     595  
     596      if path.dirname(file):
     597          exec_func(file, *argrest)
     598          return
     599      saved_exc = None
     600      path_list = get_exec_path(env)
     601      if name != 'nt':
     602          file = fsencode(file)
     603          path_list = map(fsencode, path_list)
     604      for dir in path_list:
     605          fullname = path.join(dir, file)
     606          try:
     607              exec_func(fullname, *argrest)
     608          except (FileNotFoundError, NotADirectoryError) as e:
     609              last_exc = e
     610          except OSError as e:
     611              last_exc = e
     612              if saved_exc is None:
     613                  saved_exc = e
     614      if saved_exc is not None:
     615          raise saved_exc
     616      raise last_exc
     617  
     618  
     619  def get_exec_path(env=None):
     620      """Returns the sequence of directories that will be searched for the
     621      named executable (similar to a shell) when launching a process.
     622  
     623      *env* must be an environment variable dict or None.  If *env* is None,
     624      os.environ will be used.
     625      """
     626      # Use a local import instead of a global import to limit the number of
     627      # modules loaded at startup: the os module is always loaded at startup by
     628      # Python. It may also avoid a bootstrap issue.
     629      import warnings
     630  
     631      if env is None:
     632          env = environ
     633  
     634      # {b'PATH': ...}.get('PATH') and {'PATH': ...}.get(b'PATH') emit a
     635      # BytesWarning when using python -b or python -bb: ignore the warning
     636      with warnings.catch_warnings():
     637          warnings.simplefilter("ignore", BytesWarning)
     638  
     639          try:
     640              path_list = env.get('PATH')
     641          except TypeError:
     642              path_list = None
     643  
     644          if supports_bytes_environ:
     645              try:
     646                  path_listb = env[b'PATH']
     647              except (KeyError, TypeError):
     648                  pass
     649              else:
     650                  if path_list is not None:
     651                      raise ValueError(
     652                          "env cannot contain 'PATH' and b'PATH' keys")
     653                  path_list = path_listb
     654  
     655              if path_list is not None and isinstance(path_list, bytes):
     656                  path_list = fsdecode(path_list)
     657  
     658      if path_list is None:
     659          path_list = defpath
     660      return path_list.split(pathsep)
     661  
     662  
     663  # Change environ to automatically call putenv() and unsetenv()
     664  from _collections_abc import MutableMapping, Mapping
     665  
     666  class ESC[4;38;5;81m_Environ(ESC[4;38;5;149mMutableMapping):
     667      def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
     668          self.encodekey = encodekey
     669          self.decodekey = decodekey
     670          self.encodevalue = encodevalue
     671          self.decodevalue = decodevalue
     672          self._data = data
     673  
     674      def __getitem__(self, key):
     675          try:
     676              value = self._data[self.encodekey(key)]
     677          except KeyError:
     678              # raise KeyError with the original key value
     679              raise KeyError(key) from None
     680          return self.decodevalue(value)
     681  
     682      def __setitem__(self, key, value):
     683          key = self.encodekey(key)
     684          value = self.encodevalue(value)
     685          putenv(key, value)
     686          self._data[key] = value
     687  
     688      def __delitem__(self, key):
     689          encodedkey = self.encodekey(key)
     690          unsetenv(encodedkey)
     691          try:
     692              del self._data[encodedkey]
     693          except KeyError:
     694              # raise KeyError with the original key value
     695              raise KeyError(key) from None
     696  
     697      def __iter__(self):
     698          # list() from dict object is an atomic operation
     699          keys = list(self._data)
     700          for key in keys:
     701              yield self.decodekey(key)
     702  
     703      def __len__(self):
     704          return len(self._data)
     705  
     706      def __repr__(self):
     707          formatted_items = ", ".join(
     708              f"{self.decodekey(key)!r}: {self.decodevalue(value)!r}"
     709              for key, value in self._data.items()
     710          )
     711          return f"environ({{{formatted_items}}})"
     712  
     713      def copy(self):
     714          return dict(self)
     715  
     716      def setdefault(self, key, value):
     717          if key not in self:
     718              self[key] = value
     719          return self[key]
     720  
     721      def __ior__(self, other):
     722          self.update(other)
     723          return self
     724  
     725      def __or__(self, other):
     726          if not isinstance(other, Mapping):
     727              return NotImplemented
     728          new = dict(self)
     729          new.update(other)
     730          return new
     731  
     732      def __ror__(self, other):
     733          if not isinstance(other, Mapping):
     734              return NotImplemented
     735          new = dict(other)
     736          new.update(self)
     737          return new
     738  
     739  def _createenviron():
     740      if name == 'nt':
     741          # Where Env Var Names Must Be UPPERCASE
     742          def check_str(value):
     743              if not isinstance(value, str):
     744                  raise TypeError("str expected, not %s" % type(value).__name__)
     745              return value
     746          encode = check_str
     747          decode = str
     748          def encodekey(key):
     749              return encode(key).upper()
     750          data = {}
     751          for key, value in environ.items():
     752              data[encodekey(key)] = value
     753      else:
     754          # Where Env Var Names Can Be Mixed Case
     755          encoding = sys.getfilesystemencoding()
     756          def encode(value):
     757              if not isinstance(value, str):
     758                  raise TypeError("str expected, not %s" % type(value).__name__)
     759              return value.encode(encoding, 'surrogateescape')
     760          def decode(value):
     761              return value.decode(encoding, 'surrogateescape')
     762          encodekey = encode
     763          data = environ
     764      return _Environ(data,
     765          encodekey, decode,
     766          encode, decode)
     767  
     768  # unicode environ
     769  environ = _createenviron()
     770  del _createenviron
     771  
     772  
     773  def getenv(key, default=None):
     774      """Get an environment variable, return None if it doesn't exist.
     775      The optional second argument can specify an alternate default.
     776      key, default and the result are str."""
     777      return environ.get(key, default)
     778  
     779  supports_bytes_environ = (name != 'nt')
     780  __all__.extend(("getenv", "supports_bytes_environ"))
     781  
     782  if supports_bytes_environ:
     783      def _check_bytes(value):
     784          if not isinstance(value, bytes):
     785              raise TypeError("bytes expected, not %s" % type(value).__name__)
     786          return value
     787  
     788      # bytes environ
     789      environb = _Environ(environ._data,
     790          _check_bytes, bytes,
     791          _check_bytes, bytes)
     792      del _check_bytes
     793  
     794      def getenvb(key, default=None):
     795          """Get an environment variable, return None if it doesn't exist.
     796          The optional second argument can specify an alternate default.
     797          key, default and the result are bytes."""
     798          return environb.get(key, default)
     799  
     800      __all__.extend(("environb", "getenvb"))
     801  
     802  def _fscodec():
     803      encoding = sys.getfilesystemencoding()
     804      errors = sys.getfilesystemencodeerrors()
     805  
     806      def fsencode(filename):
     807          """Encode filename (an os.PathLike, bytes, or str) to the filesystem
     808          encoding with 'surrogateescape' error handler, return bytes unchanged.
     809          On Windows, use 'strict' error handler if the file system encoding is
     810          'mbcs' (which is the default encoding).
     811          """
     812          filename = fspath(filename)  # Does type-checking of `filename`.
     813          if isinstance(filename, str):
     814              return filename.encode(encoding, errors)
     815          else:
     816              return filename
     817  
     818      def fsdecode(filename):
     819          """Decode filename (an os.PathLike, bytes, or str) from the filesystem
     820          encoding with 'surrogateescape' error handler, return str unchanged. On
     821          Windows, use 'strict' error handler if the file system encoding is
     822          'mbcs' (which is the default encoding).
     823          """
     824          filename = fspath(filename)  # Does type-checking of `filename`.
     825          if isinstance(filename, bytes):
     826              return filename.decode(encoding, errors)
     827          else:
     828              return filename
     829  
     830      return fsencode, fsdecode
     831  
     832  fsencode, fsdecode = _fscodec()
     833  del _fscodec
     834  
     835  # Supply spawn*() (probably only for Unix)
     836  if _exists("fork") and not _exists("spawnv") and _exists("execv"):
     837  
     838      P_WAIT = 0
     839      P_NOWAIT = P_NOWAITO = 1
     840  
     841      __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"])
     842  
     843      # XXX Should we support P_DETACH?  I suppose it could fork()**2
     844      # and close the std I/O streams.  Also, P_OVERLAY is the same
     845      # as execv*()?
     846  
     847      def _spawnvef(mode, file, args, env, func):
     848          # Internal helper; func is the exec*() function to use
     849          if not isinstance(args, (tuple, list)):
     850              raise TypeError('argv must be a tuple or a list')
     851          if not args or not args[0]:
     852              raise ValueError('argv first element cannot be empty')
     853          pid = fork()
     854          if not pid:
     855              # Child
     856              try:
     857                  if env is None:
     858                      func(file, args)
     859                  else:
     860                      func(file, args, env)
     861              except:
     862                  _exit(127)
     863          else:
     864              # Parent
     865              if mode == P_NOWAIT:
     866                  return pid # Caller is responsible for waiting!
     867              while 1:
     868                  wpid, sts = waitpid(pid, 0)
     869                  if WIFSTOPPED(sts):
     870                      continue
     871  
     872                  return waitstatus_to_exitcode(sts)
     873  
     874      def spawnv(mode, file, args):
     875          """spawnv(mode, file, args) -> integer
     876  
     877  Execute file with arguments from args in a subprocess.
     878  If mode == P_NOWAIT return the pid of the process.
     879  If mode == P_WAIT return the process's exit code if it exits normally;
     880  otherwise return -SIG, where SIG is the signal that killed it. """
     881          return _spawnvef(mode, file, args, None, execv)
     882  
     883      def spawnve(mode, file, args, env):
     884          """spawnve(mode, file, args, env) -> integer
     885  
     886  Execute file with arguments from args in a subprocess with the
     887  specified environment.
     888  If mode == P_NOWAIT return the pid of the process.
     889  If mode == P_WAIT return the process's exit code if it exits normally;
     890  otherwise return -SIG, where SIG is the signal that killed it. """
     891          return _spawnvef(mode, file, args, env, execve)
     892  
     893      # Note: spawnvp[e] isn't currently supported on Windows
     894  
     895      def spawnvp(mode, file, args):
     896          """spawnvp(mode, file, args) -> integer
     897  
     898  Execute file (which is looked for along $PATH) with arguments from
     899  args in a subprocess.
     900  If mode == P_NOWAIT return the pid of the process.
     901  If mode == P_WAIT return the process's exit code if it exits normally;
     902  otherwise return -SIG, where SIG is the signal that killed it. """
     903          return _spawnvef(mode, file, args, None, execvp)
     904  
     905      def spawnvpe(mode, file, args, env):
     906          """spawnvpe(mode, file, args, env) -> integer
     907  
     908  Execute file (which is looked for along $PATH) with arguments from
     909  args in a subprocess with the supplied environment.
     910  If mode == P_NOWAIT return the pid of the process.
     911  If mode == P_WAIT return the process's exit code if it exits normally;
     912  otherwise return -SIG, where SIG is the signal that killed it. """
     913          return _spawnvef(mode, file, args, env, execvpe)
     914  
     915  
     916      __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"])
     917  
     918  
     919  if _exists("spawnv"):
     920      # These aren't supplied by the basic Windows code
     921      # but can be easily implemented in Python
     922  
     923      def spawnl(mode, file, *args):
     924          """spawnl(mode, file, *args) -> integer
     925  
     926  Execute file with arguments from args in a subprocess.
     927  If mode == P_NOWAIT return the pid of the process.
     928  If mode == P_WAIT return the process's exit code if it exits normally;
     929  otherwise return -SIG, where SIG is the signal that killed it. """
     930          return spawnv(mode, file, args)
     931  
     932      def spawnle(mode, file, *args):
     933          """spawnle(mode, file, *args, env) -> integer
     934  
     935  Execute file with arguments from args in a subprocess with the
     936  supplied environment.
     937  If mode == P_NOWAIT return the pid of the process.
     938  If mode == P_WAIT return the process's exit code if it exits normally;
     939  otherwise return -SIG, where SIG is the signal that killed it. """
     940          env = args[-1]
     941          return spawnve(mode, file, args[:-1], env)
     942  
     943  
     944      __all__.extend(["spawnl", "spawnle"])
     945  
     946  
     947  if _exists("spawnvp"):
     948      # At the moment, Windows doesn't implement spawnvp[e],
     949      # so it won't have spawnlp[e] either.
     950      def spawnlp(mode, file, *args):
     951          """spawnlp(mode, file, *args) -> integer
     952  
     953  Execute file (which is looked for along $PATH) with arguments from
     954  args in a subprocess with the supplied environment.
     955  If mode == P_NOWAIT return the pid of the process.
     956  If mode == P_WAIT return the process's exit code if it exits normally;
     957  otherwise return -SIG, where SIG is the signal that killed it. """
     958          return spawnvp(mode, file, args)
     959  
     960      def spawnlpe(mode, file, *args):
     961          """spawnlpe(mode, file, *args, env) -> integer
     962  
     963  Execute file (which is looked for along $PATH) with arguments from
     964  args in a subprocess with the supplied environment.
     965  If mode == P_NOWAIT return the pid of the process.
     966  If mode == P_WAIT return the process's exit code if it exits normally;
     967  otherwise return -SIG, where SIG is the signal that killed it. """
     968          env = args[-1]
     969          return spawnvpe(mode, file, args[:-1], env)
     970  
     971  
     972      __all__.extend(["spawnlp", "spawnlpe"])
     973  
     974  # VxWorks has no user space shell provided. As a result, running
     975  # command in a shell can't be supported.
     976  if sys.platform != 'vxworks':
     977      # Supply os.popen()
     978      def popen(cmd, mode="r", buffering=-1):
     979          if not isinstance(cmd, str):
     980              raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
     981          if mode not in ("r", "w"):
     982              raise ValueError("invalid mode %r" % mode)
     983          if buffering == 0 or buffering is None:
     984              raise ValueError("popen() does not support unbuffered streams")
     985          import subprocess
     986          if mode == "r":
     987              proc = subprocess.Popen(cmd,
     988                                      shell=True, text=True,
     989                                      stdout=subprocess.PIPE,
     990                                      bufsize=buffering)
     991              return _wrap_close(proc.stdout, proc)
     992          else:
     993              proc = subprocess.Popen(cmd,
     994                                      shell=True, text=True,
     995                                      stdin=subprocess.PIPE,
     996                                      bufsize=buffering)
     997              return _wrap_close(proc.stdin, proc)
     998  
     999      # Helper for popen() -- a proxy for a file whose close waits for the process
    1000      class ESC[4;38;5;81m_wrap_close:
    1001          def __init__(self, stream, proc):
    1002              self._stream = stream
    1003              self._proc = proc
    1004          def close(self):
    1005              self._stream.close()
    1006              returncode = self._proc.wait()
    1007              if returncode == 0:
    1008                  return None
    1009              if name == 'nt':
    1010                  return returncode
    1011              else:
    1012                  return returncode << 8  # Shift left to match old behavior
    1013          def __enter__(self):
    1014              return self
    1015          def __exit__(self, *args):
    1016              self.close()
    1017          def __getattr__(self, name):
    1018              return getattr(self._stream, name)
    1019          def __iter__(self):
    1020              return iter(self._stream)
    1021  
    1022      __all__.append("popen")
    1023  
    1024  # Supply os.fdopen()
    1025  def fdopen(fd, mode="r", buffering=-1, encoding=None, *args, **kwargs):
    1026      if not isinstance(fd, int):
    1027          raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
    1028      import io
    1029      if "b" not in mode:
    1030          encoding = io.text_encoding(encoding)
    1031      return io.open(fd, mode, buffering, encoding, *args, **kwargs)
    1032  
    1033  
    1034  # For testing purposes, make sure the function is available when the C
    1035  # implementation exists.
    1036  def _fspath(path):
    1037      """Return the path representation of a path-like object.
    1038  
    1039      If str or bytes is passed in, it is returned unchanged. Otherwise the
    1040      os.PathLike interface is used to get the path representation. If the
    1041      path representation is not str or bytes, TypeError is raised. If the
    1042      provided path is not str, bytes, or os.PathLike, TypeError is raised.
    1043      """
    1044      if isinstance(path, (str, bytes)):
    1045          return path
    1046  
    1047      # Work from the object's type to match method resolution of other magic
    1048      # methods.
    1049      path_type = type(path)
    1050      try:
    1051          path_repr = path_type.__fspath__(path)
    1052      except AttributeError:
    1053          if hasattr(path_type, '__fspath__'):
    1054              raise
    1055          else:
    1056              raise TypeError("expected str, bytes or os.PathLike object, "
    1057                              "not " + path_type.__name__)
    1058      if isinstance(path_repr, (str, bytes)):
    1059          return path_repr
    1060      else:
    1061          raise TypeError("expected {}.__fspath__() to return str or bytes, "
    1062                          "not {}".format(path_type.__name__,
    1063                                          type(path_repr).__name__))
    1064  
    1065  # If there is no C implementation, make the pure Python version the
    1066  # implementation as transparently as possible.
    1067  if not _exists('fspath'):
    1068      fspath = _fspath
    1069      fspath.__name__ = "fspath"
    1070  
    1071  
    1072  class ESC[4;38;5;81mPathLike(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mABC):
    1073  
    1074      """Abstract base class for implementing the file system path protocol."""
    1075  
    1076      @abc.abstractmethod
    1077      def __fspath__(self):
    1078          """Return the file system path representation of the object."""
    1079          raise NotImplementedError
    1080  
    1081      @classmethod
    1082      def __subclasshook__(cls, subclass):
    1083          if cls is PathLike:
    1084              return _check_methods(subclass, '__fspath__')
    1085          return NotImplemented
    1086  
    1087      __class_getitem__ = classmethod(GenericAlias)
    1088  
    1089  
    1090  if name == 'nt':
    1091      class ESC[4;38;5;81m_AddedDllDirectory:
    1092          def __init__(self, path, cookie, remove_dll_directory):
    1093              self.path = path
    1094              self._cookie = cookie
    1095              self._remove_dll_directory = remove_dll_directory
    1096          def close(self):
    1097              self._remove_dll_directory(self._cookie)
    1098              self.path = None
    1099          def __enter__(self):
    1100              return self
    1101          def __exit__(self, *args):
    1102              self.close()
    1103          def __repr__(self):
    1104              if self.path:
    1105                  return "<AddedDllDirectory({!r})>".format(self.path)
    1106              return "<AddedDllDirectory()>"
    1107  
    1108      def add_dll_directory(path):
    1109          """Add a path to the DLL search path.
    1110  
    1111          This search path is used when resolving dependencies for imported
    1112          extension modules (the module itself is resolved through sys.path),
    1113          and also by ctypes.
    1114  
    1115          Remove the directory by calling close() on the returned object or
    1116          using it in a with statement.
    1117          """
    1118          import nt
    1119          cookie = nt._add_dll_directory(path)
    1120          return _AddedDllDirectory(
    1121              path,
    1122              cookie,
    1123              nt._remove_dll_directory
    1124          )