diff options
Diffstat (limited to 'Lib/pathlib.py')
-rw-r--r-- | Lib/pathlib.py | 126 |
1 files changed, 124 insertions, 2 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 4fa872d..caf685e 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -225,6 +225,36 @@ class _WindowsFlavour(_Flavour): # It's a path on a network drive => 'file://host/share/a/b' return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8')) + def gethomedir(self, username): + if 'HOME' in os.environ: + userhome = os.environ['HOME'] + elif 'USERPROFILE' in os.environ: + userhome = os.environ['USERPROFILE'] + elif 'HOMEPATH' in os.environ: + try: + drv = os.environ['HOMEDRIVE'] + except KeyError: + drv = '' + userhome = drv + os.environ['HOMEPATH'] + else: + raise RuntimeError("Can't determine home directory") + + if username: + # Try to guess user home directory. By default all users + # directories are located in the same place and are named by + # corresponding usernames. If current user home directory points + # to nonstandard place, this guess is likely wrong. + if os.environ['USERNAME'] != username: + drv, root, parts = self.parse_parts((userhome,)) + if parts[-1] != os.environ['USERNAME']: + raise RuntimeError("Can't determine home directory " + "for %r" % username) + parts[-1] = username + if drv or root: + userhome = drv + root + self.join(parts[1:]) + else: + userhome = self.join(parts) + return userhome class _PosixFlavour(_Flavour): sep = '/' @@ -308,6 +338,21 @@ class _PosixFlavour(_Flavour): bpath = bytes(path) return 'file://' + urlquote_from_bytes(bpath) + def gethomedir(self, username): + if not username: + try: + return os.environ['HOME'] + except KeyError: + import pwd + return pwd.getpwuid(os.getuid()).pw_dir + else: + import pwd + try: + return pwd.getpwnam(username).pw_dir + except KeyError: + raise RuntimeError("Can't determine home directory " + "for %r" % username) + _windows_flavour = _WindowsFlavour() _posix_flavour = _PosixFlavour() @@ -977,6 +1022,24 @@ class Path(PurePath): """ return cls(os.getcwd()) + @classmethod + def home(cls): + """Return a new path pointing to the user's home directory (as + returned by os.path.expanduser('~')). + """ + return cls(cls()._flavour.gethomedir(None)) + + def samefile(self, other_path): + """Return whether other_path is the same or not as this file + (as returned by os.path.samefile()). + """ + st = self.stat() + try: + other_st = other_path.stat() + except AttributeError: + other_st = os.stat(other_path) + return os.path.samestat(st, other_st) + def iterdir(self): """Iterate over the files in this directory. Does not yield any result for the special paths '.' and '..'. @@ -995,6 +1058,8 @@ class Path(PurePath): """Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given pattern. """ + if not pattern: + raise ValueError("Unacceptable pattern: {!r}".format(pattern)) pattern = self._flavour.casefold(pattern) drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) if drv or root: @@ -1085,6 +1150,39 @@ class Path(PurePath): return io.open(str(self), mode, buffering, encoding, errors, newline, opener=self._opener) + def read_bytes(self): + """ + Open the file in bytes mode, read it, and close the file. + """ + with self.open(mode='rb') as f: + return f.read() + + def read_text(self, encoding=None, errors=None): + """ + Open the file in text mode, read it, and close the file. + """ + with self.open(mode='r', encoding=encoding, errors=errors) as f: + return f.read() + + def write_bytes(self, data): + """ + Open the file in bytes mode, write to it, and close the file. + """ + # type-check for the buffer interface before truncating the file + view = memoryview(data) + with self.open(mode='wb') as f: + return f.write(view) + + def write_text(self, data, encoding=None, errors=None): + """ + Open the file in text mode, write to it, and close the file. + """ + if not isinstance(data, str): + raise TypeError('data must be str, not %s' % + data.__class__.__name__) + with self.open(mode='w', encoding=encoding, errors=errors) as f: + return f.write(data) + def touch(self, mode=0o666, exist_ok=True): """ Create this file with the given access mode, if it doesn't exist. @@ -1108,14 +1206,21 @@ class Path(PurePath): fd = self._raw_open(flags, mode) os.close(fd) - def mkdir(self, mode=0o777, parents=False): + def mkdir(self, mode=0o777, parents=False, exist_ok=False): if self._closed: self._raise_closed() if not parents: - self._accessor.mkdir(self, mode) + try: + self._accessor.mkdir(self, mode) + except FileExistsError: + if not exist_ok or not self.is_dir(): + raise else: try: self._accessor.mkdir(self, mode) + except FileExistsError: + if not exist_ok or not self.is_dir(): + raise except OSError as e: if e.errno != ENOENT: raise @@ -1296,9 +1401,26 @@ class Path(PurePath): # (see https://bitbucket.org/pitrou/pathlib/issue/12/) return False + def expanduser(self): + """ Return a new path with expanded ~ and ~user constructs + (as returned by os.path.expanduser) + """ + if (not (self._drv or self._root) and + self._parts and self._parts[0][:1] == '~'): + homedir = self._flavour.gethomedir(self._parts[0][1:]) + return self._from_parts([homedir] + self._parts[1:]) + + return self + class PosixPath(Path, PurePosixPath): __slots__ = () class WindowsPath(Path, PureWindowsPath): __slots__ = () + + def owner(self): + raise NotImplementedError("Path.owner() is unsupported on this system") + + def group(self): + raise NotImplementedError("Path.group() is unsupported on this system") |