blob: 64f5f181ed99507a0f0f4256276ee1800acb4f5f [file] [log] [blame]
Antoine Pitrou31119e42013-11-22 17:38:12 +01001import fnmatch
2import functools
3import io
4import ntpath
5import os
6import posixpath
7import re
8import sys
Serhiy Storchaka81108372017-09-26 00:55:55 +03009from _collections_abc import Sequence
Jörg Stucked5c120f2019-05-21 19:44:40 +020010from errno import EINVAL, ENOENT, ENOTDIR, EBADF, ELOOP
Antoine Pitrou31119e42013-11-22 17:38:12 +010011from operator import attrgetter
12from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
Antoine Pitrou069a5e12013-12-03 09:41:35 +010013from urllib.parse import quote_from_bytes as urlquote_from_bytes
Antoine Pitrou31119e42013-11-22 17:38:12 +010014
15
Antoine Pitroudb118f52014-11-19 00:32:08 +010016if os.name == 'nt':
Barney Galeb57e0452021-04-07 00:01:22 +010017 from nt import _getfinalpathname
Antoine Pitroudb118f52014-11-19 00:32:08 +010018else:
Barney Galeb57e0452021-04-07 00:01:22 +010019 _getfinalpathname = None
Antoine Pitrou31119e42013-11-22 17:38:12 +010020
21
22__all__ = [
23 "PurePath", "PurePosixPath", "PureWindowsPath",
24 "Path", "PosixPath", "WindowsPath",
25 ]
26
27#
28# Internals
29#
30
penguindustin96466302019-05-06 14:57:17 -040031# EBADF - guard against macOS `stat` throwing EBADF
Jörg Stucked5c120f2019-05-21 19:44:40 +020032_IGNORED_ERROS = (ENOENT, ENOTDIR, EBADF, ELOOP)
Przemysław Spodymek216b7452018-08-27 23:33:45 +020033
Steve Dower2f6fae62019-02-03 23:08:18 -080034_IGNORED_WINERRORS = (
35 21, # ERROR_NOT_READY - drive exists but is not accessible
Jörg Stucked5c120f2019-05-21 19:44:40 +020036 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
Steve Dower2f6fae62019-02-03 23:08:18 -080037)
38
39def _ignore_error(exception):
40 return (getattr(exception, 'errno', None) in _IGNORED_ERROS or
41 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
42
43
Antoine Pitrou31119e42013-11-22 17:38:12 +010044def _is_wildcard_pattern(pat):
45 # Whether this pattern needs actual matching using fnmatch, or can
46 # be looked up directly as a file.
47 return "*" in pat or "?" in pat or "[" in pat
48
49
50class _Flavour(object):
51 """A flavour implements a particular (platform-specific) set of path
52 semantics."""
53
54 def __init__(self):
55 self.join = self.sep.join
56
57 def parse_parts(self, parts):
58 parsed = []
59 sep = self.sep
60 altsep = self.altsep
61 drv = root = ''
62 it = reversed(parts)
63 for part in it:
64 if not part:
65 continue
66 if altsep:
67 part = part.replace(altsep, sep)
68 drv, root, rel = self.splitroot(part)
69 if sep in rel:
70 for x in reversed(rel.split(sep)):
71 if x and x != '.':
72 parsed.append(sys.intern(x))
73 else:
74 if rel and rel != '.':
75 parsed.append(sys.intern(rel))
76 if drv or root:
77 if not drv:
78 # If no drive is present, try to find one in the previous
79 # parts. This makes the result of parsing e.g.
80 # ("C:", "/", "a") reasonably intuitive.
81 for part in it:
Antoine Pitrou57fffd62015-02-15 18:03:59 +010082 if not part:
83 continue
84 if altsep:
85 part = part.replace(altsep, sep)
Antoine Pitrou31119e42013-11-22 17:38:12 +010086 drv = self.splitroot(part)[0]
87 if drv:
88 break
89 break
90 if drv or root:
91 parsed.append(drv + root)
92 parsed.reverse()
93 return drv, root, parsed
94
95 def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
96 """
97 Join the two paths represented by the respective
98 (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
99 """
100 if root2:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200101 if not drv2 and drv:
102 return drv, root2, [drv + root2] + parts2[1:]
103 elif drv2:
104 if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
105 # Same drive => second path is relative to the first
106 return drv, root, parts + parts2[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100107 else:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200108 # Second path is non-anchored (common case)
109 return drv, root, parts + parts2
110 return drv2, root2, parts2
Antoine Pitrou31119e42013-11-22 17:38:12 +0100111
112
113class _WindowsFlavour(_Flavour):
114 # Reference for Windows paths can be found at
115 # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
116
117 sep = '\\'
118 altsep = '/'
119 has_drv = True
120 pathmod = ntpath
121
Antoine Pitroudb118f52014-11-19 00:32:08 +0100122 is_supported = (os.name == 'nt')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100123
Jon Dufresne39726282017-05-18 07:35:54 -0700124 drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100125 ext_namespace_prefix = '\\\\?\\'
126
127 reserved_names = (
128 {'CON', 'PRN', 'AUX', 'NUL'} |
129 {'COM%d' % i for i in range(1, 10)} |
130 {'LPT%d' % i for i in range(1, 10)}
131 )
132
133 # Interesting findings about extended paths:
134 # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
135 # but '\\?\c:/a' is not
136 # - extended paths are always absolute; "relative" extended paths will
137 # fail.
138
139 def splitroot(self, part, sep=sep):
140 first = part[0:1]
141 second = part[1:2]
142 if (second == sep and first == sep):
143 # XXX extended paths should also disable the collapsing of "."
144 # components (according to MSDN docs).
145 prefix, part = self._split_extended_path(part)
146 first = part[0:1]
147 second = part[1:2]
148 else:
149 prefix = ''
150 third = part[2:3]
151 if (second == sep and first == sep and third != sep):
152 # is a UNC path:
153 # vvvvvvvvvvvvvvvvvvvvv root
154 # \\machine\mountpoint\directory\etc\...
155 # directory ^^^^^^^^^^^^^^
156 index = part.find(sep, 2)
157 if index != -1:
158 index2 = part.find(sep, index + 1)
159 # a UNC path can't have two slashes in a row
160 # (after the initial two)
161 if index2 != index + 1:
162 if index2 == -1:
163 index2 = len(part)
164 if prefix:
165 return prefix + part[1:index2], sep, part[index2+1:]
166 else:
167 return part[:index2], sep, part[index2+1:]
168 drv = root = ''
169 if second == ':' and first in self.drive_letters:
170 drv = part[:2]
171 part = part[2:]
172 first = third
173 if first == sep:
174 root = first
175 part = part.lstrip(sep)
176 return prefix + drv, root, part
177
178 def casefold(self, s):
179 return s.lower()
180
181 def casefold_parts(self, parts):
182 return [p.lower() for p in parts]
183
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300184 def compile_pattern(self, pattern):
185 return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
186
Steve Dower98eb3602016-11-09 12:58:17 -0800187 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100188 s = str(path)
189 if not s:
190 return os.getcwd()
Steve Dower98eb3602016-11-09 12:58:17 -0800191 previous_s = None
Antoine Pitrou31119e42013-11-22 17:38:12 +0100192 if _getfinalpathname is not None:
Steve Dower98eb3602016-11-09 12:58:17 -0800193 if strict:
194 return self._ext_to_normal(_getfinalpathname(s))
195 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200196 tail_parts = [] # End of the path after the first one not found
Steve Dower98eb3602016-11-09 12:58:17 -0800197 while True:
198 try:
199 s = self._ext_to_normal(_getfinalpathname(s))
200 except FileNotFoundError:
201 previous_s = s
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200202 s, tail = os.path.split(s)
203 tail_parts.append(tail)
Steve Dower4b1e98b2016-12-28 16:02:59 -0800204 if previous_s == s:
205 return path
Steve Dower98eb3602016-11-09 12:58:17 -0800206 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200207 return os.path.join(s, *reversed(tail_parts))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100208 # Means fallback on absolute
209 return None
210
211 def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
212 prefix = ''
213 if s.startswith(ext_prefix):
214 prefix = s[:4]
215 s = s[4:]
216 if s.startswith('UNC\\'):
217 prefix += s[:3]
218 s = '\\' + s[3:]
219 return prefix, s
220
221 def _ext_to_normal(self, s):
222 # Turn back an extended path into a normal DOS-like path
223 return self._split_extended_path(s)[1]
224
225 def is_reserved(self, parts):
226 # NOTE: the rules for reserved names seem somewhat complicated
227 # (e.g. r"..\NUL" is reserved but not r"foo\NUL").
228 # We err on the side of caution and return True for paths which are
229 # not considered reserved by Windows.
230 if not parts:
231 return False
232 if parts[0].startswith('\\\\'):
233 # UNC paths are never reserved
234 return False
235 return parts[-1].partition('.')[0].upper() in self.reserved_names
236
237 def make_uri(self, path):
238 # Under Windows, file URIs use the UTF-8 encoding.
239 drive = path.drive
240 if len(drive) == 2 and drive[1] == ':':
241 # It's a path on a local drive => 'file:///c:/a/b'
242 rest = path.as_posix()[2:].lstrip('/')
243 return 'file:///%s/%s' % (
244 drive, urlquote_from_bytes(rest.encode('utf-8')))
245 else:
246 # It's a path on a network drive => 'file://host/share/a/b'
247 return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
248
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100249 def gethomedir(self, username):
Christoph Reiterc45a2aa2020-01-28 10:41:50 +0100250 if 'USERPROFILE' in os.environ:
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100251 userhome = os.environ['USERPROFILE']
252 elif 'HOMEPATH' in os.environ:
Antoine Pitrou5d4e27e2014-12-30 22:09:42 +0100253 try:
254 drv = os.environ['HOMEDRIVE']
255 except KeyError:
256 drv = ''
257 userhome = drv + os.environ['HOMEPATH']
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100258 else:
259 raise RuntimeError("Can't determine home directory")
260
261 if username:
262 # Try to guess user home directory. By default all users
263 # directories are located in the same place and are named by
264 # corresponding usernames. If current user home directory points
265 # to nonstandard place, this guess is likely wrong.
266 if os.environ['USERNAME'] != username:
267 drv, root, parts = self.parse_parts((userhome,))
268 if parts[-1] != os.environ['USERNAME']:
269 raise RuntimeError("Can't determine home directory "
270 "for %r" % username)
271 parts[-1] = username
272 if drv or root:
273 userhome = drv + root + self.join(parts[1:])
274 else:
275 userhome = self.join(parts)
276 return userhome
Antoine Pitrou31119e42013-11-22 17:38:12 +0100277
278class _PosixFlavour(_Flavour):
279 sep = '/'
280 altsep = ''
281 has_drv = False
282 pathmod = posixpath
283
284 is_supported = (os.name != 'nt')
285
286 def splitroot(self, part, sep=sep):
287 if part and part[0] == sep:
288 stripped_part = part.lstrip(sep)
289 # According to POSIX path resolution:
290 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
291 # "A pathname that begins with two successive slashes may be
292 # interpreted in an implementation-defined manner, although more
293 # than two leading slashes shall be treated as a single slash".
294 if len(part) - len(stripped_part) == 2:
295 return '', sep * 2, stripped_part
296 else:
297 return '', sep, stripped_part
298 else:
299 return '', '', part
300
301 def casefold(self, s):
302 return s
303
304 def casefold_parts(self, parts):
305 return parts
306
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300307 def compile_pattern(self, pattern):
308 return re.compile(fnmatch.translate(pattern)).fullmatch
309
Steve Dower98eb3602016-11-09 12:58:17 -0800310 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100311 sep = self.sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100312 accessor = path._accessor
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100313 seen = {}
314 def _resolve(path, rest):
315 if rest.startswith(sep):
316 path = ''
317
318 for name in rest.split(sep):
319 if not name or name == '.':
320 # current dir
321 continue
322 if name == '..':
323 # parent dir
324 path, _, _ = path.rpartition(sep)
325 continue
Dong-hee Na94ad6c62018-06-12 23:30:45 +0900326 if path.endswith(sep):
327 newpath = path + name
328 else:
329 newpath = path + sep + name
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100330 if newpath in seen:
331 # Already seen this path
332 path = seen[newpath]
333 if path is not None:
334 # use cached value
335 continue
336 # The symlink is not resolved, so we must have a symlink loop.
337 raise RuntimeError("Symlink loop from %r" % newpath)
338 # Resolve the symbolic link
339 try:
340 target = accessor.readlink(newpath)
341 except OSError as e:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200342 if e.errno != EINVAL and strict:
343 raise
344 # Not a symlink, or non-strict mode. We just leave the path
345 # untouched.
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100346 path = newpath
347 else:
348 seen[newpath] = None # not resolved symlink
349 path = _resolve(path, target)
350 seen[newpath] = path # resolved symlink
351
352 return path
353 # NOTE: according to POSIX, getcwd() cannot contain path components
354 # which are symlinks.
355 base = '' if path.is_absolute() else os.getcwd()
356 return _resolve(base, str(path)) or sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100357
358 def is_reserved(self, parts):
359 return False
360
361 def make_uri(self, path):
362 # We represent the path using the local filesystem encoding,
363 # for portability to other applications.
364 bpath = bytes(path)
365 return 'file://' + urlquote_from_bytes(bpath)
366
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100367 def gethomedir(self, username):
368 if not username:
369 try:
370 return os.environ['HOME']
371 except KeyError:
372 import pwd
373 return pwd.getpwuid(os.getuid()).pw_dir
374 else:
375 import pwd
376 try:
377 return pwd.getpwnam(username).pw_dir
378 except KeyError:
379 raise RuntimeError("Can't determine home directory "
380 "for %r" % username)
381
Antoine Pitrou31119e42013-11-22 17:38:12 +0100382
383_windows_flavour = _WindowsFlavour()
384_posix_flavour = _PosixFlavour()
385
386
387class _Accessor:
388 """An accessor implements a particular (system-specific or not) way of
389 accessing paths on the filesystem."""
390
391
392class _NormalAccessor(_Accessor):
393
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200394 stat = os.stat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100395
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200396 lstat = os.lstat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100397
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200398 open = os.open
Antoine Pitrou31119e42013-11-22 17:38:12 +0100399
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200400 listdir = os.listdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100401
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200402 scandir = os.scandir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100403
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200404 chmod = os.chmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100405
406 if hasattr(os, "lchmod"):
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200407 lchmod = os.lchmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100408 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100409 def lchmod(self, path, mode):
410 raise NotImplementedError("os.lchmod() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100411
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200412 mkdir = os.mkdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100413
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200414 unlink = os.unlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100415
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100416 if hasattr(os, "link"):
Barney Galeb57e0452021-04-07 00:01:22 +0100417 link = os.link
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100418 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100419 def link(self, src, dst):
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100420 raise NotImplementedError("os.link() not available on this system")
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -0400421
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200422 rmdir = os.rmdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100423
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200424 rename = os.rename
Antoine Pitrou31119e42013-11-22 17:38:12 +0100425
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200426 replace = os.replace
Antoine Pitrou31119e42013-11-22 17:38:12 +0100427
Barney Galeb57e0452021-04-07 00:01:22 +0100428 if hasattr(os, "symlink"):
429 symlink = os.symlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100430 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100431 def symlink(self, src, dst, target_is_directory=False):
432 raise NotImplementedError("os.symlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100433
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200434 utime = os.utime
Antoine Pitrou31119e42013-11-22 17:38:12 +0100435
Barney Galeb57e0452021-04-07 00:01:22 +0100436 if hasattr(os, "readlink"):
437 readlink = os.readlink
438 else:
439 def readlink(self, path):
440 raise NotImplementedError("os.readlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100441
Barney Gale22386bb2020-04-17 17:41:07 +0100442 def owner(self, path):
443 try:
444 import pwd
445 return pwd.getpwuid(self.stat(path).st_uid).pw_name
446 except ImportError:
447 raise NotImplementedError("Path.owner() is unsupported on this system")
448
449 def group(self, path):
450 try:
451 import grp
452 return grp.getgrgid(self.stat(path).st_gid).gr_name
453 except ImportError:
454 raise NotImplementedError("Path.group() is unsupported on this system")
455
Antoine Pitrou31119e42013-11-22 17:38:12 +0100456
457_normal_accessor = _NormalAccessor()
458
459
460#
461# Globbing helpers
462#
463
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300464def _make_selector(pattern_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100465 pat = pattern_parts[0]
466 child_parts = pattern_parts[1:]
467 if pat == '**':
468 cls = _RecursiveWildcardSelector
469 elif '**' in pat:
470 raise ValueError("Invalid pattern: '**' can only be an entire path component")
471 elif _is_wildcard_pattern(pat):
472 cls = _WildcardSelector
473 else:
474 cls = _PreciseSelector
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300475 return cls(pat, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100476
477if hasattr(functools, "lru_cache"):
478 _make_selector = functools.lru_cache()(_make_selector)
479
480
481class _Selector:
482 """A selector matches a specific glob pattern part against the children
483 of a given path."""
484
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300485 def __init__(self, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100486 self.child_parts = child_parts
487 if child_parts:
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300488 self.successor = _make_selector(child_parts, flavour)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300489 self.dironly = True
Antoine Pitrou31119e42013-11-22 17:38:12 +0100490 else:
491 self.successor = _TerminatingSelector()
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300492 self.dironly = False
Antoine Pitrou31119e42013-11-22 17:38:12 +0100493
494 def select_from(self, parent_path):
495 """Iterate over all child paths of `parent_path` matched by this
496 selector. This can contain parent_path itself."""
497 path_cls = type(parent_path)
498 is_dir = path_cls.is_dir
499 exists = path_cls.exists
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300500 scandir = parent_path._accessor.scandir
501 if not is_dir(parent_path):
502 return iter([])
503 return self._select_from(parent_path, is_dir, exists, scandir)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100504
505
506class _TerminatingSelector:
507
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300508 def _select_from(self, parent_path, is_dir, exists, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100509 yield parent_path
510
511
512class _PreciseSelector(_Selector):
513
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300514 def __init__(self, name, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100515 self.name = name
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300516 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100517
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300518 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800519 try:
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800520 path = parent_path._make_child_relpath(self.name)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300521 if (is_dir if self.dironly else exists)(path):
522 for p in self.successor._select_from(path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800523 yield p
524 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100525 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100526
527
528class _WildcardSelector(_Selector):
529
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300530 def __init__(self, pat, child_parts, flavour):
531 self.match = flavour.compile_pattern(pat)
532 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100533
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300534 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800535 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200536 with scandir(parent_path) as scandir_it:
537 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300538 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000539 if self.dironly:
540 try:
541 # "entry.is_dir()" can raise PermissionError
542 # in some cases (see bpo-38894), which is not
543 # among the errors ignored by _ignore_error()
544 if not entry.is_dir():
545 continue
546 except OSError as e:
547 if not _ignore_error(e):
548 raise
549 continue
550 name = entry.name
551 if self.match(name):
552 path = parent_path._make_child_relpath(name)
553 for p in self.successor._select_from(path, is_dir, exists, scandir):
554 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800555 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100556 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800557
Antoine Pitrou31119e42013-11-22 17:38:12 +0100558
Antoine Pitrou31119e42013-11-22 17:38:12 +0100559class _RecursiveWildcardSelector(_Selector):
560
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300561 def __init__(self, pat, child_parts, flavour):
562 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100563
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300564 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100565 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800566 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200567 with scandir(parent_path) as scandir_it:
568 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300569 for entry in entries:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200570 entry_is_dir = False
571 try:
572 entry_is_dir = entry.is_dir()
573 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800574 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200575 raise
576 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300577 path = parent_path._make_child_relpath(entry.name)
578 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800579 yield p
580 except PermissionError:
581 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100582
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300583 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800584 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300585 yielded = set()
586 try:
587 successor_select = self.successor._select_from
588 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
589 for p in successor_select(starting_point, is_dir, exists, scandir):
590 if p not in yielded:
591 yield p
592 yielded.add(p)
593 finally:
594 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800595 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100596 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100597
598
599#
600# Public API
601#
602
603class _PathParents(Sequence):
604 """This object provides sequence-like access to the logical ancestors
605 of a path. Don't try to construct it yourself."""
606 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
607
608 def __init__(self, path):
609 # We don't store the instance to avoid reference cycles
610 self._pathcls = type(path)
611 self._drv = path._drv
612 self._root = path._root
613 self._parts = path._parts
614
615 def __len__(self):
616 if self._drv or self._root:
617 return len(self._parts) - 1
618 else:
619 return len(self._parts)
620
621 def __getitem__(self, idx):
Joshua Cannon45205842020-11-20 09:40:39 -0600622 if isinstance(idx, slice):
623 return tuple(self[i] for i in range(*idx.indices(len(self))))
Yaroslav Pankovych79d2e622020-11-23 22:06:22 +0200624
625 if idx >= len(self) or idx < -len(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100626 raise IndexError(idx)
627 return self._pathcls._from_parsed_parts(self._drv, self._root,
628 self._parts[:-idx - 1])
629
630 def __repr__(self):
631 return "<{}.parents>".format(self._pathcls.__name__)
632
633
634class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900635 """Base class for manipulating paths without I/O.
636
637 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100638 don't imply any actual filesystem I/O. Depending on your system,
639 instantiating a PurePath will return either a PurePosixPath or a
640 PureWindowsPath object. You can also instantiate either of these classes
641 directly, regardless of your system.
642 """
643 __slots__ = (
644 '_drv', '_root', '_parts',
645 '_str', '_hash', '_pparts', '_cached_cparts',
646 )
647
648 def __new__(cls, *args):
649 """Construct a PurePath from one or several strings and or existing
650 PurePath objects. The strings and path objects are combined so as
651 to yield a canonicalized path, which is incorporated into the
652 new PurePath object.
653 """
654 if cls is PurePath:
655 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
656 return cls._from_parts(args)
657
658 def __reduce__(self):
659 # Using the parts tuple helps share interned path parts
660 # when pickling related paths.
661 return (self.__class__, tuple(self._parts))
662
663 @classmethod
664 def _parse_args(cls, args):
665 # This is useful when you don't want to create an instance, just
666 # canonicalize some constructor arguments.
667 parts = []
668 for a in args:
669 if isinstance(a, PurePath):
670 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100671 else:
Brett Cannon568be632016-06-10 12:20:49 -0700672 a = os.fspath(a)
673 if isinstance(a, str):
674 # Force-cast str subclasses to str (issue #21127)
675 parts.append(str(a))
676 else:
677 raise TypeError(
678 "argument should be a str object or an os.PathLike "
679 "object returning str, not %r"
680 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100681 return cls._flavour.parse_parts(parts)
682
683 @classmethod
684 def _from_parts(cls, args, init=True):
685 # We need to call _parse_args on the instance, so as to get the
686 # right flavour.
687 self = object.__new__(cls)
688 drv, root, parts = self._parse_args(args)
689 self._drv = drv
690 self._root = root
691 self._parts = parts
692 if init:
693 self._init()
694 return self
695
696 @classmethod
697 def _from_parsed_parts(cls, drv, root, parts, init=True):
698 self = object.__new__(cls)
699 self._drv = drv
700 self._root = root
701 self._parts = parts
702 if init:
703 self._init()
704 return self
705
706 @classmethod
707 def _format_parsed_parts(cls, drv, root, parts):
708 if drv or root:
709 return drv + root + cls._flavour.join(parts[1:])
710 else:
711 return cls._flavour.join(parts)
712
713 def _init(self):
Martin Pantere26da7c2016-06-02 10:07:09 +0000714 # Overridden in concrete Path
Antoine Pitrou31119e42013-11-22 17:38:12 +0100715 pass
716
717 def _make_child(self, args):
718 drv, root, parts = self._parse_args(args)
719 drv, root, parts = self._flavour.join_parsed_parts(
720 self._drv, self._root, self._parts, drv, root, parts)
721 return self._from_parsed_parts(drv, root, parts)
722
723 def __str__(self):
724 """Return the string representation of the path, suitable for
725 passing to system calls."""
726 try:
727 return self._str
728 except AttributeError:
729 self._str = self._format_parsed_parts(self._drv, self._root,
730 self._parts) or '.'
731 return self._str
732
Brett Cannon568be632016-06-10 12:20:49 -0700733 def __fspath__(self):
734 return str(self)
735
Antoine Pitrou31119e42013-11-22 17:38:12 +0100736 def as_posix(self):
737 """Return the string representation of the path with forward (/)
738 slashes."""
739 f = self._flavour
740 return str(self).replace(f.sep, '/')
741
742 def __bytes__(self):
743 """Return the bytes representation of the path. This is only
744 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200745 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100746
747 def __repr__(self):
748 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
749
750 def as_uri(self):
751 """Return the path as a 'file' URI."""
752 if not self.is_absolute():
753 raise ValueError("relative path can't be expressed as a file URI")
754 return self._flavour.make_uri(self)
755
756 @property
757 def _cparts(self):
758 # Cached casefolded parts, for hashing and comparison
759 try:
760 return self._cached_cparts
761 except AttributeError:
762 self._cached_cparts = self._flavour.casefold_parts(self._parts)
763 return self._cached_cparts
764
765 def __eq__(self, other):
766 if not isinstance(other, PurePath):
767 return NotImplemented
768 return self._cparts == other._cparts and self._flavour is other._flavour
769
Antoine Pitrou31119e42013-11-22 17:38:12 +0100770 def __hash__(self):
771 try:
772 return self._hash
773 except AttributeError:
774 self._hash = hash(tuple(self._cparts))
775 return self._hash
776
777 def __lt__(self, other):
778 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
779 return NotImplemented
780 return self._cparts < other._cparts
781
782 def __le__(self, other):
783 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
784 return NotImplemented
785 return self._cparts <= other._cparts
786
787 def __gt__(self, other):
788 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
789 return NotImplemented
790 return self._cparts > other._cparts
791
792 def __ge__(self, other):
793 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
794 return NotImplemented
795 return self._cparts >= other._cparts
796
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300797 def __class_getitem__(cls, type):
798 return cls
799
Antoine Pitrou31119e42013-11-22 17:38:12 +0100800 drive = property(attrgetter('_drv'),
801 doc="""The drive prefix (letter or UNC path), if any.""")
802
803 root = property(attrgetter('_root'),
804 doc="""The root of the path, if any.""")
805
806 @property
807 def anchor(self):
808 """The concatenation of the drive and root, or ''."""
809 anchor = self._drv + self._root
810 return anchor
811
812 @property
813 def name(self):
814 """The final path component, if any."""
815 parts = self._parts
816 if len(parts) == (1 if (self._drv or self._root) else 0):
817 return ''
818 return parts[-1]
819
820 @property
821 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200822 """
823 The final component's last suffix, if any.
824
825 This includes the leading period. For example: '.txt'
826 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100827 name = self.name
828 i = name.rfind('.')
829 if 0 < i < len(name) - 1:
830 return name[i:]
831 else:
832 return ''
833
834 @property
835 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200836 """
837 A list of the final component's suffixes, if any.
838
839 These include the leading periods. For example: ['.tar', '.gz']
840 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100841 name = self.name
842 if name.endswith('.'):
843 return []
844 name = name.lstrip('.')
845 return ['.' + suffix for suffix in name.split('.')[1:]]
846
847 @property
848 def stem(self):
849 """The final path component, minus its last suffix."""
850 name = self.name
851 i = name.rfind('.')
852 if 0 < i < len(name) - 1:
853 return name[:i]
854 else:
855 return name
856
857 def with_name(self, name):
858 """Return a new path with the file name changed."""
859 if not self.name:
860 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400861 drv, root, parts = self._flavour.parse_parts((name,))
862 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
863 or drv or root or len(parts) != 1):
864 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100865 return self._from_parsed_parts(self._drv, self._root,
866 self._parts[:-1] + [name])
867
Tim Hoffmann8aea4b32020-04-19 17:29:49 +0200868 def with_stem(self, stem):
869 """Return a new path with the stem changed."""
870 return self.with_name(stem + self.suffix)
871
Antoine Pitrou31119e42013-11-22 17:38:12 +0100872 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200873 """Return a new path with the file suffix changed. If the path
874 has no suffix, add given suffix. If the given suffix is an empty
875 string, remove the suffix from the path.
876 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400877 f = self._flavour
878 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300879 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400880 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100881 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100882 name = self.name
883 if not name:
884 raise ValueError("%r has an empty name" % (self,))
885 old_suffix = self.suffix
886 if not old_suffix:
887 name = name + suffix
888 else:
889 name = name[:-len(old_suffix)] + suffix
890 return self._from_parsed_parts(self._drv, self._root,
891 self._parts[:-1] + [name])
892
893 def relative_to(self, *other):
894 """Return the relative path to another path identified by the passed
895 arguments. If the operation is not possible (because this is not
896 a subpath of the other path), raise ValueError.
897 """
898 # For the purpose of this method, drive and root are considered
899 # separate parts, i.e.:
900 # Path('c:/').relative_to('c:') gives Path('/')
901 # Path('c:/').relative_to('/') raise ValueError
902 if not other:
903 raise TypeError("need at least one argument")
904 parts = self._parts
905 drv = self._drv
906 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100907 if root:
908 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100909 else:
910 abs_parts = parts
911 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100912 if to_root:
913 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100914 else:
915 to_abs_parts = to_parts
916 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100917 cf = self._flavour.casefold_parts
918 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100919 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
Rotuna44832532020-05-25 21:42:28 +0200920 raise ValueError("{!r} is not in the subpath of {!r}"
921 " OR one path is relative and the other is absolute."
Antoine Pitrou31119e42013-11-22 17:38:12 +0100922 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100923 return self._from_parsed_parts('', root if n == 1 else '',
924 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100925
Hai Shi82642a02019-08-13 14:54:02 -0500926 def is_relative_to(self, *other):
927 """Return True if the path is relative to another path or False.
928 """
929 try:
930 self.relative_to(*other)
931 return True
932 except ValueError:
933 return False
934
Antoine Pitrou31119e42013-11-22 17:38:12 +0100935 @property
936 def parts(self):
937 """An object providing sequence-like access to the
938 components in the filesystem path."""
939 # We cache the tuple to avoid building a new one each time .parts
940 # is accessed. XXX is this necessary?
941 try:
942 return self._pparts
943 except AttributeError:
944 self._pparts = tuple(self._parts)
945 return self._pparts
946
947 def joinpath(self, *args):
948 """Combine this path with one or several arguments, and return a
949 new path representing either a subpath (if all arguments are relative
950 paths) or a totally different path (if one of the arguments is
951 anchored).
952 """
953 return self._make_child(args)
954
955 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400956 try:
957 return self._make_child((key,))
958 except TypeError:
959 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100960
961 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400962 try:
963 return self._from_parts([key] + self._parts)
964 except TypeError:
965 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100966
967 @property
968 def parent(self):
969 """The logical parent of the path."""
970 drv = self._drv
971 root = self._root
972 parts = self._parts
973 if len(parts) == 1 and (drv or root):
974 return self
975 return self._from_parsed_parts(drv, root, parts[:-1])
976
977 @property
978 def parents(self):
979 """A sequence of this path's logical parents."""
980 return _PathParents(self)
981
982 def is_absolute(self):
983 """True if the path is absolute (has both a root and, if applicable,
984 a drive)."""
985 if not self._root:
986 return False
987 return not self._flavour.has_drv or bool(self._drv)
988
989 def is_reserved(self):
990 """Return True if the path contains one of the special names reserved
991 by the system, if any."""
992 return self._flavour.is_reserved(self._parts)
993
994 def match(self, path_pattern):
995 """
996 Return True if this path matches the given pattern.
997 """
998 cf = self._flavour.casefold
999 path_pattern = cf(path_pattern)
1000 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
1001 if not pat_parts:
1002 raise ValueError("empty pattern")
1003 if drv and drv != cf(self._drv):
1004 return False
1005 if root and root != cf(self._root):
1006 return False
1007 parts = self._cparts
1008 if drv or root:
1009 if len(pat_parts) != len(parts):
1010 return False
1011 pat_parts = pat_parts[1:]
1012 elif len(pat_parts) > len(parts):
1013 return False
1014 for part, pat in zip(reversed(parts), reversed(pat_parts)):
1015 if not fnmatch.fnmatchcase(part, pat):
1016 return False
1017 return True
1018
Brett Cannon568be632016-06-10 12:20:49 -07001019# Can't subclass os.PathLike from PurePath and keep the constructor
1020# optimizations in PurePath._parse_args().
1021os.PathLike.register(PurePath)
1022
Antoine Pitrou31119e42013-11-22 17:38:12 +01001023
1024class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001025 """PurePath subclass for non-Windows systems.
1026
1027 On a POSIX system, instantiating a PurePath should return this object.
1028 However, you can also instantiate it directly on any system.
1029 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001030 _flavour = _posix_flavour
1031 __slots__ = ()
1032
1033
1034class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001035 """PurePath subclass for Windows systems.
1036
1037 On a Windows system, instantiating a PurePath should return this object.
1038 However, you can also instantiate it directly on any system.
1039 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001040 _flavour = _windows_flavour
1041 __slots__ = ()
1042
1043
1044# Filesystem-accessing classes
1045
1046
1047class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001048 """PurePath subclass that can make system calls.
1049
1050 Path represents a filesystem path but unlike PurePath, also offers
1051 methods to do system calls on path objects. Depending on your system,
1052 instantiating a Path will return either a PosixPath or a WindowsPath
1053 object. You can also instantiate a PosixPath or WindowsPath directly,
1054 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1055 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001056 __slots__ = (
1057 '_accessor',
Antoine Pitrou31119e42013-11-22 17:38:12 +01001058 )
1059
1060 def __new__(cls, *args, **kwargs):
1061 if cls is Path:
1062 cls = WindowsPath if os.name == 'nt' else PosixPath
1063 self = cls._from_parts(args, init=False)
1064 if not self._flavour.is_supported:
1065 raise NotImplementedError("cannot instantiate %r on your system"
1066 % (cls.__name__,))
1067 self._init()
1068 return self
1069
1070 def _init(self,
1071 # Private non-constructor arguments
1072 template=None,
1073 ):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001074 if template is not None:
1075 self._accessor = template._accessor
1076 else:
1077 self._accessor = _normal_accessor
1078
1079 def _make_child_relpath(self, part):
1080 # This is an optimization used for dir walking. `part` must be
1081 # a single part relative to this path.
1082 parts = self._parts + [part]
1083 return self._from_parsed_parts(self._drv, self._root, parts)
1084
1085 def __enter__(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001086 return self
1087
1088 def __exit__(self, t, v, tb):
Barney Gale00002e62020-04-01 15:10:51 +01001089 # https://bugs.python.org/issue39682
1090 # In previous versions of pathlib, this method marked this path as
1091 # closed; subsequent attempts to perform I/O would raise an IOError.
1092 # This functionality was never documented, and had the effect of
1093 # making Path objects mutable, contrary to PEP 428. In Python 3.9 the
1094 # _closed attribute was removed, and this method made a no-op.
1095 # This method and __enter__()/__exit__() should be deprecated and
1096 # removed in the future.
1097 pass
Antoine Pitrou31119e42013-11-22 17:38:12 +01001098
1099 def _opener(self, name, flags, mode=0o666):
1100 # A stub for the opener argument to built-in open()
1101 return self._accessor.open(self, flags, mode)
1102
Antoine Pitrou4a60d422013-12-02 21:25:18 +01001103 def _raw_open(self, flags, mode=0o777):
1104 """
1105 Open the file pointed by this path and return a file descriptor,
1106 as os.open() does.
1107 """
Antoine Pitrou4a60d422013-12-02 21:25:18 +01001108 return self._accessor.open(self, flags, mode)
1109
Antoine Pitrou31119e42013-11-22 17:38:12 +01001110 # Public API
1111
1112 @classmethod
1113 def cwd(cls):
1114 """Return a new path pointing to the current working directory
1115 (as returned by os.getcwd()).
1116 """
1117 return cls(os.getcwd())
1118
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001119 @classmethod
1120 def home(cls):
1121 """Return a new path pointing to the user's home directory (as
1122 returned by os.path.expanduser('~')).
1123 """
1124 return cls(cls()._flavour.gethomedir(None))
1125
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001126 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001127 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001128 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001129 """
1130 st = self.stat()
1131 try:
1132 other_st = other_path.stat()
1133 except AttributeError:
Barney Gale5b1d9182020-04-17 18:47:27 +01001134 other_st = self._accessor.stat(other_path)
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001135 return os.path.samestat(st, other_st)
1136
Antoine Pitrou31119e42013-11-22 17:38:12 +01001137 def iterdir(self):
1138 """Iterate over the files in this directory. Does not yield any
1139 result for the special paths '.' and '..'.
1140 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001141 for name in self._accessor.listdir(self):
1142 if name in {'.', '..'}:
1143 # Yielding a path object for these makes little sense
1144 continue
1145 yield self._make_child_relpath(name)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001146
1147 def glob(self, pattern):
1148 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001149 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001150 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001151 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001152 if not pattern:
1153 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001154 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1155 if drv or root:
1156 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001157 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001158 for p in selector.select_from(self):
1159 yield p
1160
1161 def rglob(self, pattern):
1162 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001163 directories) matching the given relative pattern, anywhere in
1164 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001165 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001166 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001167 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1168 if drv or root:
1169 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001170 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001171 for p in selector.select_from(self):
1172 yield p
1173
1174 def absolute(self):
1175 """Return an absolute version of this path. This function works
1176 even if the path doesn't point to anything.
1177
1178 No normalization is done, i.e. all '.' and '..' will be kept along.
1179 Use resolve() to get the canonical path to a file.
1180 """
1181 # XXX untested yet!
Antoine Pitrou31119e42013-11-22 17:38:12 +01001182 if self.is_absolute():
1183 return self
1184 # FIXME this must defer to the specific flavour (and, under Windows,
1185 # use nt._getfullpathname())
1186 obj = self._from_parts([os.getcwd()] + self._parts, init=False)
1187 obj._init(template=self)
1188 return obj
1189
Steve Dower98eb3602016-11-09 12:58:17 -08001190 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001191 """
1192 Make the path absolute, resolving all symlinks on the way and also
1193 normalizing it (for example turning slashes into backslashes under
1194 Windows).
1195 """
Steve Dower98eb3602016-11-09 12:58:17 -08001196 s = self._flavour.resolve(self, strict=strict)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001197 if s is None:
1198 # No symlink resolution => for consistency, raise an error if
1199 # the path doesn't exist or is forbidden
1200 self.stat()
1201 s = str(self.absolute())
1202 # Now we have no symlinks in the path, it's safe to normalize it.
1203 normed = self._flavour.pathmod.normpath(s)
1204 obj = self._from_parts((normed,), init=False)
1205 obj._init(template=self)
1206 return obj
1207
1208 def stat(self):
1209 """
1210 Return the result of the stat() system call on this path, like
1211 os.stat() does.
1212 """
1213 return self._accessor.stat(self)
1214
1215 def owner(self):
1216 """
1217 Return the login name of the file owner.
1218 """
Barney Gale22386bb2020-04-17 17:41:07 +01001219 return self._accessor.owner(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001220
1221 def group(self):
1222 """
1223 Return the group name of the file gid.
1224 """
Barney Gale22386bb2020-04-17 17:41:07 +01001225 return self._accessor.group(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001226
Antoine Pitrou31119e42013-11-22 17:38:12 +01001227 def open(self, mode='r', buffering=-1, encoding=None,
1228 errors=None, newline=None):
1229 """
1230 Open the file pointed by this path and return a file object, as
1231 the built-in open() function does.
1232 """
Inada Naoki48274832021-03-29 12:28:14 +09001233 if "b" not in mode:
1234 encoding = io.text_encoding(encoding)
Serhiy Storchaka62a99512017-03-25 13:42:11 +02001235 return io.open(self, mode, buffering, encoding, errors, newline,
Antoine Pitrou31119e42013-11-22 17:38:12 +01001236 opener=self._opener)
1237
Georg Brandlea683982014-10-01 19:12:33 +02001238 def read_bytes(self):
1239 """
1240 Open the file in bytes mode, read it, and close the file.
1241 """
1242 with self.open(mode='rb') as f:
1243 return f.read()
1244
1245 def read_text(self, encoding=None, errors=None):
1246 """
1247 Open the file in text mode, read it, and close the file.
1248 """
Inada Naoki48274832021-03-29 12:28:14 +09001249 encoding = io.text_encoding(encoding)
Georg Brandlea683982014-10-01 19:12:33 +02001250 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1251 return f.read()
1252
1253 def write_bytes(self, data):
1254 """
1255 Open the file in bytes mode, write to it, and close the file.
1256 """
1257 # type-check for the buffer interface before truncating the file
1258 view = memoryview(data)
1259 with self.open(mode='wb') as f:
1260 return f.write(view)
1261
Максим5f227412020-10-21 05:08:19 +03001262 def write_text(self, data, encoding=None, errors=None, newline=None):
Georg Brandlea683982014-10-01 19:12:33 +02001263 """
1264 Open the file in text mode, write to it, and close the file.
1265 """
1266 if not isinstance(data, str):
1267 raise TypeError('data must be str, not %s' %
1268 data.__class__.__name__)
Inada Naoki48274832021-03-29 12:28:14 +09001269 encoding = io.text_encoding(encoding)
Максим5f227412020-10-21 05:08:19 +03001270 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
Georg Brandlea683982014-10-01 19:12:33 +02001271 return f.write(data)
1272
Girtsa01ba332019-10-23 14:18:40 -07001273 def readlink(self):
1274 """
1275 Return the path to which the symbolic link points.
1276 """
1277 path = self._accessor.readlink(self)
1278 obj = self._from_parts((path,), init=False)
1279 obj._init(template=self)
1280 return obj
1281
Antoine Pitrou31119e42013-11-22 17:38:12 +01001282 def touch(self, mode=0o666, exist_ok=True):
1283 """
1284 Create this file with the given access mode, if it doesn't exist.
1285 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001286 if exist_ok:
1287 # First try to bump modification time
1288 # Implementation note: GNU touch uses the UTIME_NOW option of
1289 # the utimensat() / futimens() functions.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001290 try:
Antoine Pitrou2cf39172013-11-23 15:25:59 +01001291 self._accessor.utime(self, None)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001292 except OSError:
1293 # Avoid exception chaining
1294 pass
1295 else:
1296 return
1297 flags = os.O_CREAT | os.O_WRONLY
1298 if not exist_ok:
1299 flags |= os.O_EXCL
1300 fd = self._raw_open(flags, mode)
1301 os.close(fd)
1302
Barry Warsaw7c549c42014-08-05 11:28:12 -04001303 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001304 """
1305 Create a new directory at this given path.
1306 """
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001307 try:
1308 self._accessor.mkdir(self, mode)
1309 except FileNotFoundError:
1310 if not parents or self.parent == self:
1311 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001312 self.parent.mkdir(parents=True, exist_ok=True)
1313 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001314 except OSError:
1315 # Cannot rely on checking for EEXIST, since the operating system
1316 # could give priority to other errors like EACCES or EROFS
1317 if not exist_ok or not self.is_dir():
1318 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001319
1320 def chmod(self, mode):
1321 """
1322 Change the permissions of the path, like os.chmod().
1323 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001324 self._accessor.chmod(self, mode)
1325
1326 def lchmod(self, mode):
1327 """
1328 Like chmod(), except if the path points to a symlink, the symlink's
1329 permissions are changed, rather than its target's.
1330 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001331 self._accessor.lchmod(self, mode)
1332
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001333 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001334 """
1335 Remove this file or link.
1336 If the path is a directory, use rmdir() instead.
1337 """
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001338 try:
1339 self._accessor.unlink(self)
1340 except FileNotFoundError:
1341 if not missing_ok:
1342 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001343
1344 def rmdir(self):
1345 """
1346 Remove this directory. The directory must be empty.
1347 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001348 self._accessor.rmdir(self)
1349
1350 def lstat(self):
1351 """
1352 Like stat(), except if the path points to a symlink, the symlink's
1353 status information is returned, rather than its target's.
1354 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001355 return self._accessor.lstat(self)
1356
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -04001357 def link_to(self, target):
1358 """
1359 Create a hard link pointing to a path named target.
1360 """
Barney Galeb57e0452021-04-07 00:01:22 +01001361 self._accessor.link(self, target)
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -04001362
Antoine Pitrou31119e42013-11-22 17:38:12 +01001363 def rename(self, target):
1364 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001365 Rename this path to the target path.
1366
1367 The target path may be absolute or relative. Relative paths are
1368 interpreted relative to the current working directory, *not* the
1369 directory of the Path object.
1370
1371 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001372 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001373 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001374 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001375
1376 def replace(self, target):
1377 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001378 Rename this path to the target path, overwriting if that path exists.
1379
1380 The target path may be absolute or relative. Relative paths are
1381 interpreted relative to the current working directory, *not* the
1382 directory of the Path object.
1383
1384 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001385 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001386 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001387 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001388
1389 def symlink_to(self, target, target_is_directory=False):
1390 """
1391 Make this path a symlink pointing to the given path.
1392 Note the order of arguments (self, target) is the reverse of os.symlink's.
1393 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001394 self._accessor.symlink(target, self, target_is_directory)
1395
1396 # Convenience functions for querying the stat results
1397
1398 def exists(self):
1399 """
1400 Whether this path exists.
1401 """
1402 try:
1403 self.stat()
1404 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001405 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001406 raise
1407 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001408 except ValueError:
1409 # Non-encodable path
1410 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001411 return True
1412
1413 def is_dir(self):
1414 """
1415 Whether this path is a directory.
1416 """
1417 try:
1418 return S_ISDIR(self.stat().st_mode)
1419 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001420 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001421 raise
1422 # Path doesn't exist or is a broken symlink
1423 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1424 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001425 except ValueError:
1426 # Non-encodable path
1427 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001428
1429 def is_file(self):
1430 """
1431 Whether this path is a regular file (also True for symlinks pointing
1432 to regular files).
1433 """
1434 try:
1435 return S_ISREG(self.stat().st_mode)
1436 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001437 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001438 raise
1439 # Path doesn't exist or is a broken symlink
1440 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1441 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001442 except ValueError:
1443 # Non-encodable path
1444 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001445
Cooper Lees173ff4a2017-08-01 15:35:45 -07001446 def is_mount(self):
1447 """
1448 Check if this path is a POSIX mount point
1449 """
1450 # Need to exist and be a dir
1451 if not self.exists() or not self.is_dir():
1452 return False
1453
Cooper Lees173ff4a2017-08-01 15:35:45 -07001454 try:
Barney Galec746c4f2020-04-17 18:42:06 +01001455 parent_dev = self.parent.stat().st_dev
Cooper Lees173ff4a2017-08-01 15:35:45 -07001456 except OSError:
1457 return False
1458
1459 dev = self.stat().st_dev
1460 if dev != parent_dev:
1461 return True
1462 ino = self.stat().st_ino
Barney Galec746c4f2020-04-17 18:42:06 +01001463 parent_ino = self.parent.stat().st_ino
Cooper Lees173ff4a2017-08-01 15:35:45 -07001464 return ino == parent_ino
1465
Antoine Pitrou31119e42013-11-22 17:38:12 +01001466 def is_symlink(self):
1467 """
1468 Whether this path is a symbolic link.
1469 """
1470 try:
1471 return S_ISLNK(self.lstat().st_mode)
1472 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001473 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001474 raise
1475 # Path doesn't exist
1476 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001477 except ValueError:
1478 # Non-encodable path
1479 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001480
1481 def is_block_device(self):
1482 """
1483 Whether this path is a block device.
1484 """
1485 try:
1486 return S_ISBLK(self.stat().st_mode)
1487 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001488 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001489 raise
1490 # Path doesn't exist or is a broken symlink
1491 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1492 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001493 except ValueError:
1494 # Non-encodable path
1495 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001496
1497 def is_char_device(self):
1498 """
1499 Whether this path is a character device.
1500 """
1501 try:
1502 return S_ISCHR(self.stat().st_mode)
1503 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001504 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001505 raise
1506 # Path doesn't exist or is a broken symlink
1507 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1508 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001509 except ValueError:
1510 # Non-encodable path
1511 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001512
1513 def is_fifo(self):
1514 """
1515 Whether this path is a FIFO.
1516 """
1517 try:
1518 return S_ISFIFO(self.stat().st_mode)
1519 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001520 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001521 raise
1522 # Path doesn't exist or is a broken symlink
1523 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1524 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001525 except ValueError:
1526 # Non-encodable path
1527 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001528
1529 def is_socket(self):
1530 """
1531 Whether this path is a socket.
1532 """
1533 try:
1534 return S_ISSOCK(self.stat().st_mode)
1535 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001536 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001537 raise
1538 # Path doesn't exist or is a broken symlink
1539 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1540 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001541 except ValueError:
1542 # Non-encodable path
1543 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001544
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001545 def expanduser(self):
1546 """ Return a new path with expanded ~ and ~user constructs
1547 (as returned by os.path.expanduser)
1548 """
1549 if (not (self._drv or self._root) and
1550 self._parts and self._parts[0][:1] == '~'):
1551 homedir = self._flavour.gethomedir(self._parts[0][1:])
1552 return self._from_parts([homedir] + self._parts[1:])
1553
1554 return self
1555
Antoine Pitrou31119e42013-11-22 17:38:12 +01001556
1557class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001558 """Path subclass for non-Windows systems.
1559
1560 On a POSIX system, instantiating a Path should return this object.
1561 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001562 __slots__ = ()
1563
1564class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001565 """Path subclass for Windows systems.
1566
1567 On a Windows system, instantiating a Path should return this object.
1568 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001569 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001570
Cooper Lees173ff4a2017-08-01 15:35:45 -07001571 def is_mount(self):
1572 raise NotImplementedError("Path.is_mount() is unsupported on this system")