summaryrefslogtreecommitdiff
path: root/Lib/pathlib.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/pathlib.py')
-rw-r--r--Lib/pathlib.py126
1 files changed, 124 insertions, 2 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 4fa872d620..caf685ee6b 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")