(root)/
Python-3.12.0/
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  
     344      stack = [fspath(top)]
     345      islink, join = path.islink, path.join
     346      while stack:
     347          top = stack.pop()
     348          if isinstance(top, tuple):
     349              yield top
     350              continue
     351  
     352          dirs = []
     353          nondirs = []
     354          walk_dirs = []
     355  
     356          # We may not have read permission for top, in which case we can't
     357          # get a list of the files the directory contains.
     358          # We suppress the exception here, rather than blow up for a
     359          # minor reason when (say) a thousand readable directories are still
     360          # left to visit.
     361          try:
     362              scandir_it = scandir(top)
     363          except OSError as error:
     364              if onerror is not None:
     365                  onerror(error)
     366              continue
     367  
     368          cont = False
     369          with scandir_it:
     370              while True:
     371                  try:
     372                      try:
     373                          entry = next(scandir_it)
     374                      except StopIteration:
     375                          break
     376                  except OSError as error:
     377                      if onerror is not None:
     378                          onerror(error)
     379                      cont = True
     380                      break
     381  
     382                  try:
     383                      is_dir = entry.is_dir()
     384                  except OSError:
     385                      # If is_dir() raises an OSError, consider the entry not to
     386                      # be a directory, same behaviour as os.path.isdir().
     387                      is_dir = False
     388  
     389                  if is_dir:
     390                      dirs.append(entry.name)
     391                  else:
     392                      nondirs.append(entry.name)
     393  
     394                  if not topdown and is_dir:
     395                      # Bottom-up: traverse into sub-directory, but exclude
     396                      # symlinks to directories if followlinks is False
     397                      if followlinks:
     398                          walk_into = True
     399                      else:
     400                          try:
     401                              is_symlink = entry.is_symlink()
     402                          except OSError:
     403                              # If is_symlink() raises an OSError, consider the
     404                              # entry not to be a symbolic link, same behaviour
     405                              # as os.path.islink().
     406                              is_symlink = False
     407                          walk_into = not is_symlink
     408  
     409                      if walk_into:
     410                          walk_dirs.append(entry.path)
     411          if cont:
     412              continue
     413  
     414          if topdown:
     415              # Yield before sub-directory traversal if going top down
     416              yield top, dirs, nondirs
     417              # Traverse into sub-directories
     418              for dirname in reversed(dirs):
     419                  new_path = join(top, dirname)
     420                  # bpo-23605: os.path.islink() is used instead of caching
     421                  # entry.is_symlink() result during the loop on os.scandir() because
     422                  # the caller can replace the directory entry during the "yield"
     423                  # above.
     424                  if followlinks or not islink(new_path):
     425                      stack.append(new_path)
     426          else:
     427              # Yield after sub-directory traversal if going bottom up
     428              stack.append((top, dirs, nondirs))
     429              # Traverse into sub-directories
     430              for new_path in reversed(walk_dirs):
     431                  stack.append(new_path)
     432  
     433  __all__.append("walk")
     434  
     435  if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
     436  
     437      def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None):
     438          """Directory tree generator.
     439  
     440          This behaves exactly like walk(), except that it yields a 4-tuple
     441  
     442              dirpath, dirnames, filenames, dirfd
     443  
     444          `dirpath`, `dirnames` and `filenames` are identical to walk() output,
     445          and `dirfd` is a file descriptor referring to the directory `dirpath`.
     446  
     447          The advantage of fwalk() over walk() is that it's safe against symlink
     448          races (when follow_symlinks is False).
     449  
     450          If dir_fd is not None, it should be a file descriptor open to a directory,
     451            and top should be relative; top will then be relative to that directory.
     452            (dir_fd is always supported for fwalk.)
     453  
     454          Caution:
     455          Since fwalk() yields file descriptors, those are only valid until the
     456          next iteration step, so you should dup() them if you want to keep them
     457          for a longer period.
     458  
     459          Example:
     460  
     461          import os
     462          for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
     463              print(root, "consumes", end="")
     464              print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files),
     465                    end="")
     466              print("bytes in", len(files), "non-directory files")
     467              if 'CVS' in dirs:
     468                  dirs.remove('CVS')  # don't visit CVS directories
     469          """
     470          sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
     471          top = fspath(top)
     472          # Note: To guard against symlink races, we use the standard
     473          # lstat()/open()/fstat() trick.
     474          if not follow_symlinks:
     475              orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
     476          topfd = open(top, O_RDONLY, dir_fd=dir_fd)
     477          try:
     478              if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
     479                                      path.samestat(orig_st, stat(topfd)))):
     480                  yield from _fwalk(topfd, top, isinstance(top, bytes),
     481                                    topdown, onerror, follow_symlinks)
     482          finally:
     483              close(topfd)
     484  
     485      def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
     486          # Note: This uses O(depth of the directory tree) file descriptors: if
     487          # necessary, it can be adapted to only require O(1) FDs, see issue
     488          # #13734.
     489  
     490          scandir_it = scandir(topfd)
     491          dirs = []
     492          nondirs = []
     493          entries = None if topdown or follow_symlinks else []
     494          for entry in scandir_it:
     495              name = entry.name
     496              if isbytes:
     497                  name = fsencode(name)
     498              try:
     499                  if entry.is_dir():
     500                      dirs.append(name)
     501                      if entries is not None:
     502                          entries.append(entry)
     503                  else:
     504                      nondirs.append(name)
     505              except OSError:
     506                  try:
     507                      # Add dangling symlinks, ignore disappeared files
     508                      if entry.is_symlink():
     509                          nondirs.append(name)
     510                  except OSError:
     511                      pass
     512  
     513          if topdown:
     514              yield toppath, dirs, nondirs, topfd
     515  
     516          for name in dirs if entries is None else zip(dirs, entries):
     517              try:
     518                  if not follow_symlinks:
     519                      if topdown:
     520                          orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
     521                      else:
     522                          assert entries is not None
     523                          name, entry = name
     524                          orig_st = entry.stat(follow_symlinks=False)
     525                  dirfd = open(name, O_RDONLY, dir_fd=topfd)
     526              except OSError as err:
     527                  if onerror is not None:
     528                      onerror(err)
     529                  continue
     530              try:
     531                  if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
     532                      dirpath = path.join(toppath, name)
     533                      yield from _fwalk(dirfd, dirpath, isbytes,
     534                                        topdown, onerror, follow_symlinks)
     535              finally:
     536                  close(dirfd)
     537  
     538          if not topdown:
     539              yield toppath, dirs, nondirs, topfd
     540  
     541      __all__.append("fwalk")
     542  
     543  def execl(file, *args):
     544      """execl(file, *args)
     545  
     546      Execute the executable file with argument list args, replacing the
     547      current process. """
     548      execv(file, args)
     549  
     550  def execle(file, *args):
     551      """execle(file, *args, env)
     552  
     553      Execute the executable file with argument list args and
     554      environment env, replacing the current process. """
     555      env = args[-1]
     556      execve(file, args[:-1], env)
     557  
     558  def execlp(file, *args):
     559      """execlp(file, *args)
     560  
     561      Execute the executable file (which is searched for along $PATH)
     562      with argument list args, replacing the current process. """
     563      execvp(file, args)
     564  
     565  def execlpe(file, *args):
     566      """execlpe(file, *args, env)
     567  
     568      Execute the executable file (which is searched for along $PATH)
     569      with argument list args and environment env, replacing the current
     570      process. """
     571      env = args[-1]
     572      execvpe(file, args[:-1], env)
     573  
     574  def execvp(file, args):
     575      """execvp(file, args)
     576  
     577      Execute the executable file (which is searched for along $PATH)
     578      with argument list args, replacing the current process.
     579      args may be a list or tuple of strings. """
     580      _execvpe(file, args)
     581  
     582  def execvpe(file, args, env):
     583      """execvpe(file, args, env)
     584  
     585      Execute the executable file (which is searched for along $PATH)
     586      with argument list args and environment env, replacing the
     587      current process.
     588      args may be a list or tuple of strings. """
     589      _execvpe(file, args, env)
     590  
     591  __all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
     592  
     593  def _execvpe(file, args, env=None):
     594      if env is not None:
     595          exec_func = execve
     596          argrest = (args, env)
     597      else:
     598          exec_func = execv
     599          argrest = (args,)
     600          env = environ
     601  
     602      if path.dirname(file):
     603          exec_func(file, *argrest)
     604          return
     605      saved_exc = None
     606      path_list = get_exec_path(env)
     607      if name != 'nt':
     608          file = fsencode(file)
     609          path_list = map(fsencode, path_list)
     610      for dir in path_list:
     611          fullname = path.join(dir, file)
     612          try:
     613              exec_func(fullname, *argrest)
     614          except (FileNotFoundError, NotADirectoryError) as e:
     615              last_exc = e
     616          except OSError as e:
     617              last_exc = e
     618              if saved_exc is None:
     619                  saved_exc = e
     620      if saved_exc is not None:
     621          raise saved_exc
     622      raise last_exc
     623  
     624  
     625  def get_exec_path(env=None):
     626      """Returns the sequence of directories that will be searched for the
     627      named executable (similar to a shell) when launching a process.
     628  
     629      *env* must be an environment variable dict or None.  If *env* is None,
     630      os.environ will be used.
     631      """
     632      # Use a local import instead of a global import to limit the number of
     633      # modules loaded at startup: the os module is always loaded at startup by
     634      # Python. It may also avoid a bootstrap issue.
     635      import warnings
     636  
     637      if env is None:
     638          env = environ
     639  
     640      # {b'PATH': ...}.get('PATH') and {'PATH': ...}.get(b'PATH') emit a
     641      # BytesWarning when using python -b or python -bb: ignore the warning
     642      with warnings.catch_warnings():
     643          warnings.simplefilter("ignore", BytesWarning)
     644  
     645          try:
     646              path_list = env.get('PATH')
     647          except TypeError:
     648              path_list = None
     649  
     650          if supports_bytes_environ:
     651              try:
     652                  path_listb = env[b'PATH']
     653              except (KeyError, TypeError):
     654                  pass
     655              else:
     656                  if path_list is not None:
     657                      raise ValueError(
     658                          "env cannot contain 'PATH' and b'PATH' keys")
     659                  path_list = path_listb
     660  
     661              if path_list is not None and isinstance(path_list, bytes):
     662                  path_list = fsdecode(path_list)
     663  
     664      if path_list is None:
     665          path_list = defpath
     666      return path_list.split(pathsep)
     667  
     668  
     669  # Change environ to automatically call putenv() and unsetenv()
     670  from _collections_abc import MutableMapping, Mapping
     671  
     672  class ESC[4;38;5;81m_Environ(ESC[4;38;5;149mMutableMapping):
     673      def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
     674          self.encodekey = encodekey
     675          self.decodekey = decodekey
     676          self.encodevalue = encodevalue
     677          self.decodevalue = decodevalue
     678          self._data = data
     679  
     680      def __getitem__(self, key):
     681          try:
     682              value = self._data[self.encodekey(key)]
     683          except KeyError:
     684              # raise KeyError with the original key value
     685              raise KeyError(key) from None
     686          return self.decodevalue(value)
     687  
     688      def __setitem__(self, key, value):
     689          key = self.encodekey(key)
     690          value = self.encodevalue(value)
     691          putenv(key, value)
     692          self._data[key] = value
     693  
     694      def __delitem__(self, key):
     695          encodedkey = self.encodekey(key)
     696          unsetenv(encodedkey)
     697          try:
     698              del self._data[encodedkey]
     699          except KeyError:
     700              # raise KeyError with the original key value
     701              raise KeyError(key) from None
     702  
     703      def __iter__(self):
     704          # list() from dict object is an atomic operation
     705          keys = list(self._data)
     706          for key in keys:
     707              yield self.decodekey(key)
     708  
     709      def __len__(self):
     710          return len(self._data)
     711  
     712      def __repr__(self):
     713          formatted_items = ", ".join(
     714              f"{self.decodekey(key)!r}: {self.decodevalue(value)!r}"
     715              for key, value in self._data.items()
     716          )
     717          return f"environ({{{formatted_items}}})"
     718  
     719      def copy(self):
     720          return dict(self)
     721  
     722      def setdefault(self, key, value):
     723          if key not in self:
     724              self[key] = value
     725          return self[key]
     726  
     727      def __ior__(self, other):
     728          self.update(other)
     729          return self
     730  
     731      def __or__(self, other):
     732          if not isinstance(other, Mapping):
     733              return NotImplemented
     734          new = dict(self)
     735          new.update(other)
     736          return new
     737  
     738      def __ror__(self, other):
     739          if not isinstance(other, Mapping):
     740              return NotImplemented
     741          new = dict(other)
     742          new.update(self)
     743          return new
     744  
     745  def _createenviron():
     746      if name == 'nt':
     747          # Where Env Var Names Must Be UPPERCASE
     748          def check_str(value):
     749              if not isinstance(value, str):
     750                  raise TypeError("str expected, not %s" % type(value).__name__)
     751              return value
     752          encode = check_str
     753          decode = str
     754          def encodekey(key):
     755              return encode(key).upper()
     756          data = {}
     757          for key, value in environ.items():
     758              data[encodekey(key)] = value
     759      else:
     760          # Where Env Var Names Can Be Mixed Case
     761          encoding = sys.getfilesystemencoding()
     762          def encode(value):
     763              if not isinstance(value, str):
     764                  raise TypeError("str expected, not %s" % type(value).__name__)
     765              return value.encode(encoding, 'surrogateescape')
     766          def decode(value):
     767              return value.decode(encoding, 'surrogateescape')
     768          encodekey = encode
     769          data = environ
     770      return _Environ(data,
     771          encodekey, decode,
     772          encode, decode)
     773  
     774  # unicode environ
     775  environ = _createenviron()
     776  del _createenviron
     777  
     778  
     779  def getenv(key, default=None):
     780      """Get an environment variable, return None if it doesn't exist.
     781      The optional second argument can specify an alternate default.
     782      key, default and the result are str."""
     783      return environ.get(key, default)
     784  
     785  supports_bytes_environ = (name != 'nt')
     786  __all__.extend(("getenv", "supports_bytes_environ"))
     787  
     788  if supports_bytes_environ:
     789      def _check_bytes(value):
     790          if not isinstance(value, bytes):
     791              raise TypeError("bytes expected, not %s" % type(value).__name__)
     792          return value
     793  
     794      # bytes environ
     795      environb = _Environ(environ._data,
     796          _check_bytes, bytes,
     797          _check_bytes, bytes)
     798      del _check_bytes
     799  
     800      def getenvb(key, default=None):
     801          """Get an environment variable, return None if it doesn't exist.
     802          The optional second argument can specify an alternate default.
     803          key, default and the result are bytes."""
     804          return environb.get(key, default)
     805  
     806      __all__.extend(("environb", "getenvb"))
     807  
     808  def _fscodec():
     809      encoding = sys.getfilesystemencoding()
     810      errors = sys.getfilesystemencodeerrors()
     811  
     812      def fsencode(filename):
     813          """Encode filename (an os.PathLike, bytes, or str) to the filesystem
     814          encoding with 'surrogateescape' error handler, return bytes unchanged.
     815          On Windows, use 'strict' error handler if the file system encoding is
     816          'mbcs' (which is the default encoding).
     817          """
     818          filename = fspath(filename)  # Does type-checking of `filename`.
     819          if isinstance(filename, str):
     820              return filename.encode(encoding, errors)
     821          else:
     822              return filename
     823  
     824      def fsdecode(filename):
     825          """Decode filename (an os.PathLike, bytes, or str) from the filesystem
     826          encoding with 'surrogateescape' error handler, return str unchanged. On
     827          Windows, use 'strict' error handler if the file system encoding is
     828          'mbcs' (which is the default encoding).
     829          """
     830          filename = fspath(filename)  # Does type-checking of `filename`.
     831          if isinstance(filename, bytes):
     832              return filename.decode(encoding, errors)
     833          else:
     834              return filename
     835  
     836      return fsencode, fsdecode
     837  
     838  fsencode, fsdecode = _fscodec()
     839  del _fscodec
     840  
     841  # Supply spawn*() (probably only for Unix)
     842  if _exists("fork") and not _exists("spawnv") and _exists("execv"):
     843  
     844      P_WAIT = 0
     845      P_NOWAIT = P_NOWAITO = 1
     846  
     847      __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"])
     848  
     849      # XXX Should we support P_DETACH?  I suppose it could fork()**2
     850      # and close the std I/O streams.  Also, P_OVERLAY is the same
     851      # as execv*()?
     852  
     853      def _spawnvef(mode, file, args, env, func):
     854          # Internal helper; func is the exec*() function to use
     855          if not isinstance(args, (tuple, list)):
     856              raise TypeError('argv must be a tuple or a list')
     857          if not args or not args[0]:
     858              raise ValueError('argv first element cannot be empty')
     859          pid = fork()
     860          if not pid:
     861              # Child
     862              try:
     863                  if env is None:
     864                      func(file, args)
     865                  else:
     866                      func(file, args, env)
     867              except:
     868                  _exit(127)
     869          else:
     870              # Parent
     871              if mode == P_NOWAIT:
     872                  return pid # Caller is responsible for waiting!
     873              while 1:
     874                  wpid, sts = waitpid(pid, 0)
     875                  if WIFSTOPPED(sts):
     876                      continue
     877  
     878                  return waitstatus_to_exitcode(sts)
     879  
     880      def spawnv(mode, file, args):
     881          """spawnv(mode, file, args) -> integer
     882  
     883  Execute file with arguments from args in a subprocess.
     884  If mode == P_NOWAIT return the pid of the process.
     885  If mode == P_WAIT return the process's exit code if it exits normally;
     886  otherwise return -SIG, where SIG is the signal that killed it. """
     887          return _spawnvef(mode, file, args, None, execv)
     888  
     889      def spawnve(mode, file, args, env):
     890          """spawnve(mode, file, args, env) -> integer
     891  
     892  Execute file with arguments from args in a subprocess with the
     893  specified environment.
     894  If mode == P_NOWAIT return the pid of the process.
     895  If mode == P_WAIT return the process's exit code if it exits normally;
     896  otherwise return -SIG, where SIG is the signal that killed it. """
     897          return _spawnvef(mode, file, args, env, execve)
     898  
     899      # Note: spawnvp[e] isn't currently supported on Windows
     900  
     901      def spawnvp(mode, file, args):
     902          """spawnvp(mode, file, args) -> integer
     903  
     904  Execute file (which is looked for along $PATH) with arguments from
     905  args in a subprocess.
     906  If mode == P_NOWAIT return the pid of the process.
     907  If mode == P_WAIT return the process's exit code if it exits normally;
     908  otherwise return -SIG, where SIG is the signal that killed it. """
     909          return _spawnvef(mode, file, args, None, execvp)
     910  
     911      def spawnvpe(mode, file, args, env):
     912          """spawnvpe(mode, file, args, env) -> integer
     913  
     914  Execute file (which is looked for along $PATH) with arguments from
     915  args in a subprocess with the supplied environment.
     916  If mode == P_NOWAIT return the pid of the process.
     917  If mode == P_WAIT return the process's exit code if it exits normally;
     918  otherwise return -SIG, where SIG is the signal that killed it. """
     919          return _spawnvef(mode, file, args, env, execvpe)
     920  
     921  
     922      __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"])
     923  
     924  
     925  if _exists("spawnv"):
     926      # These aren't supplied by the basic Windows code
     927      # but can be easily implemented in Python
     928  
     929      def spawnl(mode, file, *args):
     930          """spawnl(mode, file, *args) -> integer
     931  
     932  Execute file with arguments from args in a subprocess.
     933  If mode == P_NOWAIT return the pid of the process.
     934  If mode == P_WAIT return the process's exit code if it exits normally;
     935  otherwise return -SIG, where SIG is the signal that killed it. """
     936          return spawnv(mode, file, args)
     937  
     938      def spawnle(mode, file, *args):
     939          """spawnle(mode, file, *args, env) -> integer
     940  
     941  Execute file with arguments from args in a subprocess with the
     942  supplied environment.
     943  If mode == P_NOWAIT return the pid of the process.
     944  If mode == P_WAIT return the process's exit code if it exits normally;
     945  otherwise return -SIG, where SIG is the signal that killed it. """
     946          env = args[-1]
     947          return spawnve(mode, file, args[:-1], env)
     948  
     949  
     950      __all__.extend(["spawnl", "spawnle"])
     951  
     952  
     953  if _exists("spawnvp"):
     954      # At the moment, Windows doesn't implement spawnvp[e],
     955      # so it won't have spawnlp[e] either.
     956      def spawnlp(mode, file, *args):
     957          """spawnlp(mode, file, *args) -> integer
     958  
     959  Execute file (which is looked for along $PATH) with arguments from
     960  args in a subprocess with the supplied environment.
     961  If mode == P_NOWAIT return the pid of the process.
     962  If mode == P_WAIT return the process's exit code if it exits normally;
     963  otherwise return -SIG, where SIG is the signal that killed it. """
     964          return spawnvp(mode, file, args)
     965  
     966      def spawnlpe(mode, file, *args):
     967          """spawnlpe(mode, file, *args, env) -> integer
     968  
     969  Execute file (which is looked for along $PATH) with arguments from
     970  args in a subprocess with the supplied environment.
     971  If mode == P_NOWAIT return the pid of the process.
     972  If mode == P_WAIT return the process's exit code if it exits normally;
     973  otherwise return -SIG, where SIG is the signal that killed it. """
     974          env = args[-1]
     975          return spawnvpe(mode, file, args[:-1], env)
     976  
     977  
     978      __all__.extend(["spawnlp", "spawnlpe"])
     979  
     980  # VxWorks has no user space shell provided. As a result, running
     981  # command in a shell can't be supported.
     982  if sys.platform != 'vxworks':
     983      # Supply os.popen()
     984      def popen(cmd, mode="r", buffering=-1):
     985          if not isinstance(cmd, str):
     986              raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
     987          if mode not in ("r", "w"):
     988              raise ValueError("invalid mode %r" % mode)
     989          if buffering == 0 or buffering is None:
     990              raise ValueError("popen() does not support unbuffered streams")
     991          import subprocess
     992          if mode == "r":
     993              proc = subprocess.Popen(cmd,
     994                                      shell=True, text=True,
     995                                      stdout=subprocess.PIPE,
     996                                      bufsize=buffering)
     997              return _wrap_close(proc.stdout, proc)
     998          else:
     999              proc = subprocess.Popen(cmd,
    1000                                      shell=True, text=True,
    1001                                      stdin=subprocess.PIPE,
    1002                                      bufsize=buffering)
    1003              return _wrap_close(proc.stdin, proc)
    1004  
    1005      # Helper for popen() -- a proxy for a file whose close waits for the process
    1006      class ESC[4;38;5;81m_wrap_close:
    1007          def __init__(self, stream, proc):
    1008              self._stream = stream
    1009              self._proc = proc
    1010          def close(self):
    1011              self._stream.close()
    1012              returncode = self._proc.wait()
    1013              if returncode == 0:
    1014                  return None
    1015              if name == 'nt':
    1016                  return returncode
    1017              else:
    1018                  return returncode << 8  # Shift left to match old behavior
    1019          def __enter__(self):
    1020              return self
    1021          def __exit__(self, *args):
    1022              self.close()
    1023          def __getattr__(self, name):
    1024              return getattr(self._stream, name)
    1025          def __iter__(self):
    1026              return iter(self._stream)
    1027  
    1028      __all__.append("popen")
    1029  
    1030  # Supply os.fdopen()
    1031  def fdopen(fd, mode="r", buffering=-1, encoding=None, *args, **kwargs):
    1032      if not isinstance(fd, int):
    1033          raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
    1034      import io
    1035      if "b" not in mode:
    1036          encoding = io.text_encoding(encoding)
    1037      return io.open(fd, mode, buffering, encoding, *args, **kwargs)
    1038  
    1039  
    1040  # For testing purposes, make sure the function is available when the C
    1041  # implementation exists.
    1042  def _fspath(path):
    1043      """Return the path representation of a path-like object.
    1044  
    1045      If str or bytes is passed in, it is returned unchanged. Otherwise the
    1046      os.PathLike interface is used to get the path representation. If the
    1047      path representation is not str or bytes, TypeError is raised. If the
    1048      provided path is not str, bytes, or os.PathLike, TypeError is raised.
    1049      """
    1050      if isinstance(path, (str, bytes)):
    1051          return path
    1052  
    1053      # Work from the object's type to match method resolution of other magic
    1054      # methods.
    1055      path_type = type(path)
    1056      try:
    1057          path_repr = path_type.__fspath__(path)
    1058      except AttributeError:
    1059          if hasattr(path_type, '__fspath__'):
    1060              raise
    1061          else:
    1062              raise TypeError("expected str, bytes or os.PathLike object, "
    1063                              "not " + path_type.__name__)
    1064      if isinstance(path_repr, (str, bytes)):
    1065          return path_repr
    1066      else:
    1067          raise TypeError("expected {}.__fspath__() to return str or bytes, "
    1068                          "not {}".format(path_type.__name__,
    1069                                          type(path_repr).__name__))
    1070  
    1071  # If there is no C implementation, make the pure Python version the
    1072  # implementation as transparently as possible.
    1073  if not _exists('fspath'):
    1074      fspath = _fspath
    1075      fspath.__name__ = "fspath"
    1076  
    1077  
    1078  class ESC[4;38;5;81mPathLike(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mABC):
    1079  
    1080      """Abstract base class for implementing the file system path protocol."""
    1081  
    1082      @abc.abstractmethod
    1083      def __fspath__(self):
    1084          """Return the file system path representation of the object."""
    1085          raise NotImplementedError
    1086  
    1087      @classmethod
    1088      def __subclasshook__(cls, subclass):
    1089          if cls is PathLike:
    1090              return _check_methods(subclass, '__fspath__')
    1091          return NotImplemented
    1092  
    1093      __class_getitem__ = classmethod(GenericAlias)
    1094  
    1095  
    1096  if name == 'nt':
    1097      class ESC[4;38;5;81m_AddedDllDirectory:
    1098          def __init__(self, path, cookie, remove_dll_directory):
    1099              self.path = path
    1100              self._cookie = cookie
    1101              self._remove_dll_directory = remove_dll_directory
    1102          def close(self):
    1103              self._remove_dll_directory(self._cookie)
    1104              self.path = None
    1105          def __enter__(self):
    1106              return self
    1107          def __exit__(self, *args):
    1108              self.close()
    1109          def __repr__(self):
    1110              if self.path:
    1111                  return "<AddedDllDirectory({!r})>".format(self.path)
    1112              return "<AddedDllDirectory()>"
    1113  
    1114      def add_dll_directory(path):
    1115          """Add a path to the DLL search path.
    1116  
    1117          This search path is used when resolving dependencies for imported
    1118          extension modules (the module itself is resolved through sys.path),
    1119          and also by ctypes.
    1120  
    1121          Remove the directory by calling close() on the returned object or
    1122          using it in a with statement.
    1123          """
    1124          import nt
    1125          cookie = nt._add_dll_directory(path)
    1126          return _AddedDllDirectory(
    1127              path,
    1128              cookie,
    1129              nt._remove_dll_directory
    1130          )