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