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