blob: 1518d49f2212b2828a4a757ee4ef5532bdd39794 [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:
Barney Galeb05440c2021-04-07 17:31:49 +0100190 return path._accessor.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
249
250class _PosixFlavour(_Flavour):
251 sep = '/'
252 altsep = ''
253 has_drv = False
254 pathmod = posixpath
255
256 is_supported = (os.name != 'nt')
257
258 def splitroot(self, part, sep=sep):
259 if part and part[0] == sep:
260 stripped_part = part.lstrip(sep)
261 # According to POSIX path resolution:
262 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
263 # "A pathname that begins with two successive slashes may be
264 # interpreted in an implementation-defined manner, although more
265 # than two leading slashes shall be treated as a single slash".
266 if len(part) - len(stripped_part) == 2:
267 return '', sep * 2, stripped_part
268 else:
269 return '', sep, stripped_part
270 else:
271 return '', '', part
272
273 def casefold(self, s):
274 return s
275
276 def casefold_parts(self, parts):
277 return parts
278
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300279 def compile_pattern(self, pattern):
280 return re.compile(fnmatch.translate(pattern)).fullmatch
281
Steve Dower98eb3602016-11-09 12:58:17 -0800282 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100283 sep = self.sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100284 accessor = path._accessor
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100285 seen = {}
286 def _resolve(path, rest):
287 if rest.startswith(sep):
288 path = ''
289
290 for name in rest.split(sep):
291 if not name or name == '.':
292 # current dir
293 continue
294 if name == '..':
295 # parent dir
296 path, _, _ = path.rpartition(sep)
297 continue
Dong-hee Na94ad6c62018-06-12 23:30:45 +0900298 if path.endswith(sep):
299 newpath = path + name
300 else:
301 newpath = path + sep + name
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100302 if newpath in seen:
303 # Already seen this path
304 path = seen[newpath]
305 if path is not None:
306 # use cached value
307 continue
308 # The symlink is not resolved, so we must have a symlink loop.
309 raise RuntimeError("Symlink loop from %r" % newpath)
310 # Resolve the symbolic link
311 try:
312 target = accessor.readlink(newpath)
313 except OSError as e:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200314 if e.errno != EINVAL and strict:
315 raise
316 # Not a symlink, or non-strict mode. We just leave the path
317 # untouched.
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100318 path = newpath
319 else:
320 seen[newpath] = None # not resolved symlink
321 path = _resolve(path, target)
322 seen[newpath] = path # resolved symlink
323
324 return path
325 # NOTE: according to POSIX, getcwd() cannot contain path components
326 # which are symlinks.
Barney Galeb05440c2021-04-07 17:31:49 +0100327 base = '' if path.is_absolute() else accessor.getcwd()
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100328 return _resolve(base, str(path)) or sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100329
330 def is_reserved(self, parts):
331 return False
332
333 def make_uri(self, path):
334 # We represent the path using the local filesystem encoding,
335 # for portability to other applications.
336 bpath = bytes(path)
337 return 'file://' + urlquote_from_bytes(bpath)
338
339
340_windows_flavour = _WindowsFlavour()
341_posix_flavour = _PosixFlavour()
342
343
344class _Accessor:
345 """An accessor implements a particular (system-specific or not) way of
346 accessing paths on the filesystem."""
347
348
349class _NormalAccessor(_Accessor):
350
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200351 stat = os.stat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100352
Barney Gale11c3bd32021-04-09 21:52:49 +0100353 open = io.open
Antoine Pitrou31119e42013-11-22 17:38:12 +0100354
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200355 listdir = os.listdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100356
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200357 scandir = os.scandir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100358
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200359 chmod = os.chmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100360
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200361 mkdir = os.mkdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100362
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200363 unlink = os.unlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100364
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100365 if hasattr(os, "link"):
Barney Galeb57e0452021-04-07 00:01:22 +0100366 link = os.link
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100367 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100368 def link(self, src, dst):
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100369 raise NotImplementedError("os.link() not available on this system")
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -0400370
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200371 rmdir = os.rmdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100372
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200373 rename = os.rename
Antoine Pitrou31119e42013-11-22 17:38:12 +0100374
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200375 replace = os.replace
Antoine Pitrou31119e42013-11-22 17:38:12 +0100376
Barney Galeb57e0452021-04-07 00:01:22 +0100377 if hasattr(os, "symlink"):
378 symlink = os.symlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100379 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100380 def symlink(self, src, dst, target_is_directory=False):
381 raise NotImplementedError("os.symlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100382
Barney Gale986da8e2021-04-07 01:25:37 +0100383 def touch(self, path, mode=0o666, exist_ok=True):
384 if exist_ok:
385 # First try to bump modification time
386 # Implementation note: GNU touch uses the UTIME_NOW option of
387 # the utimensat() / futimens() functions.
388 try:
389 os.utime(path, None)
390 except OSError:
391 # Avoid exception chaining
392 pass
393 else:
394 return
395 flags = os.O_CREAT | os.O_WRONLY
396 if not exist_ok:
397 flags |= os.O_EXCL
398 fd = os.open(path, flags, mode)
399 os.close(fd)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100400
Barney Galeb57e0452021-04-07 00:01:22 +0100401 if hasattr(os, "readlink"):
402 readlink = os.readlink
403 else:
404 def readlink(self, path):
405 raise NotImplementedError("os.readlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100406
Barney Gale22386bb2020-04-17 17:41:07 +0100407 def owner(self, path):
408 try:
409 import pwd
410 return pwd.getpwuid(self.stat(path).st_uid).pw_name
411 except ImportError:
412 raise NotImplementedError("Path.owner() is unsupported on this system")
413
414 def group(self, path):
415 try:
416 import grp
417 return grp.getgrgid(self.stat(path).st_gid).gr_name
418 except ImportError:
419 raise NotImplementedError("Path.group() is unsupported on this system")
420
Barney Galeb05440c2021-04-07 17:31:49 +0100421 getcwd = os.getcwd
422
Barney Gale3f3d82b2021-04-07 23:50:13 +0100423 expanduser = staticmethod(os.path.expanduser)
424
Antoine Pitrou31119e42013-11-22 17:38:12 +0100425
426_normal_accessor = _NormalAccessor()
427
428
429#
430# Globbing helpers
431#
432
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300433def _make_selector(pattern_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100434 pat = pattern_parts[0]
435 child_parts = pattern_parts[1:]
436 if pat == '**':
437 cls = _RecursiveWildcardSelector
438 elif '**' in pat:
439 raise ValueError("Invalid pattern: '**' can only be an entire path component")
440 elif _is_wildcard_pattern(pat):
441 cls = _WildcardSelector
442 else:
443 cls = _PreciseSelector
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300444 return cls(pat, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100445
446if hasattr(functools, "lru_cache"):
447 _make_selector = functools.lru_cache()(_make_selector)
448
449
450class _Selector:
451 """A selector matches a specific glob pattern part against the children
452 of a given path."""
453
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300454 def __init__(self, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100455 self.child_parts = child_parts
456 if child_parts:
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300457 self.successor = _make_selector(child_parts, flavour)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300458 self.dironly = True
Antoine Pitrou31119e42013-11-22 17:38:12 +0100459 else:
460 self.successor = _TerminatingSelector()
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300461 self.dironly = False
Antoine Pitrou31119e42013-11-22 17:38:12 +0100462
463 def select_from(self, parent_path):
464 """Iterate over all child paths of `parent_path` matched by this
465 selector. This can contain parent_path itself."""
466 path_cls = type(parent_path)
467 is_dir = path_cls.is_dir
468 exists = path_cls.exists
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300469 scandir = parent_path._accessor.scandir
470 if not is_dir(parent_path):
471 return iter([])
472 return self._select_from(parent_path, is_dir, exists, scandir)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100473
474
475class _TerminatingSelector:
476
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300477 def _select_from(self, parent_path, is_dir, exists, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100478 yield parent_path
479
480
481class _PreciseSelector(_Selector):
482
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300483 def __init__(self, name, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100484 self.name = name
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300485 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100486
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300487 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800488 try:
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800489 path = parent_path._make_child_relpath(self.name)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300490 if (is_dir if self.dironly else exists)(path):
491 for p in self.successor._select_from(path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800492 yield p
493 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100494 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100495
496
497class _WildcardSelector(_Selector):
498
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300499 def __init__(self, pat, child_parts, flavour):
500 self.match = flavour.compile_pattern(pat)
501 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100502
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300503 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800504 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200505 with scandir(parent_path) as scandir_it:
506 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300507 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000508 if self.dironly:
509 try:
510 # "entry.is_dir()" can raise PermissionError
511 # in some cases (see bpo-38894), which is not
512 # among the errors ignored by _ignore_error()
513 if not entry.is_dir():
514 continue
515 except OSError as e:
516 if not _ignore_error(e):
517 raise
518 continue
519 name = entry.name
520 if self.match(name):
521 path = parent_path._make_child_relpath(name)
522 for p in self.successor._select_from(path, is_dir, exists, scandir):
523 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800524 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100525 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800526
Antoine Pitrou31119e42013-11-22 17:38:12 +0100527
Antoine Pitrou31119e42013-11-22 17:38:12 +0100528class _RecursiveWildcardSelector(_Selector):
529
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300530 def __init__(self, pat, child_parts, flavour):
531 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100532
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300533 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100534 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -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:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200539 entry_is_dir = False
540 try:
541 entry_is_dir = entry.is_dir()
542 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800543 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200544 raise
545 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300546 path = parent_path._make_child_relpath(entry.name)
547 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800548 yield p
549 except PermissionError:
550 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100551
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300552 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800553 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300554 yielded = set()
555 try:
556 successor_select = self.successor._select_from
557 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
558 for p in successor_select(starting_point, is_dir, exists, scandir):
559 if p not in yielded:
560 yield p
561 yielded.add(p)
562 finally:
563 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800564 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100565 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100566
567
568#
569# Public API
570#
571
572class _PathParents(Sequence):
573 """This object provides sequence-like access to the logical ancestors
574 of a path. Don't try to construct it yourself."""
575 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
576
577 def __init__(self, path):
578 # We don't store the instance to avoid reference cycles
579 self._pathcls = type(path)
580 self._drv = path._drv
581 self._root = path._root
582 self._parts = path._parts
583
584 def __len__(self):
585 if self._drv or self._root:
586 return len(self._parts) - 1
587 else:
588 return len(self._parts)
589
590 def __getitem__(self, idx):
Joshua Cannon45205842020-11-20 09:40:39 -0600591 if isinstance(idx, slice):
592 return tuple(self[i] for i in range(*idx.indices(len(self))))
Yaroslav Pankovych79d2e622020-11-23 22:06:22 +0200593
594 if idx >= len(self) or idx < -len(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100595 raise IndexError(idx)
596 return self._pathcls._from_parsed_parts(self._drv, self._root,
597 self._parts[:-idx - 1])
598
599 def __repr__(self):
600 return "<{}.parents>".format(self._pathcls.__name__)
601
602
603class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900604 """Base class for manipulating paths without I/O.
605
606 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100607 don't imply any actual filesystem I/O. Depending on your system,
608 instantiating a PurePath will return either a PurePosixPath or a
609 PureWindowsPath object. You can also instantiate either of these classes
610 directly, regardless of your system.
611 """
612 __slots__ = (
613 '_drv', '_root', '_parts',
614 '_str', '_hash', '_pparts', '_cached_cparts',
615 )
616
617 def __new__(cls, *args):
618 """Construct a PurePath from one or several strings and or existing
619 PurePath objects. The strings and path objects are combined so as
620 to yield a canonicalized path, which is incorporated into the
621 new PurePath object.
622 """
623 if cls is PurePath:
624 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
625 return cls._from_parts(args)
626
627 def __reduce__(self):
628 # Using the parts tuple helps share interned path parts
629 # when pickling related paths.
630 return (self.__class__, tuple(self._parts))
631
632 @classmethod
633 def _parse_args(cls, args):
634 # This is useful when you don't want to create an instance, just
635 # canonicalize some constructor arguments.
636 parts = []
637 for a in args:
638 if isinstance(a, PurePath):
639 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100640 else:
Brett Cannon568be632016-06-10 12:20:49 -0700641 a = os.fspath(a)
642 if isinstance(a, str):
643 # Force-cast str subclasses to str (issue #21127)
644 parts.append(str(a))
645 else:
646 raise TypeError(
647 "argument should be a str object or an os.PathLike "
648 "object returning str, not %r"
649 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100650 return cls._flavour.parse_parts(parts)
651
652 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100653 def _from_parts(cls, args):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100654 # We need to call _parse_args on the instance, so as to get the
655 # right flavour.
656 self = object.__new__(cls)
657 drv, root, parts = self._parse_args(args)
658 self._drv = drv
659 self._root = root
660 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100661 return self
662
663 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100664 def _from_parsed_parts(cls, drv, root, parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100665 self = object.__new__(cls)
666 self._drv = drv
667 self._root = root
668 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100669 return self
670
671 @classmethod
672 def _format_parsed_parts(cls, drv, root, parts):
673 if drv or root:
674 return drv + root + cls._flavour.join(parts[1:])
675 else:
676 return cls._flavour.join(parts)
677
Antoine Pitrou31119e42013-11-22 17:38:12 +0100678 def _make_child(self, args):
679 drv, root, parts = self._parse_args(args)
680 drv, root, parts = self._flavour.join_parsed_parts(
681 self._drv, self._root, self._parts, drv, root, parts)
682 return self._from_parsed_parts(drv, root, parts)
683
684 def __str__(self):
685 """Return the string representation of the path, suitable for
686 passing to system calls."""
687 try:
688 return self._str
689 except AttributeError:
690 self._str = self._format_parsed_parts(self._drv, self._root,
691 self._parts) or '.'
692 return self._str
693
Brett Cannon568be632016-06-10 12:20:49 -0700694 def __fspath__(self):
695 return str(self)
696
Antoine Pitrou31119e42013-11-22 17:38:12 +0100697 def as_posix(self):
698 """Return the string representation of the path with forward (/)
699 slashes."""
700 f = self._flavour
701 return str(self).replace(f.sep, '/')
702
703 def __bytes__(self):
704 """Return the bytes representation of the path. This is only
705 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200706 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100707
708 def __repr__(self):
709 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
710
711 def as_uri(self):
712 """Return the path as a 'file' URI."""
713 if not self.is_absolute():
714 raise ValueError("relative path can't be expressed as a file URI")
715 return self._flavour.make_uri(self)
716
717 @property
718 def _cparts(self):
719 # Cached casefolded parts, for hashing and comparison
720 try:
721 return self._cached_cparts
722 except AttributeError:
723 self._cached_cparts = self._flavour.casefold_parts(self._parts)
724 return self._cached_cparts
725
726 def __eq__(self, other):
727 if not isinstance(other, PurePath):
728 return NotImplemented
729 return self._cparts == other._cparts and self._flavour is other._flavour
730
Antoine Pitrou31119e42013-11-22 17:38:12 +0100731 def __hash__(self):
732 try:
733 return self._hash
734 except AttributeError:
735 self._hash = hash(tuple(self._cparts))
736 return self._hash
737
738 def __lt__(self, other):
739 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
740 return NotImplemented
741 return self._cparts < other._cparts
742
743 def __le__(self, other):
744 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
745 return NotImplemented
746 return self._cparts <= other._cparts
747
748 def __gt__(self, other):
749 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
750 return NotImplemented
751 return self._cparts > other._cparts
752
753 def __ge__(self, other):
754 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
755 return NotImplemented
756 return self._cparts >= other._cparts
757
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300758 def __class_getitem__(cls, type):
759 return cls
760
Antoine Pitrou31119e42013-11-22 17:38:12 +0100761 drive = property(attrgetter('_drv'),
762 doc="""The drive prefix (letter or UNC path), if any.""")
763
764 root = property(attrgetter('_root'),
765 doc="""The root of the path, if any.""")
766
767 @property
768 def anchor(self):
769 """The concatenation of the drive and root, or ''."""
770 anchor = self._drv + self._root
771 return anchor
772
773 @property
774 def name(self):
775 """The final path component, if any."""
776 parts = self._parts
777 if len(parts) == (1 if (self._drv or self._root) else 0):
778 return ''
779 return parts[-1]
780
781 @property
782 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200783 """
784 The final component's last suffix, if any.
785
786 This includes the leading period. For example: '.txt'
787 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100788 name = self.name
789 i = name.rfind('.')
790 if 0 < i < len(name) - 1:
791 return name[i:]
792 else:
793 return ''
794
795 @property
796 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200797 """
798 A list of the final component's suffixes, if any.
799
800 These include the leading periods. For example: ['.tar', '.gz']
801 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100802 name = self.name
803 if name.endswith('.'):
804 return []
805 name = name.lstrip('.')
806 return ['.' + suffix for suffix in name.split('.')[1:]]
807
808 @property
809 def stem(self):
810 """The final path component, minus its last suffix."""
811 name = self.name
812 i = name.rfind('.')
813 if 0 < i < len(name) - 1:
814 return name[:i]
815 else:
816 return name
817
818 def with_name(self, name):
819 """Return a new path with the file name changed."""
820 if not self.name:
821 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400822 drv, root, parts = self._flavour.parse_parts((name,))
823 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
824 or drv or root or len(parts) != 1):
825 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100826 return self._from_parsed_parts(self._drv, self._root,
827 self._parts[:-1] + [name])
828
Tim Hoffmann8aea4b32020-04-19 17:29:49 +0200829 def with_stem(self, stem):
830 """Return a new path with the stem changed."""
831 return self.with_name(stem + self.suffix)
832
Antoine Pitrou31119e42013-11-22 17:38:12 +0100833 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200834 """Return a new path with the file suffix changed. If the path
835 has no suffix, add given suffix. If the given suffix is an empty
836 string, remove the suffix from the path.
837 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400838 f = self._flavour
839 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300840 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400841 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100842 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100843 name = self.name
844 if not name:
845 raise ValueError("%r has an empty name" % (self,))
846 old_suffix = self.suffix
847 if not old_suffix:
848 name = name + suffix
849 else:
850 name = name[:-len(old_suffix)] + suffix
851 return self._from_parsed_parts(self._drv, self._root,
852 self._parts[:-1] + [name])
853
854 def relative_to(self, *other):
855 """Return the relative path to another path identified by the passed
856 arguments. If the operation is not possible (because this is not
857 a subpath of the other path), raise ValueError.
858 """
859 # For the purpose of this method, drive and root are considered
860 # separate parts, i.e.:
861 # Path('c:/').relative_to('c:') gives Path('/')
862 # Path('c:/').relative_to('/') raise ValueError
863 if not other:
864 raise TypeError("need at least one argument")
865 parts = self._parts
866 drv = self._drv
867 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100868 if root:
869 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100870 else:
871 abs_parts = parts
872 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100873 if to_root:
874 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100875 else:
876 to_abs_parts = to_parts
877 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100878 cf = self._flavour.casefold_parts
879 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100880 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
Rotuna44832532020-05-25 21:42:28 +0200881 raise ValueError("{!r} is not in the subpath of {!r}"
882 " OR one path is relative and the other is absolute."
Antoine Pitrou31119e42013-11-22 17:38:12 +0100883 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100884 return self._from_parsed_parts('', root if n == 1 else '',
885 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100886
Hai Shi82642a02019-08-13 14:54:02 -0500887 def is_relative_to(self, *other):
888 """Return True if the path is relative to another path or False.
889 """
890 try:
891 self.relative_to(*other)
892 return True
893 except ValueError:
894 return False
895
Antoine Pitrou31119e42013-11-22 17:38:12 +0100896 @property
897 def parts(self):
898 """An object providing sequence-like access to the
899 components in the filesystem path."""
900 # We cache the tuple to avoid building a new one each time .parts
901 # is accessed. XXX is this necessary?
902 try:
903 return self._pparts
904 except AttributeError:
905 self._pparts = tuple(self._parts)
906 return self._pparts
907
908 def joinpath(self, *args):
909 """Combine this path with one or several arguments, and return a
910 new path representing either a subpath (if all arguments are relative
911 paths) or a totally different path (if one of the arguments is
912 anchored).
913 """
914 return self._make_child(args)
915
916 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400917 try:
918 return self._make_child((key,))
919 except TypeError:
920 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100921
922 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400923 try:
924 return self._from_parts([key] + self._parts)
925 except TypeError:
926 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100927
928 @property
929 def parent(self):
930 """The logical parent of the path."""
931 drv = self._drv
932 root = self._root
933 parts = self._parts
934 if len(parts) == 1 and (drv or root):
935 return self
936 return self._from_parsed_parts(drv, root, parts[:-1])
937
938 @property
939 def parents(self):
940 """A sequence of this path's logical parents."""
941 return _PathParents(self)
942
943 def is_absolute(self):
944 """True if the path is absolute (has both a root and, if applicable,
945 a drive)."""
946 if not self._root:
947 return False
948 return not self._flavour.has_drv or bool(self._drv)
949
950 def is_reserved(self):
951 """Return True if the path contains one of the special names reserved
952 by the system, if any."""
953 return self._flavour.is_reserved(self._parts)
954
955 def match(self, path_pattern):
956 """
957 Return True if this path matches the given pattern.
958 """
959 cf = self._flavour.casefold
960 path_pattern = cf(path_pattern)
961 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
962 if not pat_parts:
963 raise ValueError("empty pattern")
964 if drv and drv != cf(self._drv):
965 return False
966 if root and root != cf(self._root):
967 return False
968 parts = self._cparts
969 if drv or root:
970 if len(pat_parts) != len(parts):
971 return False
972 pat_parts = pat_parts[1:]
973 elif len(pat_parts) > len(parts):
974 return False
975 for part, pat in zip(reversed(parts), reversed(pat_parts)):
976 if not fnmatch.fnmatchcase(part, pat):
977 return False
978 return True
979
Brett Cannon568be632016-06-10 12:20:49 -0700980# Can't subclass os.PathLike from PurePath and keep the constructor
981# optimizations in PurePath._parse_args().
982os.PathLike.register(PurePath)
983
Antoine Pitrou31119e42013-11-22 17:38:12 +0100984
985class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900986 """PurePath subclass for non-Windows systems.
987
988 On a POSIX system, instantiating a PurePath should return this object.
989 However, you can also instantiate it directly on any system.
990 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100991 _flavour = _posix_flavour
992 __slots__ = ()
993
994
995class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900996 """PurePath subclass for Windows systems.
997
998 On a Windows system, instantiating a PurePath should return this object.
999 However, you can also instantiate it directly on any system.
1000 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001001 _flavour = _windows_flavour
1002 __slots__ = ()
1003
1004
1005# Filesystem-accessing classes
1006
1007
1008class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001009 """PurePath subclass that can make system calls.
1010
1011 Path represents a filesystem path but unlike PurePath, also offers
1012 methods to do system calls on path objects. Depending on your system,
1013 instantiating a Path will return either a PosixPath or a WindowsPath
1014 object. You can also instantiate a PosixPath or WindowsPath directly,
1015 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1016 """
Barney Gale22191872021-04-07 01:26:37 +01001017 _accessor = _normal_accessor
1018 __slots__ = ()
Antoine Pitrou31119e42013-11-22 17:38:12 +01001019
1020 def __new__(cls, *args, **kwargs):
1021 if cls is Path:
1022 cls = WindowsPath if os.name == 'nt' else PosixPath
Barney Gale22191872021-04-07 01:26:37 +01001023 self = cls._from_parts(args)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001024 if not self._flavour.is_supported:
1025 raise NotImplementedError("cannot instantiate %r on your system"
1026 % (cls.__name__,))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001027 return self
1028
Antoine Pitrou31119e42013-11-22 17:38:12 +01001029 def _make_child_relpath(self, part):
1030 # This is an optimization used for dir walking. `part` must be
1031 # a single part relative to this path.
1032 parts = self._parts + [part]
1033 return self._from_parsed_parts(self._drv, self._root, parts)
1034
1035 def __enter__(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001036 return self
1037
1038 def __exit__(self, t, v, tb):
Barney Gale00002e62020-04-01 15:10:51 +01001039 # https://bugs.python.org/issue39682
1040 # In previous versions of pathlib, this method marked this path as
1041 # closed; subsequent attempts to perform I/O would raise an IOError.
1042 # This functionality was never documented, and had the effect of
1043 # making Path objects mutable, contrary to PEP 428. In Python 3.9 the
1044 # _closed attribute was removed, and this method made a no-op.
1045 # This method and __enter__()/__exit__() should be deprecated and
1046 # removed in the future.
1047 pass
Antoine Pitrou31119e42013-11-22 17:38:12 +01001048
Antoine Pitrou31119e42013-11-22 17:38:12 +01001049 # Public API
1050
1051 @classmethod
1052 def cwd(cls):
1053 """Return a new path pointing to the current working directory
1054 (as returned by os.getcwd()).
1055 """
Barney Galeb05440c2021-04-07 17:31:49 +01001056 return cls(cls()._accessor.getcwd())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001057
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001058 @classmethod
1059 def home(cls):
1060 """Return a new path pointing to the user's home directory (as
1061 returned by os.path.expanduser('~')).
1062 """
Barney Gale3f3d82b2021-04-07 23:50:13 +01001063 return cls("~").expanduser()
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001064
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001065 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001066 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001067 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001068 """
1069 st = self.stat()
1070 try:
1071 other_st = other_path.stat()
1072 except AttributeError:
Barney Gale5b1d9182020-04-17 18:47:27 +01001073 other_st = self._accessor.stat(other_path)
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001074 return os.path.samestat(st, other_st)
1075
Antoine Pitrou31119e42013-11-22 17:38:12 +01001076 def iterdir(self):
1077 """Iterate over the files in this directory. Does not yield any
1078 result for the special paths '.' and '..'.
1079 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001080 for name in self._accessor.listdir(self):
1081 if name in {'.', '..'}:
1082 # Yielding a path object for these makes little sense
1083 continue
1084 yield self._make_child_relpath(name)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001085
1086 def glob(self, pattern):
1087 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001088 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001089 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001090 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001091 if not pattern:
1092 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001093 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1094 if drv or root:
1095 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001096 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001097 for p in selector.select_from(self):
1098 yield p
1099
1100 def rglob(self, pattern):
1101 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001102 directories) matching the given relative pattern, anywhere in
1103 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001104 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001105 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001106 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1107 if drv or root:
1108 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001109 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001110 for p in selector.select_from(self):
1111 yield p
1112
1113 def absolute(self):
1114 """Return an absolute version of this path. This function works
1115 even if the path doesn't point to anything.
1116
1117 No normalization is done, i.e. all '.' and '..' will be kept along.
1118 Use resolve() to get the canonical path to a file.
1119 """
1120 # XXX untested yet!
Antoine Pitrou31119e42013-11-22 17:38:12 +01001121 if self.is_absolute():
1122 return self
1123 # FIXME this must defer to the specific flavour (and, under Windows,
1124 # use nt._getfullpathname())
Barney Galeb05440c2021-04-07 17:31:49 +01001125 return self._from_parts([self._accessor.getcwd()] + self._parts)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001126
Steve Dower98eb3602016-11-09 12:58:17 -08001127 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001128 """
1129 Make the path absolute, resolving all symlinks on the way and also
1130 normalizing it (for example turning slashes into backslashes under
1131 Windows).
1132 """
Steve Dower98eb3602016-11-09 12:58:17 -08001133 s = self._flavour.resolve(self, strict=strict)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001134 if s is None:
1135 # No symlink resolution => for consistency, raise an error if
1136 # the path doesn't exist or is forbidden
1137 self.stat()
1138 s = str(self.absolute())
1139 # Now we have no symlinks in the path, it's safe to normalize it.
1140 normed = self._flavour.pathmod.normpath(s)
Barney Gale22191872021-04-07 01:26:37 +01001141 return self._from_parts((normed,))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001142
Barney Galeabf96492021-04-07 16:53:39 +01001143 def stat(self, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001144 """
1145 Return the result of the stat() system call on this path, like
1146 os.stat() does.
1147 """
Barney Galeabf96492021-04-07 16:53:39 +01001148 return self._accessor.stat(self, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001149
1150 def owner(self):
1151 """
1152 Return the login name of the file owner.
1153 """
Barney Gale22386bb2020-04-17 17:41:07 +01001154 return self._accessor.owner(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001155
1156 def group(self):
1157 """
1158 Return the group name of the file gid.
1159 """
Barney Gale22386bb2020-04-17 17:41:07 +01001160 return self._accessor.group(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001161
Antoine Pitrou31119e42013-11-22 17:38:12 +01001162 def open(self, mode='r', buffering=-1, encoding=None,
1163 errors=None, newline=None):
1164 """
1165 Open the file pointed by this path and return a file object, as
1166 the built-in open() function does.
1167 """
Inada Naoki48274832021-03-29 12:28:14 +09001168 if "b" not in mode:
1169 encoding = io.text_encoding(encoding)
Barney Gale11c3bd32021-04-09 21:52:49 +01001170 return self._accessor.open(self, mode, buffering, encoding, errors,
1171 newline)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001172
Georg Brandlea683982014-10-01 19:12:33 +02001173 def read_bytes(self):
1174 """
1175 Open the file in bytes mode, read it, and close the file.
1176 """
1177 with self.open(mode='rb') as f:
1178 return f.read()
1179
1180 def read_text(self, encoding=None, errors=None):
1181 """
1182 Open the file in text mode, read it, and close the file.
1183 """
Inada Naoki48274832021-03-29 12:28:14 +09001184 encoding = io.text_encoding(encoding)
Georg Brandlea683982014-10-01 19:12:33 +02001185 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1186 return f.read()
1187
1188 def write_bytes(self, data):
1189 """
1190 Open the file in bytes mode, write to it, and close the file.
1191 """
1192 # type-check for the buffer interface before truncating the file
1193 view = memoryview(data)
1194 with self.open(mode='wb') as f:
1195 return f.write(view)
1196
Максим5f227412020-10-21 05:08:19 +03001197 def write_text(self, data, encoding=None, errors=None, newline=None):
Georg Brandlea683982014-10-01 19:12:33 +02001198 """
1199 Open the file in text mode, write to it, and close the file.
1200 """
1201 if not isinstance(data, str):
1202 raise TypeError('data must be str, not %s' %
1203 data.__class__.__name__)
Inada Naoki48274832021-03-29 12:28:14 +09001204 encoding = io.text_encoding(encoding)
Максим5f227412020-10-21 05:08:19 +03001205 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
Georg Brandlea683982014-10-01 19:12:33 +02001206 return f.write(data)
1207
Girtsa01ba332019-10-23 14:18:40 -07001208 def readlink(self):
1209 """
1210 Return the path to which the symbolic link points.
1211 """
1212 path = self._accessor.readlink(self)
Barney Gale22191872021-04-07 01:26:37 +01001213 return self._from_parts((path,))
Girtsa01ba332019-10-23 14:18:40 -07001214
Antoine Pitrou31119e42013-11-22 17:38:12 +01001215 def touch(self, mode=0o666, exist_ok=True):
1216 """
1217 Create this file with the given access mode, if it doesn't exist.
1218 """
Barney Gale986da8e2021-04-07 01:25:37 +01001219 self._accessor.touch(self, mode, exist_ok)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001220
Barry Warsaw7c549c42014-08-05 11:28:12 -04001221 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001222 """
1223 Create a new directory at this given path.
1224 """
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001225 try:
1226 self._accessor.mkdir(self, mode)
1227 except FileNotFoundError:
1228 if not parents or self.parent == self:
1229 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001230 self.parent.mkdir(parents=True, exist_ok=True)
1231 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001232 except OSError:
1233 # Cannot rely on checking for EEXIST, since the operating system
1234 # could give priority to other errors like EACCES or EROFS
1235 if not exist_ok or not self.is_dir():
1236 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001237
Barney Galeabf96492021-04-07 16:53:39 +01001238 def chmod(self, mode, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001239 """
1240 Change the permissions of the path, like os.chmod().
1241 """
Barney Galeabf96492021-04-07 16:53:39 +01001242 self._accessor.chmod(self, mode, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001243
1244 def lchmod(self, mode):
1245 """
1246 Like chmod(), except if the path points to a symlink, the symlink's
1247 permissions are changed, rather than its target's.
1248 """
Barney Galeabf96492021-04-07 16:53:39 +01001249 self.chmod(mode, follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001250
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001251 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001252 """
1253 Remove this file or link.
1254 If the path is a directory, use rmdir() instead.
1255 """
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001256 try:
1257 self._accessor.unlink(self)
1258 except FileNotFoundError:
1259 if not missing_ok:
1260 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001261
1262 def rmdir(self):
1263 """
1264 Remove this directory. The directory must be empty.
1265 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001266 self._accessor.rmdir(self)
1267
1268 def lstat(self):
1269 """
1270 Like stat(), except if the path points to a symlink, the symlink's
1271 status information is returned, rather than its target's.
1272 """
Barney Galeabf96492021-04-07 16:53:39 +01001273 return self.stat(follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001274
1275 def rename(self, target):
1276 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001277 Rename this path to the target path.
1278
1279 The target path may be absolute or relative. Relative paths are
1280 interpreted relative to the current working directory, *not* the
1281 directory of the Path object.
1282
1283 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001284 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001285 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001286 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001287
1288 def replace(self, target):
1289 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001290 Rename this path to the target path, overwriting if that path exists.
1291
1292 The target path may be absolute or relative. Relative paths are
1293 interpreted relative to the current working directory, *not* the
1294 directory of the Path object.
1295
1296 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001297 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001298 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001299 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001300
1301 def symlink_to(self, target, target_is_directory=False):
1302 """
Barney Gale8aac1be2021-04-07 16:56:32 +01001303 Make this path a symlink pointing to the target path.
1304 Note the order of arguments (link, target) is the reverse of os.symlink.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001305 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001306 self._accessor.symlink(target, self, target_is_directory)
1307
Barney Gale8aac1be2021-04-07 16:56:32 +01001308 def link_to(self, target):
1309 """
1310 Make the target path a hard link pointing to this path.
1311
1312 Note this function does not make this path a hard link to *target*,
1313 despite the implication of the function and argument names. The order
1314 of arguments (target, link) is the reverse of Path.symlink_to, but
1315 matches that of os.link.
1316
1317 """
1318 self._accessor.link(self, target)
1319
Antoine Pitrou31119e42013-11-22 17:38:12 +01001320 # Convenience functions for querying the stat results
1321
1322 def exists(self):
1323 """
1324 Whether this path exists.
1325 """
1326 try:
1327 self.stat()
1328 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001329 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001330 raise
1331 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001332 except ValueError:
1333 # Non-encodable path
1334 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001335 return True
1336
1337 def is_dir(self):
1338 """
1339 Whether this path is a directory.
1340 """
1341 try:
1342 return S_ISDIR(self.stat().st_mode)
1343 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001344 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001345 raise
1346 # Path doesn't exist or is a broken symlink
1347 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1348 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001349 except ValueError:
1350 # Non-encodable path
1351 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001352
1353 def is_file(self):
1354 """
1355 Whether this path is a regular file (also True for symlinks pointing
1356 to regular files).
1357 """
1358 try:
1359 return S_ISREG(self.stat().st_mode)
1360 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001361 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001362 raise
1363 # Path doesn't exist or is a broken symlink
1364 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1365 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001366 except ValueError:
1367 # Non-encodable path
1368 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001369
Cooper Lees173ff4a2017-08-01 15:35:45 -07001370 def is_mount(self):
1371 """
1372 Check if this path is a POSIX mount point
1373 """
1374 # Need to exist and be a dir
1375 if not self.exists() or not self.is_dir():
1376 return False
1377
Cooper Lees173ff4a2017-08-01 15:35:45 -07001378 try:
Barney Galec746c4f2020-04-17 18:42:06 +01001379 parent_dev = self.parent.stat().st_dev
Cooper Lees173ff4a2017-08-01 15:35:45 -07001380 except OSError:
1381 return False
1382
1383 dev = self.stat().st_dev
1384 if dev != parent_dev:
1385 return True
1386 ino = self.stat().st_ino
Barney Galec746c4f2020-04-17 18:42:06 +01001387 parent_ino = self.parent.stat().st_ino
Cooper Lees173ff4a2017-08-01 15:35:45 -07001388 return ino == parent_ino
1389
Antoine Pitrou31119e42013-11-22 17:38:12 +01001390 def is_symlink(self):
1391 """
1392 Whether this path is a symbolic link.
1393 """
1394 try:
1395 return S_ISLNK(self.lstat().st_mode)
1396 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001397 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001398 raise
1399 # Path doesn't exist
1400 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001401 except ValueError:
1402 # Non-encodable path
1403 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001404
1405 def is_block_device(self):
1406 """
1407 Whether this path is a block device.
1408 """
1409 try:
1410 return S_ISBLK(self.stat().st_mode)
1411 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001412 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001413 raise
1414 # Path doesn't exist or is a broken symlink
1415 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1416 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001417 except ValueError:
1418 # Non-encodable path
1419 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001420
1421 def is_char_device(self):
1422 """
1423 Whether this path is a character device.
1424 """
1425 try:
1426 return S_ISCHR(self.stat().st_mode)
1427 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001428 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001429 raise
1430 # Path doesn't exist or is a broken symlink
1431 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1432 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001433 except ValueError:
1434 # Non-encodable path
1435 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001436
1437 def is_fifo(self):
1438 """
1439 Whether this path is a FIFO.
1440 """
1441 try:
1442 return S_ISFIFO(self.stat().st_mode)
1443 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001444 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001445 raise
1446 # Path doesn't exist or is a broken symlink
1447 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1448 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001449 except ValueError:
1450 # Non-encodable path
1451 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001452
1453 def is_socket(self):
1454 """
1455 Whether this path is a socket.
1456 """
1457 try:
1458 return S_ISSOCK(self.stat().st_mode)
1459 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001460 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001461 raise
1462 # Path doesn't exist or is a broken symlink
1463 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1464 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001465 except ValueError:
1466 # Non-encodable path
1467 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001468
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001469 def expanduser(self):
1470 """ Return a new path with expanded ~ and ~user constructs
1471 (as returned by os.path.expanduser)
1472 """
1473 if (not (self._drv or self._root) and
1474 self._parts and self._parts[0][:1] == '~'):
Barney Gale3f3d82b2021-04-07 23:50:13 +01001475 homedir = self._accessor.expanduser(self._parts[0])
1476 if homedir[:1] == "~":
1477 raise RuntimeError("Could not determine home directory.")
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001478 return self._from_parts([homedir] + self._parts[1:])
1479
1480 return self
1481
Antoine Pitrou31119e42013-11-22 17:38:12 +01001482
1483class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001484 """Path subclass for non-Windows systems.
1485
1486 On a POSIX system, instantiating a Path should return this object.
1487 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001488 __slots__ = ()
1489
1490class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001491 """Path subclass for Windows systems.
1492
1493 On a Windows system, instantiating a Path should return this object.
1494 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001495 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001496
Cooper Lees173ff4a2017-08-01 15:35:45 -07001497 def is_mount(self):
1498 raise NotImplementedError("Path.is_mount() is unsupported on this system")