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