diff -r ae1ef62954f7 Lib/os.py --- a/Lib/os.py Mon Dec 10 10:10:40 2012 +0100 +++ b/Lib/os.py Thu Dec 13 07:19:04 2012 -0300 @@ -23,7 +23,8 @@ #' -import sys, errno +import sys +import errno import stat as st _names = sys.builtin_module_names @@ -34,9 +35,11 @@ "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen", "popen", "extsep"] + def _exists(name): return name in globals() + def _get_exports_list(module): try: return list(module.__all__) @@ -107,13 +110,14 @@ sys.modules['os.path'] = path from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, - devnull) + devnull) del _names if _exists("_have_functions"): _globals = globals() + def _add(str, fn): if (fn in _globals) and (str in _have_functions): _set.add(_globals[fn]) @@ -147,12 +151,12 @@ _add("HAVE_FCHOWN", "chown") _add("HAVE_FDOPENDIR", "listdir") _add("HAVE_FEXECVE", "execve") - _set.add(stat) # fstat always works + _set.add(stat) # fstat always works _add("HAVE_FTRUNCATE", "truncate") _add("HAVE_FUTIMENS", "utime") _add("HAVE_FUTIMES", "utime") _add("HAVE_FPATHCONF", "pathconf") - if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3 + if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3 _add("HAVE_FSTATVFS", "statvfs") supports_fd = _set @@ -183,7 +187,7 @@ _add("HAVE_FSTATAT", "stat") _add("HAVE_LCHFLAGS", "chflags") _add("HAVE_LCHMOD", "chmod") - if _exists("lchown"): # mac os x10.3 + if _exists("lchown"): # mac os x10.3 _add("HAVE_LCHOWN", "chown") _add("HAVE_LINKAT", "link") _add("HAVE_LUTIMES", "utime") @@ -215,6 +219,7 @@ # Super directory utilities. # (Inspired by Eric Raymond; the doc strings are mostly his) + def makedirs(name, mode=0o777, exist_ok=False): """makedirs(path [, mode=0o777][, exist_ok=False]) @@ -253,10 +258,11 @@ if not (e.errno == errno.EEXIST and exist_ok and dir_exists and actual_mode == expected_mode): if dir_exists and actual_mode != expected_mode: - e.strerror += ' (mode %o != expected mode %o)' % ( - actual_mode, expected_mode) + e.strerror += ' (mode %o != expected mode %o)' % (actual_mode, + expected_mode) raise + def removedirs(name): """removedirs(path) @@ -279,6 +285,7 @@ break head, tail = path.split(head) + def renames(old, new): """renames(old, new) @@ -307,6 +314,7 @@ __all__.extend(["makedirs", "removedirs", "renames"]) + def walk(top, topdown=True, onerror=None, followlinks=False): """Directory tree generator. @@ -400,7 +408,8 @@ if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd: - def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None): + def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, + dir_fd=None): """Directory tree generator. This behaves exactly like walk(), except that it yields a 4-tuple @@ -413,8 +422,9 @@ The advantage of fwalk() over walk() is that it's safe against symlink races (when follow_symlinks is False). - If dir_fd is not None, it should be a file descriptor open to a directory, - and top should be relative; top will then be relative to that directory. + If dir_fd is not None, it should be a file descriptor open to a + directory, and top should be relative; top will then be relative to + that directory. (dir_fd is always supported for fwalk.) Caution: @@ -427,8 +437,8 @@ import os for root, dirs, files, rootfd in os.fwalk('python/Lib/email'): print(root, "consumes", end="") - print(sum([os.stat(name, dir_fd=rootfd).st_size for name in files]), - end="") + print(sum([os.stat(name, dir_fd=rootfd).st_size + for name in files]),end="") print("bytes in", len(files), "non-directory files") if 'CVS' in dirs: dirs.remove('CVS') # don't visit CVS directories @@ -440,7 +450,8 @@ try: if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and path.samestat(orig_st, stat(topfd)))): - yield from _fwalk(topfd, top, topdown, onerror, follow_symlinks) + yield from _fwalk(topfd, top, topdown, onerror, + follow_symlinks) finally: close(topfd) @@ -464,8 +475,9 @@ except FileNotFoundError: try: # Add dangling symlinks, ignore disappeared files - if st.S_ISLNK(stat(name, dir_fd=topfd, follow_symlinks=False) - .st_mode): + if st.S_ISLNK(stat(name, dir_fd=topfd, + follow_symlinks=False) + .st_mode): nondirs.append(name) except FileNotFoundError: continue @@ -475,7 +487,8 @@ for name in dirs: try: - orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlinks) + orig_st = stat(name, dir_fd=topfd, + follow_symlinks=follow_symlinks) dirfd = open(name, O_RDONLY, dir_fd=topfd) except error as err: if onerror is not None: @@ -484,7 +497,8 @@ try: if follow_symlinks or path.samestat(orig_st, stat(dirfd)): dirpath = path.join(toppath, name) - yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_symlinks) + yield from _fwalk(dirfd, dirpath, topdown, onerror, + follow_symlinks) finally: close(dirfd) @@ -499,6 +513,7 @@ except NameError: environ = {} + def execl(file, *args): """execl(file, *args) @@ -506,6 +521,7 @@ current process. """ execv(file, args) + def execle(file, *args): """execle(file, *args, env) @@ -514,6 +530,7 @@ env = args[-1] execve(file, args[:-1], env) + def execlp(file, *args): """execlp(file, *args) @@ -521,6 +538,7 @@ with argument list args, replacing the current process. """ execvp(file, args) + def execlpe(file, *args): """execlpe(file, *args, env) @@ -530,6 +548,7 @@ env = args[-1] execvpe(file, args[:-1], env) + def execvp(file, args): """execvp(file, args) @@ -538,6 +557,7 @@ args may be a list or tuple of strings. """ _execvpe(file, args) + def execvpe(file, args, env): """execvpe(file, args, env) @@ -547,7 +567,8 @@ args may be a list or tuple of strings. """ _execvpe(file, args, env) -__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"]) +__all__.extend(["execl", "execle", "execlp", "execlpe", "execvp", "execvpe"]) + def _execvpe(file, args, env=None): if env is not None: @@ -576,7 +597,7 @@ last_exc = e tb = sys.exc_info()[2] if (e.errno != errno.ENOENT and e.errno != errno.ENOTDIR - and saved_exc is None): + and saved_exc is None): saved_exc = e saved_tb = tb if saved_exc: @@ -631,8 +652,10 @@ # Change environ to automatically call putenv(), unsetenv if they exist. from collections.abc import MutableMapping + class _Environ(MutableMapping): - def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, putenv, unsetenv): + def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, + putenv, unsetenv): self.encodekey = encodekey self.decodekey = decodekey self.encodevalue = encodevalue @@ -666,7 +689,7 @@ def __repr__(self): return 'environ({{{}}})'.format(', '.join( ('{!r}: {!r}'.format(self.decodekey(key), self.decodevalue(value)) - for key, value in self._data.items()))) + for key, value in self._data.items()))) def copy(self): return dict(self) @@ -690,15 +713,18 @@ else: __all__.append("unsetenv") + def _createenviron(): if name == 'nt': # Where Env Var Names Must Be UPPERCASE + def check_str(value): if not isinstance(value, str): raise TypeError("str expected, not %s" % type(value).__name__) return value encode = check_str decode = str + def encodekey(key): return encode(key).upper() data = {} @@ -707,18 +733,20 @@ else: # Where Env Var Names Can Be Mixed Case encoding = sys.getfilesystemencoding() + def encode(value): if not isinstance(value, str): raise TypeError("str expected, not %s" % type(value).__name__) return value.encode(encoding, 'surrogateescape') + def decode(value): return value.decode(encoding, 'surrogateescape') encodekey = encode data = environ return _Environ(data, - encodekey, decode, - encode, decode, - _putenv, _unsetenv) + encodekey, decode, + encode, decode, + _putenv, _unsetenv) # unicode environ environ = _createenviron() @@ -735,6 +763,7 @@ __all__.extend(("getenv", "supports_bytes_environ")) if supports_bytes_environ: + def _check_bytes(value): if not isinstance(value, bytes): raise TypeError("bytes expected, not %s" % type(value).__name__) @@ -742,9 +771,9 @@ # bytes environ environb = _Environ(environ._data, - _check_bytes, bytes, - _check_bytes, bytes, - _putenv, _unsetenv) + _check_bytes, bytes, + _check_bytes, bytes, + _putenv, _unsetenv) del _check_bytes def getenvb(key, default=None): @@ -755,6 +784,7 @@ __all__.extend(("environb", "getenvb")) + def _fscodec(): encoding = sys.getfilesystemencoding() if encoding == 'mbcs': @@ -765,28 +795,31 @@ def fsencode(filename): """ Encode filename to the filesystem encoding with 'surrogateescape' error - handler, return bytes unchanged. On Windows, use 'strict' error handler if - the file system encoding is 'mbcs' (which is the default encoding). + handler, return bytes unchanged. On Windows, use 'strict' error handler + if the file system encoding is 'mbcs' (which is the default encoding). """ if isinstance(filename, bytes): return filename elif isinstance(filename, str): return filename.encode(encoding, errors) else: - raise TypeError("expect bytes or str, not %s" % type(filename).__name__) + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) def fsdecode(filename): """ - Decode filename from the filesystem encoding with 'surrogateescape' error - handler, return str unchanged. On Windows, use 'strict' error handler if - the file system encoding is 'mbcs' (which is the default encoding). + Decode filename from the filesystem encoding with 'surrogateescape' + error handler, return str unchanged. On Windows, use 'strict' error + handler if the file system encoding is 'mbcs' (which is the default + encoding). """ if isinstance(filename, str): return filename elif isinstance(filename, bytes): return filename.decode(encoding, errors) else: - raise TypeError("expect bytes or str, not %s" % type(filename).__name__) + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) return fsencode, fsdecode @@ -820,7 +853,7 @@ else: # Parent if mode == P_NOWAIT: - return pid # Caller is responsible for waiting! + return pid # Caller is responsible for waiting! while 1: wpid, sts = waitpid(pid, 0) if WIFSTOPPED(sts): @@ -897,8 +930,7 @@ env = args[-1] return spawnve(mode, file, args[:-1], env) - - __all__.extend(["spawnv", "spawnve", "spawnl", "spawnle",]) + __all__.extend(["spawnv", "spawnve", "spawnl", "spawnle"]) if _exists("spawnvp"): @@ -925,36 +957,40 @@ env = args[-1] return spawnvpe(mode, file, args[:-1], env) - - __all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe",]) + __all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe"]) import copyreg as _copyreg + def _make_stat_result(tup, dict): return stat_result(tup, dict) + def _pickle_stat_result(sr): (type, args) = sr.__reduce__() return (_make_stat_result, args) try: _copyreg.pickle(stat_result, _pickle_stat_result, _make_stat_result) -except NameError: # stat_result may not exist +except NameError: # stat_result may not exist pass + def _make_statvfs_result(tup, dict): return statvfs_result(tup, dict) + def _pickle_statvfs_result(sr): (type, args) = sr.__reduce__() return (_make_statvfs_result, args) try: _copyreg.pickle(statvfs_result, _pickle_statvfs_result, - _make_statvfs_result) -except NameError: # statvfs_result may not exist + _make_statvfs_result) +except NameError: # statvfs_result may not exist pass + # Supply os.popen() def popen(cmd, mode="r", buffering=-1): if not isinstance(cmd, str): @@ -963,7 +999,8 @@ raise ValueError("invalid mode %r" % mode) if buffering == 0 or buffering is None: raise ValueError("popen() does not support unbuffered streams") - import subprocess, io + import subprocess + import io if mode == "r": proc = subprocess.Popen(cmd, shell=True, @@ -977,11 +1014,13 @@ bufsize=buffering) return _wrap_close(io.TextIOWrapper(proc.stdin), proc) + # Helper for popen() -- a proxy for a file whose close waits for the process class _wrap_close: def __init__(self, stream, proc): self._stream = stream self._proc = proc + def close(self): self._stream.close() returncode = self._proc.wait() @@ -991,15 +1030,20 @@ return returncode else: return returncode << 8 # Shift left to match old behavior + def __enter__(self): return self + def __exit__(self, *args): self.close() + def __getattr__(self, name): return getattr(self._stream, name) + def __iter__(self): return iter(self._stream) + # Supply os.fdopen() def fdopen(fd, *args, **kwargs): if not isinstance(fd, int):