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