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