xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/os.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
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 (including symlinks to directories,
292    and excluding '.' and '..').
293    filenames is a list of the names of the non-directory files in dirpath.
294    Note that the names in the lists are just names, with no path components.
295    To get a full path (which begins with top) to a file or directory in
296    dirpath, do os.path.join(dirpath, name).
297
298    If optional arg 'topdown' is true or not specified, the triple for a
299    directory is generated before the triples for any of its subdirectories
300    (directories are generated top down).  If topdown is false, the triple
301    for a directory is generated after the triples for all of its
302    subdirectories (directories are generated bottom up).
303
304    When topdown is true, the caller can modify the dirnames list in-place
305    (e.g., via del or slice assignment), and walk will only recurse into the
306    subdirectories whose names remain in dirnames; this can be used to prune the
307    search, or to impose a specific order of visiting.  Modifying dirnames when
308    topdown is false has no effect on the behavior of os.walk(), since the
309    directories in dirnames have already been generated by the time dirnames
310    itself is generated. No matter the value of topdown, the list of
311    subdirectories is retrieved before the tuples for the directory and its
312    subdirectories are generated.
313
314    By default errors from the os.scandir() call are ignored.  If
315    optional arg 'onerror' is specified, it should be a function; it
316    will be called with one argument, an OSError instance.  It can
317    report the error to continue with the walk, or raise the exception
318    to abort the walk.  Note that the filename is available as the
319    filename attribute of the exception object.
320
321    By default, os.walk does not follow symbolic links to subdirectories on
322    systems that support them.  In order to get this functionality, set the
323    optional argument 'followlinks' to true.
324
325    Caution:  if you pass a relative pathname for top, don't change the
326    current working directory between resumptions of walk.  walk never
327    changes the current directory, and assumes that the client doesn't
328    either.
329
330    Example:
331
332    import os
333    from os.path import join, getsize
334    for root, dirs, files in os.walk('python/Lib/email'):
335        print(root, "consumes ")
336        print(sum(getsize(join(root, name)) for name in files), end=" ")
337        print("bytes in", len(files), "non-directory files")
338        if 'CVS' in dirs:
339            dirs.remove('CVS')  # don't visit CVS directories
340
341    """
342    sys.audit("os.walk", top, topdown, onerror, followlinks)
343    return _walk(fspath(top), topdown, onerror, followlinks)
344
345def _walk(top, topdown, onerror, followlinks):
346    dirs = []
347    nondirs = []
348    walk_dirs = []
349
350    # We may not have read permission for top, in which case we can't
351    # get a list of the files the directory contains.  os.walk
352    # always suppressed the exception then, rather than blow up for a
353    # minor reason when (say) a thousand readable directories are still
354    # left to visit.  That logic is copied here.
355    try:
356        # Note that scandir is global in this module due
357        # to earlier import-*.
358        scandir_it = scandir(top)
359    except OSError as error:
360        if onerror is not None:
361            onerror(error)
362        return
363
364    with scandir_it:
365        while True:
366            try:
367                try:
368                    entry = next(scandir_it)
369                except StopIteration:
370                    break
371            except OSError as error:
372                if onerror is not None:
373                    onerror(error)
374                return
375
376            try:
377                is_dir = entry.is_dir()
378            except OSError:
379                # If is_dir() raises an OSError, consider that the entry is not
380                # a directory, same behaviour than os.path.isdir().
381                is_dir = False
382
383            if is_dir:
384                dirs.append(entry.name)
385            else:
386                nondirs.append(entry.name)
387
388            if not topdown and is_dir:
389                # Bottom-up: recurse into sub-directory, but exclude symlinks to
390                # directories if followlinks is False
391                if followlinks:
392                    walk_into = True
393                else:
394                    try:
395                        is_symlink = entry.is_symlink()
396                    except OSError:
397                        # If is_symlink() raises an OSError, consider that the
398                        # entry is not a symbolic link, same behaviour than
399                        # os.path.islink().
400                        is_symlink = False
401                    walk_into = not is_symlink
402
403                if walk_into:
404                    walk_dirs.append(entry.path)
405
406    # Yield before recursion if going top down
407    if topdown:
408        yield top, dirs, nondirs
409
410        # Recurse into sub-directories
411        islink, join = path.islink, path.join
412        for dirname in dirs:
413            new_path = join(top, dirname)
414            # Issue #23605: os.path.islink() is used instead of caching
415            # entry.is_symlink() result during the loop on os.scandir() because
416            # the caller can replace the directory entry during the "yield"
417            # above.
418            if followlinks or not islink(new_path):
419                yield from _walk(new_path, topdown, onerror, followlinks)
420    else:
421        # Recurse into sub-directories
422        for new_path in walk_dirs:
423            yield from _walk(new_path, topdown, onerror, followlinks)
424        # Yield after recursion if going bottom up
425        yield top, dirs, nondirs
426
427__all__.append("walk")
428
429if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
430
431    def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None):
432        """Directory tree generator.
433
434        This behaves exactly like walk(), except that it yields a 4-tuple
435
436            dirpath, dirnames, filenames, dirfd
437
438        `dirpath`, `dirnames` and `filenames` are identical to walk() output,
439        and `dirfd` is a file descriptor referring to the directory `dirpath`.
440
441        The advantage of fwalk() over walk() is that it's safe against symlink
442        races (when follow_symlinks is False).
443
444        If dir_fd is not None, it should be a file descriptor open to a directory,
445          and top should be relative; top will then be relative to that directory.
446          (dir_fd is always supported for fwalk.)
447
448        Caution:
449        Since fwalk() yields file descriptors, those are only valid until the
450        next iteration step, so you should dup() them if you want to keep them
451        for a longer period.
452
453        Example:
454
455        import os
456        for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
457            print(root, "consumes", end="")
458            print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files),
459                  end="")
460            print("bytes in", len(files), "non-directory files")
461            if 'CVS' in dirs:
462                dirs.remove('CVS')  # don't visit CVS directories
463        """
464        sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
465        top = fspath(top)
466        # Note: To guard against symlink races, we use the standard
467        # lstat()/open()/fstat() trick.
468        if not follow_symlinks:
469            orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
470        topfd = open(top, O_RDONLY, dir_fd=dir_fd)
471        try:
472            if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
473                                    path.samestat(orig_st, stat(topfd)))):
474                yield from _fwalk(topfd, top, isinstance(top, bytes),
475                                  topdown, onerror, follow_symlinks)
476        finally:
477            close(topfd)
478
479    def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
480        # Note: This uses O(depth of the directory tree) file descriptors: if
481        # necessary, it can be adapted to only require O(1) FDs, see issue
482        # #13734.
483
484        scandir_it = scandir(topfd)
485        dirs = []
486        nondirs = []
487        entries = None if topdown or follow_symlinks else []
488        for entry in scandir_it:
489            name = entry.name
490            if isbytes:
491                name = fsencode(name)
492            try:
493                if entry.is_dir():
494                    dirs.append(name)
495                    if entries is not None:
496                        entries.append(entry)
497                else:
498                    nondirs.append(name)
499            except OSError:
500                try:
501                    # Add dangling symlinks, ignore disappeared files
502                    if entry.is_symlink():
503                        nondirs.append(name)
504                except OSError:
505                    pass
506
507        if topdown:
508            yield toppath, dirs, nondirs, topfd
509
510        for name in dirs if entries is None else zip(dirs, entries):
511            try:
512                if not follow_symlinks:
513                    if topdown:
514                        orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
515                    else:
516                        assert entries is not None
517                        name, entry = name
518                        orig_st = entry.stat(follow_symlinks=False)
519                dirfd = open(name, O_RDONLY, dir_fd=topfd)
520            except OSError as err:
521                if onerror is not None:
522                    onerror(err)
523                continue
524            try:
525                if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
526                    dirpath = path.join(toppath, name)
527                    yield from _fwalk(dirfd, dirpath, isbytes,
528                                      topdown, onerror, follow_symlinks)
529            finally:
530                close(dirfd)
531
532        if not topdown:
533            yield toppath, dirs, nondirs, topfd
534
535    __all__.append("fwalk")
536
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        formatted_items = ", ".join(
708            f"{self.decodekey(key)!r}: {self.decodevalue(value)!r}"
709            for key, value in self._data.items()
710        )
711        return f"environ({{{formatted_items}}})"
712
713    def copy(self):
714        return dict(self)
715
716    def setdefault(self, key, value):
717        if key not in self:
718            self[key] = value
719        return self[key]
720
721    def __ior__(self, other):
722        self.update(other)
723        return self
724
725    def __or__(self, other):
726        if not isinstance(other, Mapping):
727            return NotImplemented
728        new = dict(self)
729        new.update(other)
730        return new
731
732    def __ror__(self, other):
733        if not isinstance(other, Mapping):
734            return NotImplemented
735        new = dict(other)
736        new.update(self)
737        return new
738
739def _createenviron():
740    if name == 'nt':
741        # Where Env Var Names Must Be UPPERCASE
742        def check_str(value):
743            if not isinstance(value, str):
744                raise TypeError("str expected, not %s" % type(value).__name__)
745            return value
746        encode = check_str
747        decode = str
748        def encodekey(key):
749            return encode(key).upper()
750        data = {}
751        for key, value in environ.items():
752            data[encodekey(key)] = value
753    else:
754        # Where Env Var Names Can Be Mixed Case
755        encoding = sys.getfilesystemencoding()
756        def encode(value):
757            if not isinstance(value, str):
758                raise TypeError("str expected, not %s" % type(value).__name__)
759            return value.encode(encoding, 'surrogateescape')
760        def decode(value):
761            return value.decode(encoding, 'surrogateescape')
762        encodekey = encode
763        data = environ
764    return _Environ(data,
765        encodekey, decode,
766        encode, decode)
767
768# unicode environ
769environ = _createenviron()
770del _createenviron
771
772
773def getenv(key, default=None):
774    """Get an environment variable, return None if it doesn't exist.
775    The optional second argument can specify an alternate default.
776    key, default and the result are str."""
777    return environ.get(key, default)
778
779supports_bytes_environ = (name != 'nt')
780__all__.extend(("getenv", "supports_bytes_environ"))
781
782if supports_bytes_environ:
783    def _check_bytes(value):
784        if not isinstance(value, bytes):
785            raise TypeError("bytes expected, not %s" % type(value).__name__)
786        return value
787
788    # bytes environ
789    environb = _Environ(environ._data,
790        _check_bytes, bytes,
791        _check_bytes, bytes)
792    del _check_bytes
793
794    def getenvb(key, default=None):
795        """Get an environment variable, return None if it doesn't exist.
796        The optional second argument can specify an alternate default.
797        key, default and the result are bytes."""
798        return environb.get(key, default)
799
800    __all__.extend(("environb", "getenvb"))
801
802def _fscodec():
803    encoding = sys.getfilesystemencoding()
804    errors = sys.getfilesystemencodeerrors()
805
806    def fsencode(filename):
807        """Encode filename (an os.PathLike, bytes, or str) to the filesystem
808        encoding with 'surrogateescape' error handler, return bytes unchanged.
809        On Windows, use 'strict' error handler if the file system encoding is
810        'mbcs' (which is the default encoding).
811        """
812        filename = fspath(filename)  # Does type-checking of `filename`.
813        if isinstance(filename, str):
814            return filename.encode(encoding, errors)
815        else:
816            return filename
817
818    def fsdecode(filename):
819        """Decode filename (an os.PathLike, bytes, or str) from the filesystem
820        encoding with 'surrogateescape' error handler, return str unchanged. On
821        Windows, use 'strict' error handler if the file system encoding is
822        'mbcs' (which is the default encoding).
823        """
824        filename = fspath(filename)  # Does type-checking of `filename`.
825        if isinstance(filename, bytes):
826            return filename.decode(encoding, errors)
827        else:
828            return filename
829
830    return fsencode, fsdecode
831
832fsencode, fsdecode = _fscodec()
833del _fscodec
834
835# Supply spawn*() (probably only for Unix)
836if _exists("fork") and not _exists("spawnv") and _exists("execv"):
837
838    P_WAIT = 0
839    P_NOWAIT = P_NOWAITO = 1
840
841    __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"])
842
843    # XXX Should we support P_DETACH?  I suppose it could fork()**2
844    # and close the std I/O streams.  Also, P_OVERLAY is the same
845    # as execv*()?
846
847    def _spawnvef(mode, file, args, env, func):
848        # Internal helper; func is the exec*() function to use
849        if not isinstance(args, (tuple, list)):
850            raise TypeError('argv must be a tuple or a list')
851        if not args or not args[0]:
852            raise ValueError('argv first element cannot be empty')
853        pid = fork()
854        if not pid:
855            # Child
856            try:
857                if env is None:
858                    func(file, args)
859                else:
860                    func(file, args, env)
861            except:
862                _exit(127)
863        else:
864            # Parent
865            if mode == P_NOWAIT:
866                return pid # Caller is responsible for waiting!
867            while 1:
868                wpid, sts = waitpid(pid, 0)
869                if WIFSTOPPED(sts):
870                    continue
871
872                return waitstatus_to_exitcode(sts)
873
874    def spawnv(mode, file, args):
875        """spawnv(mode, file, args) -> integer
876
877Execute file with arguments from args in a subprocess.
878If mode == P_NOWAIT return the pid of the process.
879If mode == P_WAIT return the process's exit code if it exits normally;
880otherwise return -SIG, where SIG is the signal that killed it. """
881        return _spawnvef(mode, file, args, None, execv)
882
883    def spawnve(mode, file, args, env):
884        """spawnve(mode, file, args, env) -> integer
885
886Execute file with arguments from args in a subprocess with the
887specified environment.
888If mode == P_NOWAIT return the pid of the process.
889If mode == P_WAIT return the process's exit code if it exits normally;
890otherwise return -SIG, where SIG is the signal that killed it. """
891        return _spawnvef(mode, file, args, env, execve)
892
893    # Note: spawnvp[e] isn't currently supported on Windows
894
895    def spawnvp(mode, file, args):
896        """spawnvp(mode, file, args) -> integer
897
898Execute file (which is looked for along $PATH) with arguments from
899args in a subprocess.
900If mode == P_NOWAIT return the pid of the process.
901If mode == P_WAIT return the process's exit code if it exits normally;
902otherwise return -SIG, where SIG is the signal that killed it. """
903        return _spawnvef(mode, file, args, None, execvp)
904
905    def spawnvpe(mode, file, args, env):
906        """spawnvpe(mode, file, args, env) -> integer
907
908Execute file (which is looked for along $PATH) with arguments from
909args in a subprocess with the supplied environment.
910If mode == P_NOWAIT return the pid of the process.
911If mode == P_WAIT return the process's exit code if it exits normally;
912otherwise return -SIG, where SIG is the signal that killed it. """
913        return _spawnvef(mode, file, args, env, execvpe)
914
915
916    __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"])
917
918
919if _exists("spawnv"):
920    # These aren't supplied by the basic Windows code
921    # but can be easily implemented in Python
922
923    def spawnl(mode, file, *args):
924        """spawnl(mode, file, *args) -> integer
925
926Execute file with arguments from args in a subprocess.
927If mode == P_NOWAIT return the pid of the process.
928If mode == P_WAIT return the process's exit code if it exits normally;
929otherwise return -SIG, where SIG is the signal that killed it. """
930        return spawnv(mode, file, args)
931
932    def spawnle(mode, file, *args):
933        """spawnle(mode, file, *args, env) -> integer
934
935Execute file with arguments from args in a subprocess with the
936supplied environment.
937If mode == P_NOWAIT return the pid of the process.
938If mode == P_WAIT return the process's exit code if it exits normally;
939otherwise return -SIG, where SIG is the signal that killed it. """
940        env = args[-1]
941        return spawnve(mode, file, args[:-1], env)
942
943
944    __all__.extend(["spawnl", "spawnle"])
945
946
947if _exists("spawnvp"):
948    # At the moment, Windows doesn't implement spawnvp[e],
949    # so it won't have spawnlp[e] either.
950    def spawnlp(mode, file, *args):
951        """spawnlp(mode, file, *args) -> integer
952
953Execute file (which is looked for along $PATH) with arguments from
954args in a subprocess with the supplied environment.
955If mode == P_NOWAIT return the pid of the process.
956If mode == P_WAIT return the process's exit code if it exits normally;
957otherwise return -SIG, where SIG is the signal that killed it. """
958        return spawnvp(mode, file, args)
959
960    def spawnlpe(mode, file, *args):
961        """spawnlpe(mode, file, *args, env) -> integer
962
963Execute file (which is looked for along $PATH) with arguments from
964args in a subprocess with the supplied environment.
965If mode == P_NOWAIT return the pid of the process.
966If mode == P_WAIT return the process's exit code if it exits normally;
967otherwise return -SIG, where SIG is the signal that killed it. """
968        env = args[-1]
969        return spawnvpe(mode, file, args[:-1], env)
970
971
972    __all__.extend(["spawnlp", "spawnlpe"])
973
974# VxWorks has no user space shell provided. As a result, running
975# command in a shell can't be supported.
976if sys.platform != 'vxworks':
977    # Supply os.popen()
978    def popen(cmd, mode="r", buffering=-1):
979        if not isinstance(cmd, str):
980            raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
981        if mode not in ("r", "w"):
982            raise ValueError("invalid mode %r" % mode)
983        if buffering == 0 or buffering is None:
984            raise ValueError("popen() does not support unbuffered streams")
985        import subprocess
986        if mode == "r":
987            proc = subprocess.Popen(cmd,
988                                    shell=True, text=True,
989                                    stdout=subprocess.PIPE,
990                                    bufsize=buffering)
991            return _wrap_close(proc.stdout, proc)
992        else:
993            proc = subprocess.Popen(cmd,
994                                    shell=True, text=True,
995                                    stdin=subprocess.PIPE,
996                                    bufsize=buffering)
997            return _wrap_close(proc.stdin, proc)
998
999    # Helper for popen() -- a proxy for a file whose close waits for the process
1000    class _wrap_close:
1001        def __init__(self, stream, proc):
1002            self._stream = stream
1003            self._proc = proc
1004        def close(self):
1005            self._stream.close()
1006            returncode = self._proc.wait()
1007            if returncode == 0:
1008                return None
1009            if name == 'nt':
1010                return returncode
1011            else:
1012                return returncode << 8  # Shift left to match old behavior
1013        def __enter__(self):
1014            return self
1015        def __exit__(self, *args):
1016            self.close()
1017        def __getattr__(self, name):
1018            return getattr(self._stream, name)
1019        def __iter__(self):
1020            return iter(self._stream)
1021
1022    __all__.append("popen")
1023
1024# Supply os.fdopen()
1025def fdopen(fd, mode="r", buffering=-1, encoding=None, *args, **kwargs):
1026    if not isinstance(fd, int):
1027        raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
1028    import io
1029    if "b" not in mode:
1030        encoding = io.text_encoding(encoding)
1031    return io.open(fd, mode, buffering, encoding, *args, **kwargs)
1032
1033
1034# For testing purposes, make sure the function is available when the C
1035# implementation exists.
1036def _fspath(path):
1037    """Return the path representation of a path-like object.
1038
1039    If str or bytes is passed in, it is returned unchanged. Otherwise the
1040    os.PathLike interface is used to get the path representation. If the
1041    path representation is not str or bytes, TypeError is raised. If the
1042    provided path is not str, bytes, or os.PathLike, TypeError is raised.
1043    """
1044    if isinstance(path, (str, bytes)):
1045        return path
1046
1047    # Work from the object's type to match method resolution of other magic
1048    # methods.
1049    path_type = type(path)
1050    try:
1051        path_repr = path_type.__fspath__(path)
1052    except AttributeError:
1053        if hasattr(path_type, '__fspath__'):
1054            raise
1055        else:
1056            raise TypeError("expected str, bytes or os.PathLike object, "
1057                            "not " + path_type.__name__)
1058    if isinstance(path_repr, (str, bytes)):
1059        return path_repr
1060    else:
1061        raise TypeError("expected {}.__fspath__() to return str or bytes, "
1062                        "not {}".format(path_type.__name__,
1063                                        type(path_repr).__name__))
1064
1065# If there is no C implementation, make the pure Python version the
1066# implementation as transparently as possible.
1067if not _exists('fspath'):
1068    fspath = _fspath
1069    fspath.__name__ = "fspath"
1070
1071
1072class PathLike(abc.ABC):
1073
1074    """Abstract base class for implementing the file system path protocol."""
1075
1076    @abc.abstractmethod
1077    def __fspath__(self):
1078        """Return the file system path representation of the object."""
1079        raise NotImplementedError
1080
1081    @classmethod
1082    def __subclasshook__(cls, subclass):
1083        if cls is PathLike:
1084            return _check_methods(subclass, '__fspath__')
1085        return NotImplemented
1086
1087    __class_getitem__ = classmethod(GenericAlias)
1088
1089
1090if name == 'nt':
1091    class _AddedDllDirectory:
1092        def __init__(self, path, cookie, remove_dll_directory):
1093            self.path = path
1094            self._cookie = cookie
1095            self._remove_dll_directory = remove_dll_directory
1096        def close(self):
1097            self._remove_dll_directory(self._cookie)
1098            self.path = None
1099        def __enter__(self):
1100            return self
1101        def __exit__(self, *args):
1102            self.close()
1103        def __repr__(self):
1104            if self.path:
1105                return "<AddedDllDirectory({!r})>".format(self.path)
1106            return "<AddedDllDirectory()>"
1107
1108    def add_dll_directory(path):
1109        """Add a path to the DLL search path.
1110
1111        This search path is used when resolving dependencies for imported
1112        extension modules (the module itself is resolved through sys.path),
1113        and also by ctypes.
1114
1115        Remove the directory by calling close() on the returned object or
1116        using it in a with statement.
1117        """
1118        import nt
1119        cookie = nt._add_dll_directory(path)
1120        return _AddedDllDirectory(
1121            path,
1122            cookie,
1123            nt._remove_dll_directory
1124        )
1125