blob: ebc2c02ecc0dc2a4b4c6753b94607f02f951481d [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
Steve Dower4696f122021-04-22 21:04:44 +010036 123, # ERROR_INVALID_NAME - fix for bpo-35306
Jörg Stucked5c120f2019-05-21 19:44:40 +020037 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
Steve Dower2f6fae62019-02-03 23:08:18 -080038)
39
40def _ignore_error(exception):
41 return (getattr(exception, 'errno', None) in _IGNORED_ERROS or
42 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
43
44
Antoine Pitrou31119e42013-11-22 17:38:12 +010045def _is_wildcard_pattern(pat):
46 # Whether this pattern needs actual matching using fnmatch, or can
47 # be looked up directly as a file.
48 return "*" in pat or "?" in pat or "[" in pat
49
50
51class _Flavour(object):
52 """A flavour implements a particular (platform-specific) set of path
53 semantics."""
54
55 def __init__(self):
56 self.join = self.sep.join
57
58 def parse_parts(self, parts):
59 parsed = []
60 sep = self.sep
61 altsep = self.altsep
62 drv = root = ''
63 it = reversed(parts)
64 for part in it:
65 if not part:
66 continue
67 if altsep:
68 part = part.replace(altsep, sep)
69 drv, root, rel = self.splitroot(part)
70 if sep in rel:
71 for x in reversed(rel.split(sep)):
72 if x and x != '.':
73 parsed.append(sys.intern(x))
74 else:
75 if rel and rel != '.':
76 parsed.append(sys.intern(rel))
77 if drv or root:
78 if not drv:
79 # If no drive is present, try to find one in the previous
80 # parts. This makes the result of parsing e.g.
81 # ("C:", "/", "a") reasonably intuitive.
82 for part in it:
Antoine Pitrou57fffd62015-02-15 18:03:59 +010083 if not part:
84 continue
85 if altsep:
86 part = part.replace(altsep, sep)
Antoine Pitrou31119e42013-11-22 17:38:12 +010087 drv = self.splitroot(part)[0]
88 if drv:
89 break
90 break
91 if drv or root:
92 parsed.append(drv + root)
93 parsed.reverse()
94 return drv, root, parsed
95
96 def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
97 """
98 Join the two paths represented by the respective
99 (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
100 """
101 if root2:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200102 if not drv2 and drv:
103 return drv, root2, [drv + root2] + parts2[1:]
104 elif drv2:
105 if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
106 # Same drive => second path is relative to the first
107 return drv, root, parts + parts2[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100108 else:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200109 # Second path is non-anchored (common case)
110 return drv, root, parts + parts2
111 return drv2, root2, parts2
Antoine Pitrou31119e42013-11-22 17:38:12 +0100112
113
114class _WindowsFlavour(_Flavour):
115 # Reference for Windows paths can be found at
116 # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
117
118 sep = '\\'
119 altsep = '/'
120 has_drv = True
121 pathmod = ntpath
122
Antoine Pitroudb118f52014-11-19 00:32:08 +0100123 is_supported = (os.name == 'nt')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100124
Jon Dufresne39726282017-05-18 07:35:54 -0700125 drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100126 ext_namespace_prefix = '\\\\?\\'
127
128 reserved_names = (
129 {'CON', 'PRN', 'AUX', 'NUL'} |
130 {'COM%d' % i for i in range(1, 10)} |
131 {'LPT%d' % i for i in range(1, 10)}
132 )
133
134 # Interesting findings about extended paths:
135 # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
136 # but '\\?\c:/a' is not
137 # - extended paths are always absolute; "relative" extended paths will
138 # fail.
139
140 def splitroot(self, part, sep=sep):
141 first = part[0:1]
142 second = part[1:2]
143 if (second == sep and first == sep):
144 # XXX extended paths should also disable the collapsing of "."
145 # components (according to MSDN docs).
146 prefix, part = self._split_extended_path(part)
147 first = part[0:1]
148 second = part[1:2]
149 else:
150 prefix = ''
151 third = part[2:3]
152 if (second == sep and first == sep and third != sep):
153 # is a UNC path:
154 # vvvvvvvvvvvvvvvvvvvvv root
155 # \\machine\mountpoint\directory\etc\...
156 # directory ^^^^^^^^^^^^^^
157 index = part.find(sep, 2)
158 if index != -1:
159 index2 = part.find(sep, index + 1)
160 # a UNC path can't have two slashes in a row
161 # (after the initial two)
162 if index2 != index + 1:
163 if index2 == -1:
164 index2 = len(part)
165 if prefix:
166 return prefix + part[1:index2], sep, part[index2+1:]
167 else:
168 return part[:index2], sep, part[index2+1:]
169 drv = root = ''
170 if second == ':' and first in self.drive_letters:
171 drv = part[:2]
172 part = part[2:]
173 first = third
174 if first == sep:
175 root = first
176 part = part.lstrip(sep)
177 return prefix + drv, root, part
178
179 def casefold(self, s):
180 return s.lower()
181
182 def casefold_parts(self, parts):
183 return [p.lower() for p in parts]
184
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300185 def compile_pattern(self, pattern):
186 return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
187
Steve Dower98eb3602016-11-09 12:58:17 -0800188 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100189 s = str(path)
190 if not s:
Barney Galeb05440c2021-04-07 17:31:49 +0100191 return path._accessor.getcwd()
Steve Dower98eb3602016-11-09 12:58:17 -0800192 previous_s = None
Antoine Pitrou31119e42013-11-22 17:38:12 +0100193 if _getfinalpathname is not None:
Steve Dower98eb3602016-11-09 12:58:17 -0800194 if strict:
195 return self._ext_to_normal(_getfinalpathname(s))
196 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200197 tail_parts = [] # End of the path after the first one not found
Steve Dower98eb3602016-11-09 12:58:17 -0800198 while True:
199 try:
200 s = self._ext_to_normal(_getfinalpathname(s))
201 except FileNotFoundError:
202 previous_s = s
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200203 s, tail = os.path.split(s)
204 tail_parts.append(tail)
Steve Dower4b1e98b2016-12-28 16:02:59 -0800205 if previous_s == s:
206 return path
Steve Dower98eb3602016-11-09 12:58:17 -0800207 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200208 return os.path.join(s, *reversed(tail_parts))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100209 # Means fallback on absolute
210 return None
211
212 def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
213 prefix = ''
214 if s.startswith(ext_prefix):
215 prefix = s[:4]
216 s = s[4:]
217 if s.startswith('UNC\\'):
218 prefix += s[:3]
219 s = '\\' + s[3:]
220 return prefix, s
221
222 def _ext_to_normal(self, s):
223 # Turn back an extended path into a normal DOS-like path
224 return self._split_extended_path(s)[1]
225
226 def is_reserved(self, parts):
227 # NOTE: the rules for reserved names seem somewhat complicated
228 # (e.g. r"..\NUL" is reserved but not r"foo\NUL").
229 # We err on the side of caution and return True for paths which are
230 # not considered reserved by Windows.
231 if not parts:
232 return False
233 if parts[0].startswith('\\\\'):
234 # UNC paths are never reserved
235 return False
236 return parts[-1].partition('.')[0].upper() in self.reserved_names
237
238 def make_uri(self, path):
239 # Under Windows, file URIs use the UTF-8 encoding.
240 drive = path.drive
241 if len(drive) == 2 and drive[1] == ':':
242 # It's a path on a local drive => 'file:///c:/a/b'
243 rest = path.as_posix()[2:].lstrip('/')
244 return 'file:///%s/%s' % (
245 drive, urlquote_from_bytes(rest.encode('utf-8')))
246 else:
247 # It's a path on a network drive => 'file://host/share/a/b'
248 return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
249
250
251class _PosixFlavour(_Flavour):
252 sep = '/'
253 altsep = ''
254 has_drv = False
255 pathmod = posixpath
256
257 is_supported = (os.name != 'nt')
258
259 def splitroot(self, part, sep=sep):
260 if part and part[0] == sep:
261 stripped_part = part.lstrip(sep)
262 # According to POSIX path resolution:
263 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
264 # "A pathname that begins with two successive slashes may be
265 # interpreted in an implementation-defined manner, although more
266 # than two leading slashes shall be treated as a single slash".
267 if len(part) - len(stripped_part) == 2:
268 return '', sep * 2, stripped_part
269 else:
270 return '', sep, stripped_part
271 else:
272 return '', '', part
273
274 def casefold(self, s):
275 return s
276
277 def casefold_parts(self, parts):
278 return parts
279
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300280 def compile_pattern(self, pattern):
281 return re.compile(fnmatch.translate(pattern)).fullmatch
282
Steve Dower98eb3602016-11-09 12:58:17 -0800283 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100284 sep = self.sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100285 accessor = path._accessor
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100286 seen = {}
287 def _resolve(path, rest):
288 if rest.startswith(sep):
289 path = ''
290
291 for name in rest.split(sep):
292 if not name or name == '.':
293 # current dir
294 continue
295 if name == '..':
296 # parent dir
297 path, _, _ = path.rpartition(sep)
298 continue
Dong-hee Na94ad6c62018-06-12 23:30:45 +0900299 if path.endswith(sep):
300 newpath = path + name
301 else:
302 newpath = path + sep + name
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100303 if newpath in seen:
304 # Already seen this path
305 path = seen[newpath]
306 if path is not None:
307 # use cached value
308 continue
309 # The symlink is not resolved, so we must have a symlink loop.
310 raise RuntimeError("Symlink loop from %r" % newpath)
311 # Resolve the symbolic link
312 try:
313 target = accessor.readlink(newpath)
314 except OSError as e:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200315 if e.errno != EINVAL and strict:
316 raise
317 # Not a symlink, or non-strict mode. We just leave the path
318 # untouched.
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100319 path = newpath
320 else:
321 seen[newpath] = None # not resolved symlink
322 path = _resolve(path, target)
323 seen[newpath] = path # resolved symlink
324
325 return path
326 # NOTE: according to POSIX, getcwd() cannot contain path components
327 # which are symlinks.
Barney Galeb05440c2021-04-07 17:31:49 +0100328 base = '' if path.is_absolute() else accessor.getcwd()
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100329 return _resolve(base, str(path)) or sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100330
331 def is_reserved(self, parts):
332 return False
333
334 def make_uri(self, path):
335 # We represent the path using the local filesystem encoding,
336 # for portability to other applications.
337 bpath = bytes(path)
338 return 'file://' + urlquote_from_bytes(bpath)
339
340
341_windows_flavour = _WindowsFlavour()
342_posix_flavour = _PosixFlavour()
343
344
345class _Accessor:
346 """An accessor implements a particular (system-specific or not) way of
347 accessing paths on the filesystem."""
348
349
350class _NormalAccessor(_Accessor):
351
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200352 stat = os.stat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100353
Barney Gale11c3bd32021-04-09 21:52:49 +0100354 open = io.open
Antoine Pitrou31119e42013-11-22 17:38:12 +0100355
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200356 listdir = os.listdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100357
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200358 scandir = os.scandir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100359
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200360 chmod = os.chmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100361
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200362 mkdir = os.mkdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100363
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200364 unlink = os.unlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100365
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100366 if hasattr(os, "link"):
Barney Galeb57e0452021-04-07 00:01:22 +0100367 link = os.link
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100368 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100369 def link(self, src, dst):
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100370 raise NotImplementedError("os.link() not available on this system")
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -0400371
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200372 rmdir = os.rmdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100373
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200374 rename = os.rename
Antoine Pitrou31119e42013-11-22 17:38:12 +0100375
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200376 replace = os.replace
Antoine Pitrou31119e42013-11-22 17:38:12 +0100377
Barney Galeb57e0452021-04-07 00:01:22 +0100378 if hasattr(os, "symlink"):
379 symlink = os.symlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100380 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100381 def symlink(self, src, dst, target_is_directory=False):
382 raise NotImplementedError("os.symlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100383
Barney Gale986da8e2021-04-07 01:25:37 +0100384 def touch(self, path, mode=0o666, exist_ok=True):
385 if exist_ok:
386 # First try to bump modification time
387 # Implementation note: GNU touch uses the UTIME_NOW option of
388 # the utimensat() / futimens() functions.
389 try:
390 os.utime(path, None)
391 except OSError:
392 # Avoid exception chaining
393 pass
394 else:
395 return
396 flags = os.O_CREAT | os.O_WRONLY
397 if not exist_ok:
398 flags |= os.O_EXCL
399 fd = os.open(path, flags, mode)
400 os.close(fd)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100401
Barney Galeb57e0452021-04-07 00:01:22 +0100402 if hasattr(os, "readlink"):
403 readlink = os.readlink
404 else:
405 def readlink(self, path):
406 raise NotImplementedError("os.readlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100407
Barney Gale22386bb2020-04-17 17:41:07 +0100408 def owner(self, path):
409 try:
410 import pwd
411 return pwd.getpwuid(self.stat(path).st_uid).pw_name
412 except ImportError:
413 raise NotImplementedError("Path.owner() is unsupported on this system")
414
415 def group(self, path):
416 try:
417 import grp
418 return grp.getgrgid(self.stat(path).st_gid).gr_name
419 except ImportError:
420 raise NotImplementedError("Path.group() is unsupported on this system")
421
Barney Galeb05440c2021-04-07 17:31:49 +0100422 getcwd = os.getcwd
423
Barney Gale3f3d82b2021-04-07 23:50:13 +0100424 expanduser = staticmethod(os.path.expanduser)
425
Antoine Pitrou31119e42013-11-22 17:38:12 +0100426
427_normal_accessor = _NormalAccessor()
428
429
430#
431# Globbing helpers
432#
433
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300434def _make_selector(pattern_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100435 pat = pattern_parts[0]
436 child_parts = pattern_parts[1:]
437 if pat == '**':
438 cls = _RecursiveWildcardSelector
439 elif '**' in pat:
440 raise ValueError("Invalid pattern: '**' can only be an entire path component")
441 elif _is_wildcard_pattern(pat):
442 cls = _WildcardSelector
443 else:
444 cls = _PreciseSelector
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300445 return cls(pat, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100446
447if hasattr(functools, "lru_cache"):
448 _make_selector = functools.lru_cache()(_make_selector)
449
450
451class _Selector:
452 """A selector matches a specific glob pattern part against the children
453 of a given path."""
454
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300455 def __init__(self, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100456 self.child_parts = child_parts
457 if child_parts:
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300458 self.successor = _make_selector(child_parts, flavour)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300459 self.dironly = True
Antoine Pitrou31119e42013-11-22 17:38:12 +0100460 else:
461 self.successor = _TerminatingSelector()
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300462 self.dironly = False
Antoine Pitrou31119e42013-11-22 17:38:12 +0100463
464 def select_from(self, parent_path):
465 """Iterate over all child paths of `parent_path` matched by this
466 selector. This can contain parent_path itself."""
467 path_cls = type(parent_path)
468 is_dir = path_cls.is_dir
469 exists = path_cls.exists
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300470 scandir = parent_path._accessor.scandir
471 if not is_dir(parent_path):
472 return iter([])
473 return self._select_from(parent_path, is_dir, exists, scandir)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100474
475
476class _TerminatingSelector:
477
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300478 def _select_from(self, parent_path, is_dir, exists, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100479 yield parent_path
480
481
482class _PreciseSelector(_Selector):
483
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300484 def __init__(self, name, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100485 self.name = name
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300486 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100487
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300488 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800489 try:
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800490 path = parent_path._make_child_relpath(self.name)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300491 if (is_dir if self.dironly else exists)(path):
492 for p in self.successor._select_from(path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800493 yield p
494 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100495 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100496
497
498class _WildcardSelector(_Selector):
499
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300500 def __init__(self, pat, child_parts, flavour):
501 self.match = flavour.compile_pattern(pat)
502 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100503
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300504 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800505 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200506 with scandir(parent_path) as scandir_it:
507 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300508 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000509 if self.dironly:
510 try:
511 # "entry.is_dir()" can raise PermissionError
512 # in some cases (see bpo-38894), which is not
513 # among the errors ignored by _ignore_error()
514 if not entry.is_dir():
515 continue
516 except OSError as e:
517 if not _ignore_error(e):
518 raise
519 continue
520 name = entry.name
521 if self.match(name):
522 path = parent_path._make_child_relpath(name)
523 for p in self.successor._select_from(path, is_dir, exists, scandir):
524 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800525 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100526 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800527
Antoine Pitrou31119e42013-11-22 17:38:12 +0100528
Antoine Pitrou31119e42013-11-22 17:38:12 +0100529class _RecursiveWildcardSelector(_Selector):
530
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300531 def __init__(self, pat, child_parts, flavour):
532 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100533
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300534 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100535 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800536 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200537 with scandir(parent_path) as scandir_it:
538 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300539 for entry in entries:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200540 entry_is_dir = False
541 try:
542 entry_is_dir = entry.is_dir()
543 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800544 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200545 raise
546 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300547 path = parent_path._make_child_relpath(entry.name)
548 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800549 yield p
550 except PermissionError:
551 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100552
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300553 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800554 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300555 yielded = set()
556 try:
557 successor_select = self.successor._select_from
558 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
559 for p in successor_select(starting_point, is_dir, exists, scandir):
560 if p not in yielded:
561 yield p
562 yielded.add(p)
563 finally:
564 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800565 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100566 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100567
568
569#
570# Public API
571#
572
573class _PathParents(Sequence):
574 """This object provides sequence-like access to the logical ancestors
575 of a path. Don't try to construct it yourself."""
576 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
577
578 def __init__(self, path):
579 # We don't store the instance to avoid reference cycles
580 self._pathcls = type(path)
581 self._drv = path._drv
582 self._root = path._root
583 self._parts = path._parts
584
585 def __len__(self):
586 if self._drv or self._root:
587 return len(self._parts) - 1
588 else:
589 return len(self._parts)
590
591 def __getitem__(self, idx):
Joshua Cannon45205842020-11-20 09:40:39 -0600592 if isinstance(idx, slice):
593 return tuple(self[i] for i in range(*idx.indices(len(self))))
Yaroslav Pankovych79d2e622020-11-23 22:06:22 +0200594
595 if idx >= len(self) or idx < -len(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100596 raise IndexError(idx)
597 return self._pathcls._from_parsed_parts(self._drv, self._root,
598 self._parts[:-idx - 1])
599
600 def __repr__(self):
601 return "<{}.parents>".format(self._pathcls.__name__)
602
603
604class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900605 """Base class for manipulating paths without I/O.
606
607 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100608 don't imply any actual filesystem I/O. Depending on your system,
609 instantiating a PurePath will return either a PurePosixPath or a
610 PureWindowsPath object. You can also instantiate either of these classes
611 directly, regardless of your system.
612 """
613 __slots__ = (
614 '_drv', '_root', '_parts',
615 '_str', '_hash', '_pparts', '_cached_cparts',
616 )
617
618 def __new__(cls, *args):
619 """Construct a PurePath from one or several strings and or existing
620 PurePath objects. The strings and path objects are combined so as
621 to yield a canonicalized path, which is incorporated into the
622 new PurePath object.
623 """
624 if cls is PurePath:
625 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
626 return cls._from_parts(args)
627
628 def __reduce__(self):
629 # Using the parts tuple helps share interned path parts
630 # when pickling related paths.
631 return (self.__class__, tuple(self._parts))
632
633 @classmethod
634 def _parse_args(cls, args):
635 # This is useful when you don't want to create an instance, just
636 # canonicalize some constructor arguments.
637 parts = []
638 for a in args:
639 if isinstance(a, PurePath):
640 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100641 else:
Brett Cannon568be632016-06-10 12:20:49 -0700642 a = os.fspath(a)
643 if isinstance(a, str):
644 # Force-cast str subclasses to str (issue #21127)
645 parts.append(str(a))
646 else:
647 raise TypeError(
648 "argument should be a str object or an os.PathLike "
649 "object returning str, not %r"
650 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100651 return cls._flavour.parse_parts(parts)
652
653 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100654 def _from_parts(cls, args):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100655 # We need to call _parse_args on the instance, so as to get the
656 # right flavour.
657 self = object.__new__(cls)
658 drv, root, parts = self._parse_args(args)
659 self._drv = drv
660 self._root = root
661 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100662 return self
663
664 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100665 def _from_parsed_parts(cls, drv, root, parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100666 self = object.__new__(cls)
667 self._drv = drv
668 self._root = root
669 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100670 return self
671
672 @classmethod
673 def _format_parsed_parts(cls, drv, root, parts):
674 if drv or root:
675 return drv + root + cls._flavour.join(parts[1:])
676 else:
677 return cls._flavour.join(parts)
678
Antoine Pitrou31119e42013-11-22 17:38:12 +0100679 def _make_child(self, args):
680 drv, root, parts = self._parse_args(args)
681 drv, root, parts = self._flavour.join_parsed_parts(
682 self._drv, self._root, self._parts, drv, root, parts)
683 return self._from_parsed_parts(drv, root, parts)
684
685 def __str__(self):
686 """Return the string representation of the path, suitable for
687 passing to system calls."""
688 try:
689 return self._str
690 except AttributeError:
691 self._str = self._format_parsed_parts(self._drv, self._root,
692 self._parts) or '.'
693 return self._str
694
Brett Cannon568be632016-06-10 12:20:49 -0700695 def __fspath__(self):
696 return str(self)
697
Antoine Pitrou31119e42013-11-22 17:38:12 +0100698 def as_posix(self):
699 """Return the string representation of the path with forward (/)
700 slashes."""
701 f = self._flavour
702 return str(self).replace(f.sep, '/')
703
704 def __bytes__(self):
705 """Return the bytes representation of the path. This is only
706 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200707 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100708
709 def __repr__(self):
710 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
711
712 def as_uri(self):
713 """Return the path as a 'file' URI."""
714 if not self.is_absolute():
715 raise ValueError("relative path can't be expressed as a file URI")
716 return self._flavour.make_uri(self)
717
718 @property
719 def _cparts(self):
720 # Cached casefolded parts, for hashing and comparison
721 try:
722 return self._cached_cparts
723 except AttributeError:
724 self._cached_cparts = self._flavour.casefold_parts(self._parts)
725 return self._cached_cparts
726
727 def __eq__(self, other):
728 if not isinstance(other, PurePath):
729 return NotImplemented
730 return self._cparts == other._cparts and self._flavour is other._flavour
731
Antoine Pitrou31119e42013-11-22 17:38:12 +0100732 def __hash__(self):
733 try:
734 return self._hash
735 except AttributeError:
736 self._hash = hash(tuple(self._cparts))
737 return self._hash
738
739 def __lt__(self, other):
740 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
741 return NotImplemented
742 return self._cparts < other._cparts
743
744 def __le__(self, other):
745 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
746 return NotImplemented
747 return self._cparts <= other._cparts
748
749 def __gt__(self, other):
750 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
751 return NotImplemented
752 return self._cparts > other._cparts
753
754 def __ge__(self, other):
755 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
756 return NotImplemented
757 return self._cparts >= other._cparts
758
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300759 def __class_getitem__(cls, type):
760 return cls
761
Antoine Pitrou31119e42013-11-22 17:38:12 +0100762 drive = property(attrgetter('_drv'),
763 doc="""The drive prefix (letter or UNC path), if any.""")
764
765 root = property(attrgetter('_root'),
766 doc="""The root of the path, if any.""")
767
768 @property
769 def anchor(self):
770 """The concatenation of the drive and root, or ''."""
771 anchor = self._drv + self._root
772 return anchor
773
774 @property
775 def name(self):
776 """The final path component, if any."""
777 parts = self._parts
778 if len(parts) == (1 if (self._drv or self._root) else 0):
779 return ''
780 return parts[-1]
781
782 @property
783 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200784 """
785 The final component's last suffix, if any.
786
787 This includes the leading period. For example: '.txt'
788 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100789 name = self.name
790 i = name.rfind('.')
791 if 0 < i < len(name) - 1:
792 return name[i:]
793 else:
794 return ''
795
796 @property
797 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200798 """
799 A list of the final component's suffixes, if any.
800
801 These include the leading periods. For example: ['.tar', '.gz']
802 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100803 name = self.name
804 if name.endswith('.'):
805 return []
806 name = name.lstrip('.')
807 return ['.' + suffix for suffix in name.split('.')[1:]]
808
809 @property
810 def stem(self):
811 """The final path component, minus its last suffix."""
812 name = self.name
813 i = name.rfind('.')
814 if 0 < i < len(name) - 1:
815 return name[:i]
816 else:
817 return name
818
819 def with_name(self, name):
820 """Return a new path with the file name changed."""
821 if not self.name:
822 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400823 drv, root, parts = self._flavour.parse_parts((name,))
824 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
825 or drv or root or len(parts) != 1):
826 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100827 return self._from_parsed_parts(self._drv, self._root,
828 self._parts[:-1] + [name])
829
Tim Hoffmann8aea4b32020-04-19 17:29:49 +0200830 def with_stem(self, stem):
831 """Return a new path with the stem changed."""
832 return self.with_name(stem + self.suffix)
833
Antoine Pitrou31119e42013-11-22 17:38:12 +0100834 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200835 """Return a new path with the file suffix changed. If the path
836 has no suffix, add given suffix. If the given suffix is an empty
837 string, remove the suffix from the path.
838 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400839 f = self._flavour
840 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300841 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400842 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100843 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100844 name = self.name
845 if not name:
846 raise ValueError("%r has an empty name" % (self,))
847 old_suffix = self.suffix
848 if not old_suffix:
849 name = name + suffix
850 else:
851 name = name[:-len(old_suffix)] + suffix
852 return self._from_parsed_parts(self._drv, self._root,
853 self._parts[:-1] + [name])
854
855 def relative_to(self, *other):
856 """Return the relative path to another path identified by the passed
857 arguments. If the operation is not possible (because this is not
858 a subpath of the other path), raise ValueError.
859 """
860 # For the purpose of this method, drive and root are considered
861 # separate parts, i.e.:
862 # Path('c:/').relative_to('c:') gives Path('/')
863 # Path('c:/').relative_to('/') raise ValueError
864 if not other:
865 raise TypeError("need at least one argument")
866 parts = self._parts
867 drv = self._drv
868 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100869 if root:
870 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100871 else:
872 abs_parts = parts
873 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100874 if to_root:
875 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100876 else:
877 to_abs_parts = to_parts
878 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100879 cf = self._flavour.casefold_parts
880 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100881 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
Rotuna44832532020-05-25 21:42:28 +0200882 raise ValueError("{!r} is not in the subpath of {!r}"
883 " OR one path is relative and the other is absolute."
Antoine Pitrou31119e42013-11-22 17:38:12 +0100884 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100885 return self._from_parsed_parts('', root if n == 1 else '',
886 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100887
Hai Shi82642a02019-08-13 14:54:02 -0500888 def is_relative_to(self, *other):
889 """Return True if the path is relative to another path or False.
890 """
891 try:
892 self.relative_to(*other)
893 return True
894 except ValueError:
895 return False
896
Antoine Pitrou31119e42013-11-22 17:38:12 +0100897 @property
898 def parts(self):
899 """An object providing sequence-like access to the
900 components in the filesystem path."""
901 # We cache the tuple to avoid building a new one each time .parts
902 # is accessed. XXX is this necessary?
903 try:
904 return self._pparts
905 except AttributeError:
906 self._pparts = tuple(self._parts)
907 return self._pparts
908
909 def joinpath(self, *args):
910 """Combine this path with one or several arguments, and return a
911 new path representing either a subpath (if all arguments are relative
912 paths) or a totally different path (if one of the arguments is
913 anchored).
914 """
915 return self._make_child(args)
916
917 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400918 try:
919 return self._make_child((key,))
920 except TypeError:
921 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100922
923 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400924 try:
925 return self._from_parts([key] + self._parts)
926 except TypeError:
927 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100928
929 @property
930 def parent(self):
931 """The logical parent of the path."""
932 drv = self._drv
933 root = self._root
934 parts = self._parts
935 if len(parts) == 1 and (drv or root):
936 return self
937 return self._from_parsed_parts(drv, root, parts[:-1])
938
939 @property
940 def parents(self):
941 """A sequence of this path's logical parents."""
942 return _PathParents(self)
943
944 def is_absolute(self):
945 """True if the path is absolute (has both a root and, if applicable,
946 a drive)."""
947 if not self._root:
948 return False
949 return not self._flavour.has_drv or bool(self._drv)
950
951 def is_reserved(self):
952 """Return True if the path contains one of the special names reserved
953 by the system, if any."""
954 return self._flavour.is_reserved(self._parts)
955
956 def match(self, path_pattern):
957 """
958 Return True if this path matches the given pattern.
959 """
960 cf = self._flavour.casefold
961 path_pattern = cf(path_pattern)
962 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
963 if not pat_parts:
964 raise ValueError("empty pattern")
965 if drv and drv != cf(self._drv):
966 return False
967 if root and root != cf(self._root):
968 return False
969 parts = self._cparts
970 if drv or root:
971 if len(pat_parts) != len(parts):
972 return False
973 pat_parts = pat_parts[1:]
974 elif len(pat_parts) > len(parts):
975 return False
976 for part, pat in zip(reversed(parts), reversed(pat_parts)):
977 if not fnmatch.fnmatchcase(part, pat):
978 return False
979 return True
980
Brett Cannon568be632016-06-10 12:20:49 -0700981# Can't subclass os.PathLike from PurePath and keep the constructor
982# optimizations in PurePath._parse_args().
983os.PathLike.register(PurePath)
984
Antoine Pitrou31119e42013-11-22 17:38:12 +0100985
986class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900987 """PurePath subclass for non-Windows systems.
988
989 On a POSIX system, instantiating a PurePath should return this object.
990 However, you can also instantiate it directly on any system.
991 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100992 _flavour = _posix_flavour
993 __slots__ = ()
994
995
996class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900997 """PurePath subclass for Windows systems.
998
999 On a Windows system, instantiating a PurePath should return this object.
1000 However, you can also instantiate it directly on any system.
1001 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001002 _flavour = _windows_flavour
1003 __slots__ = ()
1004
1005
1006# Filesystem-accessing classes
1007
1008
1009class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001010 """PurePath subclass that can make system calls.
1011
1012 Path represents a filesystem path but unlike PurePath, also offers
1013 methods to do system calls on path objects. Depending on your system,
1014 instantiating a Path will return either a PosixPath or a WindowsPath
1015 object. You can also instantiate a PosixPath or WindowsPath directly,
1016 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1017 """
Barney Gale22191872021-04-07 01:26:37 +01001018 _accessor = _normal_accessor
1019 __slots__ = ()
Antoine Pitrou31119e42013-11-22 17:38:12 +01001020
1021 def __new__(cls, *args, **kwargs):
1022 if cls is Path:
1023 cls = WindowsPath if os.name == 'nt' else PosixPath
Barney Gale22191872021-04-07 01:26:37 +01001024 self = cls._from_parts(args)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001025 if not self._flavour.is_supported:
1026 raise NotImplementedError("cannot instantiate %r on your system"
1027 % (cls.__name__,))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001028 return self
1029
Antoine Pitrou31119e42013-11-22 17:38:12 +01001030 def _make_child_relpath(self, part):
1031 # This is an optimization used for dir walking. `part` must be
1032 # a single part relative to this path.
1033 parts = self._parts + [part]
1034 return self._from_parsed_parts(self._drv, self._root, parts)
1035
1036 def __enter__(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001037 return self
1038
1039 def __exit__(self, t, v, tb):
Barney Gale00002e62020-04-01 15:10:51 +01001040 # https://bugs.python.org/issue39682
1041 # In previous versions of pathlib, this method marked this path as
1042 # closed; subsequent attempts to perform I/O would raise an IOError.
1043 # This functionality was never documented, and had the effect of
1044 # making Path objects mutable, contrary to PEP 428. In Python 3.9 the
1045 # _closed attribute was removed, and this method made a no-op.
1046 # This method and __enter__()/__exit__() should be deprecated and
1047 # removed in the future.
1048 pass
Antoine Pitrou31119e42013-11-22 17:38:12 +01001049
Antoine Pitrou31119e42013-11-22 17:38:12 +01001050 # Public API
1051
1052 @classmethod
1053 def cwd(cls):
1054 """Return a new path pointing to the current working directory
1055 (as returned by os.getcwd()).
1056 """
Barney Galeb05440c2021-04-07 17:31:49 +01001057 return cls(cls()._accessor.getcwd())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001058
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001059 @classmethod
1060 def home(cls):
1061 """Return a new path pointing to the user's home directory (as
1062 returned by os.path.expanduser('~')).
1063 """
Barney Gale3f3d82b2021-04-07 23:50:13 +01001064 return cls("~").expanduser()
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001065
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001066 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001067 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001068 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001069 """
1070 st = self.stat()
1071 try:
1072 other_st = other_path.stat()
1073 except AttributeError:
Barney Gale5b1d9182020-04-17 18:47:27 +01001074 other_st = self._accessor.stat(other_path)
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001075 return os.path.samestat(st, other_st)
1076
Antoine Pitrou31119e42013-11-22 17:38:12 +01001077 def iterdir(self):
1078 """Iterate over the files in this directory. Does not yield any
1079 result for the special paths '.' and '..'.
1080 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001081 for name in self._accessor.listdir(self):
1082 if name in {'.', '..'}:
1083 # Yielding a path object for these makes little sense
1084 continue
1085 yield self._make_child_relpath(name)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001086
1087 def glob(self, pattern):
1088 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001089 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001090 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001091 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001092 if not pattern:
1093 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001094 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1095 if drv or root:
1096 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001097 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001098 for p in selector.select_from(self):
1099 yield p
1100
1101 def rglob(self, pattern):
1102 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001103 directories) matching the given relative pattern, anywhere in
1104 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001105 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001106 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001107 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1108 if drv or root:
1109 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001110 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001111 for p in selector.select_from(self):
1112 yield p
1113
1114 def absolute(self):
1115 """Return an absolute version of this path. This function works
1116 even if the path doesn't point to anything.
1117
1118 No normalization is done, i.e. all '.' and '..' will be kept along.
1119 Use resolve() to get the canonical path to a file.
1120 """
1121 # XXX untested yet!
Antoine Pitrou31119e42013-11-22 17:38:12 +01001122 if self.is_absolute():
1123 return self
1124 # FIXME this must defer to the specific flavour (and, under Windows,
1125 # use nt._getfullpathname())
Barney Galeb05440c2021-04-07 17:31:49 +01001126 return self._from_parts([self._accessor.getcwd()] + self._parts)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001127
Steve Dower98eb3602016-11-09 12:58:17 -08001128 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001129 """
1130 Make the path absolute, resolving all symlinks on the way and also
1131 normalizing it (for example turning slashes into backslashes under
1132 Windows).
1133 """
Steve Dower98eb3602016-11-09 12:58:17 -08001134 s = self._flavour.resolve(self, strict=strict)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001135 if s is None:
1136 # No symlink resolution => for consistency, raise an error if
1137 # the path doesn't exist or is forbidden
1138 self.stat()
1139 s = str(self.absolute())
1140 # Now we have no symlinks in the path, it's safe to normalize it.
1141 normed = self._flavour.pathmod.normpath(s)
Barney Gale22191872021-04-07 01:26:37 +01001142 return self._from_parts((normed,))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001143
Barney Galeabf96492021-04-07 16:53:39 +01001144 def stat(self, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001145 """
1146 Return the result of the stat() system call on this path, like
1147 os.stat() does.
1148 """
Barney Galeabf96492021-04-07 16:53:39 +01001149 return self._accessor.stat(self, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001150
1151 def owner(self):
1152 """
1153 Return the login name of the file owner.
1154 """
Barney Gale22386bb2020-04-17 17:41:07 +01001155 return self._accessor.owner(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001156
1157 def group(self):
1158 """
1159 Return the group name of the file gid.
1160 """
Barney Gale22386bb2020-04-17 17:41:07 +01001161 return self._accessor.group(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001162
Antoine Pitrou31119e42013-11-22 17:38:12 +01001163 def open(self, mode='r', buffering=-1, encoding=None,
1164 errors=None, newline=None):
1165 """
1166 Open the file pointed by this path and return a file object, as
1167 the built-in open() function does.
1168 """
Inada Naoki48274832021-03-29 12:28:14 +09001169 if "b" not in mode:
1170 encoding = io.text_encoding(encoding)
Barney Gale11c3bd32021-04-09 21:52:49 +01001171 return self._accessor.open(self, mode, buffering, encoding, errors,
1172 newline)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001173
Georg Brandlea683982014-10-01 19:12:33 +02001174 def read_bytes(self):
1175 """
1176 Open the file in bytes mode, read it, and close the file.
1177 """
1178 with self.open(mode='rb') as f:
1179 return f.read()
1180
1181 def read_text(self, encoding=None, errors=None):
1182 """
1183 Open the file in text mode, read it, and close the file.
1184 """
Inada Naoki48274832021-03-29 12:28:14 +09001185 encoding = io.text_encoding(encoding)
Georg Brandlea683982014-10-01 19:12:33 +02001186 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1187 return f.read()
1188
1189 def write_bytes(self, data):
1190 """
1191 Open the file in bytes mode, write to it, and close the file.
1192 """
1193 # type-check for the buffer interface before truncating the file
1194 view = memoryview(data)
1195 with self.open(mode='wb') as f:
1196 return f.write(view)
1197
Максим5f227412020-10-21 05:08:19 +03001198 def write_text(self, data, encoding=None, errors=None, newline=None):
Georg Brandlea683982014-10-01 19:12:33 +02001199 """
1200 Open the file in text mode, write to it, and close the file.
1201 """
1202 if not isinstance(data, str):
1203 raise TypeError('data must be str, not %s' %
1204 data.__class__.__name__)
Inada Naoki48274832021-03-29 12:28:14 +09001205 encoding = io.text_encoding(encoding)
Максим5f227412020-10-21 05:08:19 +03001206 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
Georg Brandlea683982014-10-01 19:12:33 +02001207 return f.write(data)
1208
Girtsa01ba332019-10-23 14:18:40 -07001209 def readlink(self):
1210 """
1211 Return the path to which the symbolic link points.
1212 """
1213 path = self._accessor.readlink(self)
Barney Gale22191872021-04-07 01:26:37 +01001214 return self._from_parts((path,))
Girtsa01ba332019-10-23 14:18:40 -07001215
Antoine Pitrou31119e42013-11-22 17:38:12 +01001216 def touch(self, mode=0o666, exist_ok=True):
1217 """
1218 Create this file with the given access mode, if it doesn't exist.
1219 """
Barney Gale986da8e2021-04-07 01:25:37 +01001220 self._accessor.touch(self, mode, exist_ok)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001221
Barry Warsaw7c549c42014-08-05 11:28:12 -04001222 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001223 """
1224 Create a new directory at this given path.
1225 """
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001226 try:
1227 self._accessor.mkdir(self, mode)
1228 except FileNotFoundError:
1229 if not parents or self.parent == self:
1230 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001231 self.parent.mkdir(parents=True, exist_ok=True)
1232 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001233 except OSError:
1234 # Cannot rely on checking for EEXIST, since the operating system
1235 # could give priority to other errors like EACCES or EROFS
1236 if not exist_ok or not self.is_dir():
1237 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001238
Barney Galeabf96492021-04-07 16:53:39 +01001239 def chmod(self, mode, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001240 """
1241 Change the permissions of the path, like os.chmod().
1242 """
Barney Galeabf96492021-04-07 16:53:39 +01001243 self._accessor.chmod(self, mode, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001244
1245 def lchmod(self, mode):
1246 """
1247 Like chmod(), except if the path points to a symlink, the symlink's
1248 permissions are changed, rather than its target's.
1249 """
Barney Galeabf96492021-04-07 16:53:39 +01001250 self.chmod(mode, follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001251
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001252 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001253 """
1254 Remove this file or link.
1255 If the path is a directory, use rmdir() instead.
1256 """
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001257 try:
1258 self._accessor.unlink(self)
1259 except FileNotFoundError:
1260 if not missing_ok:
1261 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001262
1263 def rmdir(self):
1264 """
1265 Remove this directory. The directory must be empty.
1266 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001267 self._accessor.rmdir(self)
1268
1269 def lstat(self):
1270 """
1271 Like stat(), except if the path points to a symlink, the symlink's
1272 status information is returned, rather than its target's.
1273 """
Barney Galeabf96492021-04-07 16:53:39 +01001274 return self.stat(follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001275
1276 def rename(self, target):
1277 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001278 Rename this path to the target path.
1279
1280 The target path may be absolute or relative. Relative paths are
1281 interpreted relative to the current working directory, *not* the
1282 directory of the Path object.
1283
1284 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001285 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001286 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001287 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001288
1289 def replace(self, target):
1290 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001291 Rename this path to the target path, overwriting if that path exists.
1292
1293 The target path may be absolute or relative. Relative paths are
1294 interpreted relative to the current working directory, *not* the
1295 directory of the Path object.
1296
1297 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001298 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001299 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001300 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001301
1302 def symlink_to(self, target, target_is_directory=False):
1303 """
Barney Gale8aac1be2021-04-07 16:56:32 +01001304 Make this path a symlink pointing to the target path.
1305 Note the order of arguments (link, target) is the reverse of os.symlink.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001306 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001307 self._accessor.symlink(target, self, target_is_directory)
1308
Barney Gale8aac1be2021-04-07 16:56:32 +01001309 def link_to(self, target):
1310 """
1311 Make the target path a hard link pointing to this path.
1312
1313 Note this function does not make this path a hard link to *target*,
1314 despite the implication of the function and argument names. The order
1315 of arguments (target, link) is the reverse of Path.symlink_to, but
1316 matches that of os.link.
1317
1318 """
1319 self._accessor.link(self, target)
1320
Antoine Pitrou31119e42013-11-22 17:38:12 +01001321 # Convenience functions for querying the stat results
1322
1323 def exists(self):
1324 """
1325 Whether this path exists.
1326 """
1327 try:
1328 self.stat()
1329 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001330 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001331 raise
1332 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001333 except ValueError:
1334 # Non-encodable path
1335 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001336 return True
1337
1338 def is_dir(self):
1339 """
1340 Whether this path is a directory.
1341 """
1342 try:
1343 return S_ISDIR(self.stat().st_mode)
1344 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001345 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001346 raise
1347 # Path doesn't exist or is a broken symlink
1348 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1349 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001350 except ValueError:
1351 # Non-encodable path
1352 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001353
1354 def is_file(self):
1355 """
1356 Whether this path is a regular file (also True for symlinks pointing
1357 to regular files).
1358 """
1359 try:
1360 return S_ISREG(self.stat().st_mode)
1361 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001362 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001363 raise
1364 # Path doesn't exist or is a broken symlink
1365 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1366 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001367 except ValueError:
1368 # Non-encodable path
1369 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001370
Cooper Lees173ff4a2017-08-01 15:35:45 -07001371 def is_mount(self):
1372 """
1373 Check if this path is a POSIX mount point
1374 """
1375 # Need to exist and be a dir
1376 if not self.exists() or not self.is_dir():
1377 return False
1378
Cooper Lees173ff4a2017-08-01 15:35:45 -07001379 try:
Barney Galec746c4f2020-04-17 18:42:06 +01001380 parent_dev = self.parent.stat().st_dev
Cooper Lees173ff4a2017-08-01 15:35:45 -07001381 except OSError:
1382 return False
1383
1384 dev = self.stat().st_dev
1385 if dev != parent_dev:
1386 return True
1387 ino = self.stat().st_ino
Barney Galec746c4f2020-04-17 18:42:06 +01001388 parent_ino = self.parent.stat().st_ino
Cooper Lees173ff4a2017-08-01 15:35:45 -07001389 return ino == parent_ino
1390
Antoine Pitrou31119e42013-11-22 17:38:12 +01001391 def is_symlink(self):
1392 """
1393 Whether this path is a symbolic link.
1394 """
1395 try:
1396 return S_ISLNK(self.lstat().st_mode)
1397 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001398 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001399 raise
1400 # Path doesn't exist
1401 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001402 except ValueError:
1403 # Non-encodable path
1404 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001405
1406 def is_block_device(self):
1407 """
1408 Whether this path is a block device.
1409 """
1410 try:
1411 return S_ISBLK(self.stat().st_mode)
1412 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001413 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001414 raise
1415 # Path doesn't exist or is a broken symlink
1416 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1417 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001418 except ValueError:
1419 # Non-encodable path
1420 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001421
1422 def is_char_device(self):
1423 """
1424 Whether this path is a character device.
1425 """
1426 try:
1427 return S_ISCHR(self.stat().st_mode)
1428 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001429 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001430 raise
1431 # Path doesn't exist or is a broken symlink
1432 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1433 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001434 except ValueError:
1435 # Non-encodable path
1436 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001437
1438 def is_fifo(self):
1439 """
1440 Whether this path is a FIFO.
1441 """
1442 try:
1443 return S_ISFIFO(self.stat().st_mode)
1444 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001445 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001446 raise
1447 # Path doesn't exist or is a broken symlink
1448 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1449 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001450 except ValueError:
1451 # Non-encodable path
1452 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001453
1454 def is_socket(self):
1455 """
1456 Whether this path is a socket.
1457 """
1458 try:
1459 return S_ISSOCK(self.stat().st_mode)
1460 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001461 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001462 raise
1463 # Path doesn't exist or is a broken symlink
1464 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1465 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001466 except ValueError:
1467 # Non-encodable path
1468 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001469
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001470 def expanduser(self):
1471 """ Return a new path with expanded ~ and ~user constructs
1472 (as returned by os.path.expanduser)
1473 """
1474 if (not (self._drv or self._root) and
1475 self._parts and self._parts[0][:1] == '~'):
Barney Gale3f3d82b2021-04-07 23:50:13 +01001476 homedir = self._accessor.expanduser(self._parts[0])
1477 if homedir[:1] == "~":
1478 raise RuntimeError("Could not determine home directory.")
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001479 return self._from_parts([homedir] + self._parts[1:])
1480
1481 return self
1482
Antoine Pitrou31119e42013-11-22 17:38:12 +01001483
1484class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001485 """Path subclass for non-Windows systems.
1486
1487 On a POSIX system, instantiating a Path should return this object.
1488 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001489 __slots__ = ()
1490
1491class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001492 """Path subclass for Windows systems.
1493
1494 On a Windows system, instantiating a Path should return this object.
1495 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001496 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001497
Cooper Lees173ff4a2017-08-01 15:35:45 -07001498 def is_mount(self):
1499 raise NotImplementedError("Path.is_mount() is unsupported on this system")