blob: 37934c6038e1d1ac3fd58eb4cd82cd128121417c [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
Barney Galef24e2e52021-04-23 21:48:52 +01009import warnings
Serhiy Storchaka81108372017-09-26 00:55:55 +030010from _collections_abc import Sequence
Jörg Stucked5c120f2019-05-21 19:44:40 +020011from errno import EINVAL, ENOENT, ENOTDIR, EBADF, ELOOP
Antoine Pitrou31119e42013-11-22 17:38:12 +010012from operator import attrgetter
13from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
Antoine Pitrou069a5e12013-12-03 09:41:35 +010014from urllib.parse import quote_from_bytes as urlquote_from_bytes
Antoine Pitrou31119e42013-11-22 17:38:12 +010015
16
Antoine Pitroudb118f52014-11-19 00:32:08 +010017if os.name == 'nt':
Barney Galeb57e0452021-04-07 00:01:22 +010018 from nt import _getfinalpathname
Antoine Pitroudb118f52014-11-19 00:32:08 +010019else:
Barney Galeb57e0452021-04-07 00:01:22 +010020 _getfinalpathname = None
Antoine Pitrou31119e42013-11-22 17:38:12 +010021
22
23__all__ = [
24 "PurePath", "PurePosixPath", "PureWindowsPath",
25 "Path", "PosixPath", "WindowsPath",
26 ]
27
28#
29# Internals
30#
31
penguindustin96466302019-05-06 14:57:17 -040032# EBADF - guard against macOS `stat` throwing EBADF
Jörg Stucked5c120f2019-05-21 19:44:40 +020033_IGNORED_ERROS = (ENOENT, ENOTDIR, EBADF, ELOOP)
Przemysław Spodymek216b7452018-08-27 23:33:45 +020034
Steve Dower2f6fae62019-02-03 23:08:18 -080035_IGNORED_WINERRORS = (
36 21, # ERROR_NOT_READY - drive exists but is not accessible
Steve Dower4696f122021-04-22 21:04:44 +010037 123, # ERROR_INVALID_NAME - fix for bpo-35306
Jörg Stucked5c120f2019-05-21 19:44:40 +020038 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
Steve Dower2f6fae62019-02-03 23:08:18 -080039)
40
41def _ignore_error(exception):
42 return (getattr(exception, 'errno', None) in _IGNORED_ERROS or
43 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
44
45
Antoine Pitrou31119e42013-11-22 17:38:12 +010046def _is_wildcard_pattern(pat):
47 # Whether this pattern needs actual matching using fnmatch, or can
48 # be looked up directly as a file.
49 return "*" in pat or "?" in pat or "[" in pat
50
51
52class _Flavour(object):
53 """A flavour implements a particular (platform-specific) set of path
54 semantics."""
55
56 def __init__(self):
57 self.join = self.sep.join
58
59 def parse_parts(self, parts):
60 parsed = []
61 sep = self.sep
62 altsep = self.altsep
63 drv = root = ''
64 it = reversed(parts)
65 for part in it:
66 if not part:
67 continue
68 if altsep:
69 part = part.replace(altsep, sep)
70 drv, root, rel = self.splitroot(part)
71 if sep in rel:
72 for x in reversed(rel.split(sep)):
73 if x and x != '.':
74 parsed.append(sys.intern(x))
75 else:
76 if rel and rel != '.':
77 parsed.append(sys.intern(rel))
78 if drv or root:
79 if not drv:
80 # If no drive is present, try to find one in the previous
81 # parts. This makes the result of parsing e.g.
82 # ("C:", "/", "a") reasonably intuitive.
83 for part in it:
Antoine Pitrou57fffd62015-02-15 18:03:59 +010084 if not part:
85 continue
86 if altsep:
87 part = part.replace(altsep, sep)
Antoine Pitrou31119e42013-11-22 17:38:12 +010088 drv = self.splitroot(part)[0]
89 if drv:
90 break
91 break
92 if drv or root:
93 parsed.append(drv + root)
94 parsed.reverse()
95 return drv, root, parsed
96
97 def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
98 """
99 Join the two paths represented by the respective
100 (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
101 """
102 if root2:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200103 if not drv2 and drv:
104 return drv, root2, [drv + root2] + parts2[1:]
105 elif drv2:
106 if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
107 # Same drive => second path is relative to the first
108 return drv, root, parts + parts2[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100109 else:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200110 # Second path is non-anchored (common case)
111 return drv, root, parts + parts2
112 return drv2, root2, parts2
Antoine Pitrou31119e42013-11-22 17:38:12 +0100113
114
115class _WindowsFlavour(_Flavour):
116 # Reference for Windows paths can be found at
117 # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
118
119 sep = '\\'
120 altsep = '/'
121 has_drv = True
122 pathmod = ntpath
123
Antoine Pitroudb118f52014-11-19 00:32:08 +0100124 is_supported = (os.name == 'nt')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100125
Jon Dufresne39726282017-05-18 07:35:54 -0700126 drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100127 ext_namespace_prefix = '\\\\?\\'
128
129 reserved_names = (
130 {'CON', 'PRN', 'AUX', 'NUL'} |
131 {'COM%d' % i for i in range(1, 10)} |
132 {'LPT%d' % i for i in range(1, 10)}
133 )
134
135 # Interesting findings about extended paths:
136 # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
137 # but '\\?\c:/a' is not
138 # - extended paths are always absolute; "relative" extended paths will
139 # fail.
140
141 def splitroot(self, part, sep=sep):
142 first = part[0:1]
143 second = part[1:2]
144 if (second == sep and first == sep):
145 # XXX extended paths should also disable the collapsing of "."
146 # components (according to MSDN docs).
147 prefix, part = self._split_extended_path(part)
148 first = part[0:1]
149 second = part[1:2]
150 else:
151 prefix = ''
152 third = part[2:3]
153 if (second == sep and first == sep and third != sep):
154 # is a UNC path:
155 # vvvvvvvvvvvvvvvvvvvvv root
156 # \\machine\mountpoint\directory\etc\...
157 # directory ^^^^^^^^^^^^^^
158 index = part.find(sep, 2)
159 if index != -1:
160 index2 = part.find(sep, index + 1)
161 # a UNC path can't have two slashes in a row
162 # (after the initial two)
163 if index2 != index + 1:
164 if index2 == -1:
165 index2 = len(part)
166 if prefix:
167 return prefix + part[1:index2], sep, part[index2+1:]
168 else:
169 return part[:index2], sep, part[index2+1:]
170 drv = root = ''
171 if second == ':' and first in self.drive_letters:
172 drv = part[:2]
173 part = part[2:]
174 first = third
175 if first == sep:
176 root = first
177 part = part.lstrip(sep)
178 return prefix + drv, root, part
179
180 def casefold(self, s):
181 return s.lower()
182
183 def casefold_parts(self, parts):
184 return [p.lower() for p in parts]
185
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300186 def compile_pattern(self, pattern):
187 return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
188
Steve Dower98eb3602016-11-09 12:58:17 -0800189 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100190 s = str(path)
191 if not s:
Barney Galeb05440c2021-04-07 17:31:49 +0100192 return path._accessor.getcwd()
Steve Dower98eb3602016-11-09 12:58:17 -0800193 previous_s = None
Antoine Pitrou31119e42013-11-22 17:38:12 +0100194 if _getfinalpathname is not None:
Steve Dower98eb3602016-11-09 12:58:17 -0800195 if strict:
196 return self._ext_to_normal(_getfinalpathname(s))
197 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200198 tail_parts = [] # End of the path after the first one not found
Steve Dower98eb3602016-11-09 12:58:17 -0800199 while True:
200 try:
201 s = self._ext_to_normal(_getfinalpathname(s))
202 except FileNotFoundError:
203 previous_s = s
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200204 s, tail = os.path.split(s)
205 tail_parts.append(tail)
Steve Dower4b1e98b2016-12-28 16:02:59 -0800206 if previous_s == s:
207 return path
Steve Dower98eb3602016-11-09 12:58:17 -0800208 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200209 return os.path.join(s, *reversed(tail_parts))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100210 # Means fallback on absolute
211 return None
212
213 def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
214 prefix = ''
215 if s.startswith(ext_prefix):
216 prefix = s[:4]
217 s = s[4:]
218 if s.startswith('UNC\\'):
219 prefix += s[:3]
220 s = '\\' + s[3:]
221 return prefix, s
222
223 def _ext_to_normal(self, s):
224 # Turn back an extended path into a normal DOS-like path
225 return self._split_extended_path(s)[1]
226
227 def is_reserved(self, parts):
228 # NOTE: the rules for reserved names seem somewhat complicated
229 # (e.g. r"..\NUL" is reserved but not r"foo\NUL").
230 # We err on the side of caution and return True for paths which are
231 # not considered reserved by Windows.
232 if not parts:
233 return False
234 if parts[0].startswith('\\\\'):
235 # UNC paths are never reserved
236 return False
237 return parts[-1].partition('.')[0].upper() in self.reserved_names
238
239 def make_uri(self, path):
240 # Under Windows, file URIs use the UTF-8 encoding.
241 drive = path.drive
242 if len(drive) == 2 and drive[1] == ':':
243 # It's a path on a local drive => 'file:///c:/a/b'
244 rest = path.as_posix()[2:].lstrip('/')
245 return 'file:///%s/%s' % (
246 drive, urlquote_from_bytes(rest.encode('utf-8')))
247 else:
248 # It's a path on a network drive => 'file://host/share/a/b'
249 return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
250
251
252class _PosixFlavour(_Flavour):
253 sep = '/'
254 altsep = ''
255 has_drv = False
256 pathmod = posixpath
257
258 is_supported = (os.name != 'nt')
259
260 def splitroot(self, part, sep=sep):
261 if part and part[0] == sep:
262 stripped_part = part.lstrip(sep)
263 # According to POSIX path resolution:
264 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
265 # "A pathname that begins with two successive slashes may be
266 # interpreted in an implementation-defined manner, although more
267 # than two leading slashes shall be treated as a single slash".
268 if len(part) - len(stripped_part) == 2:
269 return '', sep * 2, stripped_part
270 else:
271 return '', sep, stripped_part
272 else:
273 return '', '', part
274
275 def casefold(self, s):
276 return s
277
278 def casefold_parts(self, parts):
279 return parts
280
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300281 def compile_pattern(self, pattern):
282 return re.compile(fnmatch.translate(pattern)).fullmatch
283
Steve Dower98eb3602016-11-09 12:58:17 -0800284 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100285 sep = self.sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100286 accessor = path._accessor
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100287 seen = {}
288 def _resolve(path, rest):
289 if rest.startswith(sep):
290 path = ''
291
292 for name in rest.split(sep):
293 if not name or name == '.':
294 # current dir
295 continue
296 if name == '..':
297 # parent dir
298 path, _, _ = path.rpartition(sep)
299 continue
Dong-hee Na94ad6c62018-06-12 23:30:45 +0900300 if path.endswith(sep):
301 newpath = path + name
302 else:
303 newpath = path + sep + name
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100304 if newpath in seen:
305 # Already seen this path
306 path = seen[newpath]
307 if path is not None:
308 # use cached value
309 continue
310 # The symlink is not resolved, so we must have a symlink loop.
311 raise RuntimeError("Symlink loop from %r" % newpath)
312 # Resolve the symbolic link
313 try:
314 target = accessor.readlink(newpath)
315 except OSError as e:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200316 if e.errno != EINVAL and strict:
317 raise
318 # Not a symlink, or non-strict mode. We just leave the path
319 # untouched.
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100320 path = newpath
321 else:
322 seen[newpath] = None # not resolved symlink
323 path = _resolve(path, target)
324 seen[newpath] = path # resolved symlink
325
326 return path
327 # NOTE: according to POSIX, getcwd() cannot contain path components
328 # which are symlinks.
Barney Galeb05440c2021-04-07 17:31:49 +0100329 base = '' if path.is_absolute() else accessor.getcwd()
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100330 return _resolve(base, str(path)) or sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100331
332 def is_reserved(self, parts):
333 return False
334
335 def make_uri(self, path):
336 # We represent the path using the local filesystem encoding,
337 # for portability to other applications.
338 bpath = bytes(path)
339 return 'file://' + urlquote_from_bytes(bpath)
340
341
342_windows_flavour = _WindowsFlavour()
343_posix_flavour = _PosixFlavour()
344
345
346class _Accessor:
347 """An accessor implements a particular (system-specific or not) way of
348 accessing paths on the filesystem."""
349
350
351class _NormalAccessor(_Accessor):
352
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200353 stat = os.stat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100354
Barney Gale11c3bd32021-04-09 21:52:49 +0100355 open = io.open
Antoine Pitrou31119e42013-11-22 17:38:12 +0100356
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200357 listdir = os.listdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100358
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200359 scandir = os.scandir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100360
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200361 chmod = os.chmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100362
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200363 mkdir = os.mkdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100364
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200365 unlink = os.unlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100366
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100367 if hasattr(os, "link"):
Barney Galeb57e0452021-04-07 00:01:22 +0100368 link = os.link
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100369 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100370 def link(self, src, dst):
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100371 raise NotImplementedError("os.link() not available on this system")
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -0400372
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200373 rmdir = os.rmdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100374
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200375 rename = os.rename
Antoine Pitrou31119e42013-11-22 17:38:12 +0100376
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200377 replace = os.replace
Antoine Pitrou31119e42013-11-22 17:38:12 +0100378
Barney Galeb57e0452021-04-07 00:01:22 +0100379 if hasattr(os, "symlink"):
380 symlink = os.symlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100381 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100382 def symlink(self, src, dst, target_is_directory=False):
383 raise NotImplementedError("os.symlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100384
Barney Gale986da8e2021-04-07 01:25:37 +0100385 def touch(self, path, mode=0o666, exist_ok=True):
386 if exist_ok:
387 # First try to bump modification time
388 # Implementation note: GNU touch uses the UTIME_NOW option of
389 # the utimensat() / futimens() functions.
390 try:
391 os.utime(path, None)
392 except OSError:
393 # Avoid exception chaining
394 pass
395 else:
396 return
397 flags = os.O_CREAT | os.O_WRONLY
398 if not exist_ok:
399 flags |= os.O_EXCL
400 fd = os.open(path, flags, mode)
401 os.close(fd)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100402
Barney Galeb57e0452021-04-07 00:01:22 +0100403 if hasattr(os, "readlink"):
404 readlink = os.readlink
405 else:
406 def readlink(self, path):
407 raise NotImplementedError("os.readlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100408
Barney Gale22386bb2020-04-17 17:41:07 +0100409 def owner(self, path):
410 try:
411 import pwd
412 return pwd.getpwuid(self.stat(path).st_uid).pw_name
413 except ImportError:
414 raise NotImplementedError("Path.owner() is unsupported on this system")
415
416 def group(self, path):
417 try:
418 import grp
419 return grp.getgrgid(self.stat(path).st_gid).gr_name
420 except ImportError:
421 raise NotImplementedError("Path.group() is unsupported on this system")
422
Barney Galeb05440c2021-04-07 17:31:49 +0100423 getcwd = os.getcwd
424
Barney Gale3f3d82b2021-04-07 23:50:13 +0100425 expanduser = staticmethod(os.path.expanduser)
426
Antoine Pitrou31119e42013-11-22 17:38:12 +0100427
428_normal_accessor = _NormalAccessor()
429
430
431#
432# Globbing helpers
433#
434
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300435def _make_selector(pattern_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100436 pat = pattern_parts[0]
437 child_parts = pattern_parts[1:]
438 if pat == '**':
439 cls = _RecursiveWildcardSelector
440 elif '**' in pat:
441 raise ValueError("Invalid pattern: '**' can only be an entire path component")
442 elif _is_wildcard_pattern(pat):
443 cls = _WildcardSelector
444 else:
445 cls = _PreciseSelector
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300446 return cls(pat, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100447
448if hasattr(functools, "lru_cache"):
449 _make_selector = functools.lru_cache()(_make_selector)
450
451
452class _Selector:
453 """A selector matches a specific glob pattern part against the children
454 of a given path."""
455
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300456 def __init__(self, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100457 self.child_parts = child_parts
458 if child_parts:
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300459 self.successor = _make_selector(child_parts, flavour)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300460 self.dironly = True
Antoine Pitrou31119e42013-11-22 17:38:12 +0100461 else:
462 self.successor = _TerminatingSelector()
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300463 self.dironly = False
Antoine Pitrou31119e42013-11-22 17:38:12 +0100464
465 def select_from(self, parent_path):
466 """Iterate over all child paths of `parent_path` matched by this
467 selector. This can contain parent_path itself."""
468 path_cls = type(parent_path)
469 is_dir = path_cls.is_dir
470 exists = path_cls.exists
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300471 scandir = parent_path._accessor.scandir
472 if not is_dir(parent_path):
473 return iter([])
474 return self._select_from(parent_path, is_dir, exists, scandir)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100475
476
477class _TerminatingSelector:
478
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300479 def _select_from(self, parent_path, is_dir, exists, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100480 yield parent_path
481
482
483class _PreciseSelector(_Selector):
484
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300485 def __init__(self, name, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100486 self.name = name
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300487 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100488
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300489 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800490 try:
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800491 path = parent_path._make_child_relpath(self.name)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300492 if (is_dir if self.dironly else exists)(path):
493 for p in self.successor._select_from(path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800494 yield p
495 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100496 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100497
498
499class _WildcardSelector(_Selector):
500
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300501 def __init__(self, pat, child_parts, flavour):
502 self.match = flavour.compile_pattern(pat)
503 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100504
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300505 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800506 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200507 with scandir(parent_path) as scandir_it:
508 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300509 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000510 if self.dironly:
511 try:
512 # "entry.is_dir()" can raise PermissionError
513 # in some cases (see bpo-38894), which is not
514 # among the errors ignored by _ignore_error()
515 if not entry.is_dir():
516 continue
517 except OSError as e:
518 if not _ignore_error(e):
519 raise
520 continue
521 name = entry.name
522 if self.match(name):
523 path = parent_path._make_child_relpath(name)
524 for p in self.successor._select_from(path, is_dir, exists, scandir):
525 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800526 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100527 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800528
Antoine Pitrou31119e42013-11-22 17:38:12 +0100529
Antoine Pitrou31119e42013-11-22 17:38:12 +0100530class _RecursiveWildcardSelector(_Selector):
531
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300532 def __init__(self, pat, child_parts, flavour):
533 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100534
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300535 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100536 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800537 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200538 with scandir(parent_path) as scandir_it:
539 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300540 for entry in entries:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200541 entry_is_dir = False
542 try:
543 entry_is_dir = entry.is_dir()
544 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800545 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200546 raise
547 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300548 path = parent_path._make_child_relpath(entry.name)
549 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800550 yield p
551 except PermissionError:
552 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100553
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300554 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800555 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300556 yielded = set()
557 try:
558 successor_select = self.successor._select_from
559 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
560 for p in successor_select(starting_point, is_dir, exists, scandir):
561 if p not in yielded:
562 yield p
563 yielded.add(p)
564 finally:
565 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800566 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100567 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100568
569
570#
571# Public API
572#
573
574class _PathParents(Sequence):
575 """This object provides sequence-like access to the logical ancestors
576 of a path. Don't try to construct it yourself."""
577 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
578
579 def __init__(self, path):
580 # We don't store the instance to avoid reference cycles
581 self._pathcls = type(path)
582 self._drv = path._drv
583 self._root = path._root
584 self._parts = path._parts
585
586 def __len__(self):
587 if self._drv or self._root:
588 return len(self._parts) - 1
589 else:
590 return len(self._parts)
591
592 def __getitem__(self, idx):
Joshua Cannon45205842020-11-20 09:40:39 -0600593 if isinstance(idx, slice):
594 return tuple(self[i] for i in range(*idx.indices(len(self))))
Yaroslav Pankovych79d2e622020-11-23 22:06:22 +0200595
596 if idx >= len(self) or idx < -len(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100597 raise IndexError(idx)
598 return self._pathcls._from_parsed_parts(self._drv, self._root,
599 self._parts[:-idx - 1])
600
601 def __repr__(self):
602 return "<{}.parents>".format(self._pathcls.__name__)
603
604
605class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900606 """Base class for manipulating paths without I/O.
607
608 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100609 don't imply any actual filesystem I/O. Depending on your system,
610 instantiating a PurePath will return either a PurePosixPath or a
611 PureWindowsPath object. You can also instantiate either of these classes
612 directly, regardless of your system.
613 """
614 __slots__ = (
615 '_drv', '_root', '_parts',
616 '_str', '_hash', '_pparts', '_cached_cparts',
617 )
618
619 def __new__(cls, *args):
620 """Construct a PurePath from one or several strings and or existing
621 PurePath objects. The strings and path objects are combined so as
622 to yield a canonicalized path, which is incorporated into the
623 new PurePath object.
624 """
625 if cls is PurePath:
626 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
627 return cls._from_parts(args)
628
629 def __reduce__(self):
630 # Using the parts tuple helps share interned path parts
631 # when pickling related paths.
632 return (self.__class__, tuple(self._parts))
633
634 @classmethod
635 def _parse_args(cls, args):
636 # This is useful when you don't want to create an instance, just
637 # canonicalize some constructor arguments.
638 parts = []
639 for a in args:
640 if isinstance(a, PurePath):
641 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100642 else:
Brett Cannon568be632016-06-10 12:20:49 -0700643 a = os.fspath(a)
644 if isinstance(a, str):
645 # Force-cast str subclasses to str (issue #21127)
646 parts.append(str(a))
647 else:
648 raise TypeError(
649 "argument should be a str object or an os.PathLike "
650 "object returning str, not %r"
651 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100652 return cls._flavour.parse_parts(parts)
653
654 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100655 def _from_parts(cls, args):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100656 # We need to call _parse_args on the instance, so as to get the
657 # right flavour.
658 self = object.__new__(cls)
659 drv, root, parts = self._parse_args(args)
660 self._drv = drv
661 self._root = root
662 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100663 return self
664
665 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100666 def _from_parsed_parts(cls, drv, root, parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100667 self = object.__new__(cls)
668 self._drv = drv
669 self._root = root
670 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100671 return self
672
673 @classmethod
674 def _format_parsed_parts(cls, drv, root, parts):
675 if drv or root:
676 return drv + root + cls._flavour.join(parts[1:])
677 else:
678 return cls._flavour.join(parts)
679
Antoine Pitrou31119e42013-11-22 17:38:12 +0100680 def _make_child(self, args):
681 drv, root, parts = self._parse_args(args)
682 drv, root, parts = self._flavour.join_parsed_parts(
683 self._drv, self._root, self._parts, drv, root, parts)
684 return self._from_parsed_parts(drv, root, parts)
685
686 def __str__(self):
687 """Return the string representation of the path, suitable for
688 passing to system calls."""
689 try:
690 return self._str
691 except AttributeError:
692 self._str = self._format_parsed_parts(self._drv, self._root,
693 self._parts) or '.'
694 return self._str
695
Brett Cannon568be632016-06-10 12:20:49 -0700696 def __fspath__(self):
697 return str(self)
698
Antoine Pitrou31119e42013-11-22 17:38:12 +0100699 def as_posix(self):
700 """Return the string representation of the path with forward (/)
701 slashes."""
702 f = self._flavour
703 return str(self).replace(f.sep, '/')
704
705 def __bytes__(self):
706 """Return the bytes representation of the path. This is only
707 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200708 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100709
710 def __repr__(self):
711 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
712
713 def as_uri(self):
714 """Return the path as a 'file' URI."""
715 if not self.is_absolute():
716 raise ValueError("relative path can't be expressed as a file URI")
717 return self._flavour.make_uri(self)
718
719 @property
720 def _cparts(self):
721 # Cached casefolded parts, for hashing and comparison
722 try:
723 return self._cached_cparts
724 except AttributeError:
725 self._cached_cparts = self._flavour.casefold_parts(self._parts)
726 return self._cached_cparts
727
728 def __eq__(self, other):
729 if not isinstance(other, PurePath):
730 return NotImplemented
731 return self._cparts == other._cparts and self._flavour is other._flavour
732
Antoine Pitrou31119e42013-11-22 17:38:12 +0100733 def __hash__(self):
734 try:
735 return self._hash
736 except AttributeError:
737 self._hash = hash(tuple(self._cparts))
738 return self._hash
739
740 def __lt__(self, other):
741 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
742 return NotImplemented
743 return self._cparts < other._cparts
744
745 def __le__(self, other):
746 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
747 return NotImplemented
748 return self._cparts <= other._cparts
749
750 def __gt__(self, other):
751 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
752 return NotImplemented
753 return self._cparts > other._cparts
754
755 def __ge__(self, other):
756 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
757 return NotImplemented
758 return self._cparts >= other._cparts
759
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300760 def __class_getitem__(cls, type):
761 return cls
762
Antoine Pitrou31119e42013-11-22 17:38:12 +0100763 drive = property(attrgetter('_drv'),
764 doc="""The drive prefix (letter or UNC path), if any.""")
765
766 root = property(attrgetter('_root'),
767 doc="""The root of the path, if any.""")
768
769 @property
770 def anchor(self):
771 """The concatenation of the drive and root, or ''."""
772 anchor = self._drv + self._root
773 return anchor
774
775 @property
776 def name(self):
777 """The final path component, if any."""
778 parts = self._parts
779 if len(parts) == (1 if (self._drv or self._root) else 0):
780 return ''
781 return parts[-1]
782
783 @property
784 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200785 """
786 The final component's last suffix, if any.
787
788 This includes the leading period. For example: '.txt'
789 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100790 name = self.name
791 i = name.rfind('.')
792 if 0 < i < len(name) - 1:
793 return name[i:]
794 else:
795 return ''
796
797 @property
798 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200799 """
800 A list of the final component's suffixes, if any.
801
802 These include the leading periods. For example: ['.tar', '.gz']
803 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100804 name = self.name
805 if name.endswith('.'):
806 return []
807 name = name.lstrip('.')
808 return ['.' + suffix for suffix in name.split('.')[1:]]
809
810 @property
811 def stem(self):
812 """The final path component, minus its last suffix."""
813 name = self.name
814 i = name.rfind('.')
815 if 0 < i < len(name) - 1:
816 return name[:i]
817 else:
818 return name
819
820 def with_name(self, name):
821 """Return a new path with the file name changed."""
822 if not self.name:
823 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400824 drv, root, parts = self._flavour.parse_parts((name,))
825 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
826 or drv or root or len(parts) != 1):
827 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100828 return self._from_parsed_parts(self._drv, self._root,
829 self._parts[:-1] + [name])
830
Tim Hoffmann8aea4b32020-04-19 17:29:49 +0200831 def with_stem(self, stem):
832 """Return a new path with the stem changed."""
833 return self.with_name(stem + self.suffix)
834
Antoine Pitrou31119e42013-11-22 17:38:12 +0100835 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200836 """Return a new path with the file suffix changed. If the path
837 has no suffix, add given suffix. If the given suffix is an empty
838 string, remove the suffix from the path.
839 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400840 f = self._flavour
841 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300842 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400843 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100844 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100845 name = self.name
846 if not name:
847 raise ValueError("%r has an empty name" % (self,))
848 old_suffix = self.suffix
849 if not old_suffix:
850 name = name + suffix
851 else:
852 name = name[:-len(old_suffix)] + suffix
853 return self._from_parsed_parts(self._drv, self._root,
854 self._parts[:-1] + [name])
855
856 def relative_to(self, *other):
857 """Return the relative path to another path identified by the passed
858 arguments. If the operation is not possible (because this is not
859 a subpath of the other path), raise ValueError.
860 """
861 # For the purpose of this method, drive and root are considered
862 # separate parts, i.e.:
863 # Path('c:/').relative_to('c:') gives Path('/')
864 # Path('c:/').relative_to('/') raise ValueError
865 if not other:
866 raise TypeError("need at least one argument")
867 parts = self._parts
868 drv = self._drv
869 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100870 if root:
871 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100872 else:
873 abs_parts = parts
874 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100875 if to_root:
876 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100877 else:
878 to_abs_parts = to_parts
879 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100880 cf = self._flavour.casefold_parts
881 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100882 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
Rotuna44832532020-05-25 21:42:28 +0200883 raise ValueError("{!r} is not in the subpath of {!r}"
884 " OR one path is relative and the other is absolute."
Antoine Pitrou31119e42013-11-22 17:38:12 +0100885 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100886 return self._from_parsed_parts('', root if n == 1 else '',
887 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100888
Hai Shi82642a02019-08-13 14:54:02 -0500889 def is_relative_to(self, *other):
890 """Return True if the path is relative to another path or False.
891 """
892 try:
893 self.relative_to(*other)
894 return True
895 except ValueError:
896 return False
897
Antoine Pitrou31119e42013-11-22 17:38:12 +0100898 @property
899 def parts(self):
900 """An object providing sequence-like access to the
901 components in the filesystem path."""
902 # We cache the tuple to avoid building a new one each time .parts
903 # is accessed. XXX is this necessary?
904 try:
905 return self._pparts
906 except AttributeError:
907 self._pparts = tuple(self._parts)
908 return self._pparts
909
910 def joinpath(self, *args):
911 """Combine this path with one or several arguments, and return a
912 new path representing either a subpath (if all arguments are relative
913 paths) or a totally different path (if one of the arguments is
914 anchored).
915 """
916 return self._make_child(args)
917
918 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400919 try:
920 return self._make_child((key,))
921 except TypeError:
922 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100923
924 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400925 try:
926 return self._from_parts([key] + self._parts)
927 except TypeError:
928 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100929
930 @property
931 def parent(self):
932 """The logical parent of the path."""
933 drv = self._drv
934 root = self._root
935 parts = self._parts
936 if len(parts) == 1 and (drv or root):
937 return self
938 return self._from_parsed_parts(drv, root, parts[:-1])
939
940 @property
941 def parents(self):
942 """A sequence of this path's logical parents."""
943 return _PathParents(self)
944
945 def is_absolute(self):
946 """True if the path is absolute (has both a root and, if applicable,
947 a drive)."""
948 if not self._root:
949 return False
950 return not self._flavour.has_drv or bool(self._drv)
951
952 def is_reserved(self):
953 """Return True if the path contains one of the special names reserved
954 by the system, if any."""
955 return self._flavour.is_reserved(self._parts)
956
957 def match(self, path_pattern):
958 """
959 Return True if this path matches the given pattern.
960 """
961 cf = self._flavour.casefold
962 path_pattern = cf(path_pattern)
963 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
964 if not pat_parts:
965 raise ValueError("empty pattern")
966 if drv and drv != cf(self._drv):
967 return False
968 if root and root != cf(self._root):
969 return False
970 parts = self._cparts
971 if drv or root:
972 if len(pat_parts) != len(parts):
973 return False
974 pat_parts = pat_parts[1:]
975 elif len(pat_parts) > len(parts):
976 return False
977 for part, pat in zip(reversed(parts), reversed(pat_parts)):
978 if not fnmatch.fnmatchcase(part, pat):
979 return False
980 return True
981
Brett Cannon568be632016-06-10 12:20:49 -0700982# Can't subclass os.PathLike from PurePath and keep the constructor
983# optimizations in PurePath._parse_args().
984os.PathLike.register(PurePath)
985
Antoine Pitrou31119e42013-11-22 17:38:12 +0100986
987class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900988 """PurePath subclass for non-Windows systems.
989
990 On a POSIX system, instantiating a PurePath should return this object.
991 However, you can also instantiate it directly on any system.
992 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100993 _flavour = _posix_flavour
994 __slots__ = ()
995
996
997class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900998 """PurePath subclass for Windows systems.
999
1000 On a Windows system, instantiating a PurePath should return this object.
1001 However, you can also instantiate it directly on any system.
1002 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001003 _flavour = _windows_flavour
1004 __slots__ = ()
1005
1006
1007# Filesystem-accessing classes
1008
1009
1010class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001011 """PurePath subclass that can make system calls.
1012
1013 Path represents a filesystem path but unlike PurePath, also offers
1014 methods to do system calls on path objects. Depending on your system,
1015 instantiating a Path will return either a PosixPath or a WindowsPath
1016 object. You can also instantiate a PosixPath or WindowsPath directly,
1017 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1018 """
Barney Gale22191872021-04-07 01:26:37 +01001019 _accessor = _normal_accessor
1020 __slots__ = ()
Antoine Pitrou31119e42013-11-22 17:38:12 +01001021
1022 def __new__(cls, *args, **kwargs):
1023 if cls is Path:
1024 cls = WindowsPath if os.name == 'nt' else PosixPath
Barney Gale22191872021-04-07 01:26:37 +01001025 self = cls._from_parts(args)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001026 if not self._flavour.is_supported:
1027 raise NotImplementedError("cannot instantiate %r on your system"
1028 % (cls.__name__,))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001029 return self
1030
Antoine Pitrou31119e42013-11-22 17:38:12 +01001031 def _make_child_relpath(self, part):
1032 # This is an optimization used for dir walking. `part` must be
1033 # a single part relative to this path.
1034 parts = self._parts + [part]
1035 return self._from_parsed_parts(self._drv, self._root, parts)
1036
1037 def __enter__(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001038 return self
1039
1040 def __exit__(self, t, v, tb):
Barney Gale00002e62020-04-01 15:10:51 +01001041 # https://bugs.python.org/issue39682
1042 # In previous versions of pathlib, this method marked this path as
1043 # closed; subsequent attempts to perform I/O would raise an IOError.
1044 # This functionality was never documented, and had the effect of
1045 # making Path objects mutable, contrary to PEP 428. In Python 3.9 the
1046 # _closed attribute was removed, and this method made a no-op.
1047 # This method and __enter__()/__exit__() should be deprecated and
1048 # removed in the future.
1049 pass
Antoine Pitrou31119e42013-11-22 17:38:12 +01001050
Antoine Pitrou31119e42013-11-22 17:38:12 +01001051 # Public API
1052
1053 @classmethod
1054 def cwd(cls):
1055 """Return a new path pointing to the current working directory
1056 (as returned by os.getcwd()).
1057 """
Barney Galeb05440c2021-04-07 17:31:49 +01001058 return cls(cls()._accessor.getcwd())
Antoine Pitrou31119e42013-11-22 17:38:12 +01001059
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001060 @classmethod
1061 def home(cls):
1062 """Return a new path pointing to the user's home directory (as
1063 returned by os.path.expanduser('~')).
1064 """
Barney Gale3f3d82b2021-04-07 23:50:13 +01001065 return cls("~").expanduser()
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001066
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001067 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001068 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001069 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001070 """
1071 st = self.stat()
1072 try:
1073 other_st = other_path.stat()
1074 except AttributeError:
Barney Gale5b1d9182020-04-17 18:47:27 +01001075 other_st = self._accessor.stat(other_path)
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001076 return os.path.samestat(st, other_st)
1077
Antoine Pitrou31119e42013-11-22 17:38:12 +01001078 def iterdir(self):
1079 """Iterate over the files in this directory. Does not yield any
1080 result for the special paths '.' and '..'.
1081 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001082 for name in self._accessor.listdir(self):
1083 if name in {'.', '..'}:
1084 # Yielding a path object for these makes little sense
1085 continue
1086 yield self._make_child_relpath(name)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001087
1088 def glob(self, pattern):
1089 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001090 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001091 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001092 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001093 if not pattern:
1094 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001095 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1096 if drv or root:
1097 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001098 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001099 for p in selector.select_from(self):
1100 yield p
1101
1102 def rglob(self, pattern):
1103 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001104 directories) matching the given relative pattern, anywhere in
1105 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001106 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001107 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001108 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1109 if drv or root:
1110 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001111 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001112 for p in selector.select_from(self):
1113 yield p
1114
1115 def absolute(self):
1116 """Return an absolute version of this path. This function works
1117 even if the path doesn't point to anything.
1118
1119 No normalization is done, i.e. all '.' and '..' will be kept along.
1120 Use resolve() to get the canonical path to a file.
1121 """
1122 # XXX untested yet!
Antoine Pitrou31119e42013-11-22 17:38:12 +01001123 if self.is_absolute():
1124 return self
1125 # FIXME this must defer to the specific flavour (and, under Windows,
1126 # use nt._getfullpathname())
Barney Galeb05440c2021-04-07 17:31:49 +01001127 return self._from_parts([self._accessor.getcwd()] + self._parts)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001128
Steve Dower98eb3602016-11-09 12:58:17 -08001129 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001130 """
1131 Make the path absolute, resolving all symlinks on the way and also
1132 normalizing it (for example turning slashes into backslashes under
1133 Windows).
1134 """
Steve Dower98eb3602016-11-09 12:58:17 -08001135 s = self._flavour.resolve(self, strict=strict)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001136 if s is None:
1137 # No symlink resolution => for consistency, raise an error if
1138 # the path doesn't exist or is forbidden
1139 self.stat()
1140 s = str(self.absolute())
1141 # Now we have no symlinks in the path, it's safe to normalize it.
1142 normed = self._flavour.pathmod.normpath(s)
Barney Gale22191872021-04-07 01:26:37 +01001143 return self._from_parts((normed,))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001144
Barney Galeabf96492021-04-07 16:53:39 +01001145 def stat(self, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001146 """
1147 Return the result of the stat() system call on this path, like
1148 os.stat() does.
1149 """
Barney Galeabf96492021-04-07 16:53:39 +01001150 return self._accessor.stat(self, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001151
1152 def owner(self):
1153 """
1154 Return the login name of the file owner.
1155 """
Barney Gale22386bb2020-04-17 17:41:07 +01001156 return self._accessor.owner(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001157
1158 def group(self):
1159 """
1160 Return the group name of the file gid.
1161 """
Barney Gale22386bb2020-04-17 17:41:07 +01001162 return self._accessor.group(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001163
Antoine Pitrou31119e42013-11-22 17:38:12 +01001164 def open(self, mode='r', buffering=-1, encoding=None,
1165 errors=None, newline=None):
1166 """
1167 Open the file pointed by this path and return a file object, as
1168 the built-in open() function does.
1169 """
Inada Naoki48274832021-03-29 12:28:14 +09001170 if "b" not in mode:
1171 encoding = io.text_encoding(encoding)
Barney Gale11c3bd32021-04-09 21:52:49 +01001172 return self._accessor.open(self, mode, buffering, encoding, errors,
1173 newline)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001174
Georg Brandlea683982014-10-01 19:12:33 +02001175 def read_bytes(self):
1176 """
1177 Open the file in bytes mode, read it, and close the file.
1178 """
1179 with self.open(mode='rb') as f:
1180 return f.read()
1181
1182 def read_text(self, encoding=None, errors=None):
1183 """
1184 Open the file in text mode, read it, and close the file.
1185 """
Inada Naoki48274832021-03-29 12:28:14 +09001186 encoding = io.text_encoding(encoding)
Georg Brandlea683982014-10-01 19:12:33 +02001187 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1188 return f.read()
1189
1190 def write_bytes(self, data):
1191 """
1192 Open the file in bytes mode, write to it, and close the file.
1193 """
1194 # type-check for the buffer interface before truncating the file
1195 view = memoryview(data)
1196 with self.open(mode='wb') as f:
1197 return f.write(view)
1198
Максим5f227412020-10-21 05:08:19 +03001199 def write_text(self, data, encoding=None, errors=None, newline=None):
Georg Brandlea683982014-10-01 19:12:33 +02001200 """
1201 Open the file in text mode, write to it, and close the file.
1202 """
1203 if not isinstance(data, str):
1204 raise TypeError('data must be str, not %s' %
1205 data.__class__.__name__)
Inada Naoki48274832021-03-29 12:28:14 +09001206 encoding = io.text_encoding(encoding)
Максим5f227412020-10-21 05:08:19 +03001207 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
Georg Brandlea683982014-10-01 19:12:33 +02001208 return f.write(data)
1209
Girtsa01ba332019-10-23 14:18:40 -07001210 def readlink(self):
1211 """
1212 Return the path to which the symbolic link points.
1213 """
1214 path = self._accessor.readlink(self)
Barney Gale22191872021-04-07 01:26:37 +01001215 return self._from_parts((path,))
Girtsa01ba332019-10-23 14:18:40 -07001216
Antoine Pitrou31119e42013-11-22 17:38:12 +01001217 def touch(self, mode=0o666, exist_ok=True):
1218 """
1219 Create this file with the given access mode, if it doesn't exist.
1220 """
Barney Gale986da8e2021-04-07 01:25:37 +01001221 self._accessor.touch(self, mode, exist_ok)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001222
Barry Warsaw7c549c42014-08-05 11:28:12 -04001223 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001224 """
1225 Create a new directory at this given path.
1226 """
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001227 try:
1228 self._accessor.mkdir(self, mode)
1229 except FileNotFoundError:
1230 if not parents or self.parent == self:
1231 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001232 self.parent.mkdir(parents=True, exist_ok=True)
1233 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001234 except OSError:
1235 # Cannot rely on checking for EEXIST, since the operating system
1236 # could give priority to other errors like EACCES or EROFS
1237 if not exist_ok or not self.is_dir():
1238 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001239
Barney Galeabf96492021-04-07 16:53:39 +01001240 def chmod(self, mode, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001241 """
1242 Change the permissions of the path, like os.chmod().
1243 """
Barney Galeabf96492021-04-07 16:53:39 +01001244 self._accessor.chmod(self, mode, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001245
1246 def lchmod(self, mode):
1247 """
1248 Like chmod(), except if the path points to a symlink, the symlink's
1249 permissions are changed, rather than its target's.
1250 """
Barney Galeabf96492021-04-07 16:53:39 +01001251 self.chmod(mode, follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001252
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001253 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001254 """
1255 Remove this file or link.
1256 If the path is a directory, use rmdir() instead.
1257 """
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001258 try:
1259 self._accessor.unlink(self)
1260 except FileNotFoundError:
1261 if not missing_ok:
1262 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001263
1264 def rmdir(self):
1265 """
1266 Remove this directory. The directory must be empty.
1267 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001268 self._accessor.rmdir(self)
1269
1270 def lstat(self):
1271 """
1272 Like stat(), except if the path points to a symlink, the symlink's
1273 status information is returned, rather than its target's.
1274 """
Barney Galeabf96492021-04-07 16:53:39 +01001275 return self.stat(follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001276
1277 def rename(self, target):
1278 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001279 Rename this path to the target path.
1280
1281 The target path may be absolute or relative. Relative paths are
1282 interpreted relative to the current working directory, *not* the
1283 directory of the Path object.
1284
1285 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001286 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001287 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001288 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001289
1290 def replace(self, target):
1291 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001292 Rename this path to the target path, overwriting if that path exists.
1293
1294 The target path may be absolute or relative. Relative paths are
1295 interpreted relative to the current working directory, *not* the
1296 directory of the Path object.
1297
1298 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001299 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001300 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001301 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001302
1303 def symlink_to(self, target, target_is_directory=False):
1304 """
Barney Gale8aac1be2021-04-07 16:56:32 +01001305 Make this path a symlink pointing to the target path.
1306 Note the order of arguments (link, target) is the reverse of os.symlink.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001307 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001308 self._accessor.symlink(target, self, target_is_directory)
1309
Barney Galef24e2e52021-04-23 21:48:52 +01001310 def hardlink_to(self, target):
1311 """
1312 Make this path a hard link pointing to the same file as *target*.
1313
1314 Note the order of arguments (self, target) is the reverse of os.link's.
1315 """
1316 self._accessor.link(target, self)
1317
Barney Gale8aac1be2021-04-07 16:56:32 +01001318 def link_to(self, target):
1319 """
1320 Make the target path a hard link pointing to this path.
1321
1322 Note this function does not make this path a hard link to *target*,
1323 despite the implication of the function and argument names. The order
1324 of arguments (target, link) is the reverse of Path.symlink_to, but
1325 matches that of os.link.
1326
Barney Galef24e2e52021-04-23 21:48:52 +01001327 Deprecated since Python 3.10 and scheduled for removal in Python 3.12.
1328 Use `hardlink_to()` instead.
Barney Gale8aac1be2021-04-07 16:56:32 +01001329 """
Barney Galef24e2e52021-04-23 21:48:52 +01001330 warnings.warn("pathlib.Path.link_to() is deprecated and is scheduled "
1331 "for removal in Python 3.12. "
1332 "Use pathlib.Path.hardlink_to() instead.",
1333 DeprecationWarning)
Barney Gale8aac1be2021-04-07 16:56:32 +01001334 self._accessor.link(self, target)
1335
Antoine Pitrou31119e42013-11-22 17:38:12 +01001336 # Convenience functions for querying the stat results
1337
1338 def exists(self):
1339 """
1340 Whether this path exists.
1341 """
1342 try:
1343 self.stat()
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 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001348 except ValueError:
1349 # Non-encodable path
1350 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001351 return True
1352
1353 def is_dir(self):
1354 """
1355 Whether this path is a directory.
1356 """
1357 try:
1358 return S_ISDIR(self.stat().st_mode)
1359 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001360 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001361 raise
1362 # Path doesn't exist or is a broken symlink
1363 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1364 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001365 except ValueError:
1366 # Non-encodable path
1367 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001368
1369 def is_file(self):
1370 """
1371 Whether this path is a regular file (also True for symlinks pointing
1372 to regular files).
1373 """
1374 try:
1375 return S_ISREG(self.stat().st_mode)
1376 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001377 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001378 raise
1379 # Path doesn't exist or is a broken symlink
1380 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1381 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001382 except ValueError:
1383 # Non-encodable path
1384 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001385
Cooper Lees173ff4a2017-08-01 15:35:45 -07001386 def is_mount(self):
1387 """
1388 Check if this path is a POSIX mount point
1389 """
1390 # Need to exist and be a dir
1391 if not self.exists() or not self.is_dir():
1392 return False
1393
Cooper Lees173ff4a2017-08-01 15:35:45 -07001394 try:
Barney Galec746c4f2020-04-17 18:42:06 +01001395 parent_dev = self.parent.stat().st_dev
Cooper Lees173ff4a2017-08-01 15:35:45 -07001396 except OSError:
1397 return False
1398
1399 dev = self.stat().st_dev
1400 if dev != parent_dev:
1401 return True
1402 ino = self.stat().st_ino
Barney Galec746c4f2020-04-17 18:42:06 +01001403 parent_ino = self.parent.stat().st_ino
Cooper Lees173ff4a2017-08-01 15:35:45 -07001404 return ino == parent_ino
1405
Antoine Pitrou31119e42013-11-22 17:38:12 +01001406 def is_symlink(self):
1407 """
1408 Whether this path is a symbolic link.
1409 """
1410 try:
1411 return S_ISLNK(self.lstat().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
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_block_device(self):
1422 """
1423 Whether this path is a block device.
1424 """
1425 try:
1426 return S_ISBLK(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_char_device(self):
1438 """
1439 Whether this path is a character device.
1440 """
1441 try:
1442 return S_ISCHR(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_fifo(self):
1454 """
1455 Whether this path is a FIFO.
1456 """
1457 try:
1458 return S_ISFIFO(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
1469 def is_socket(self):
1470 """
1471 Whether this path is a socket.
1472 """
1473 try:
1474 return S_ISSOCK(self.stat().st_mode)
1475 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001476 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001477 raise
1478 # Path doesn't exist or is a broken symlink
1479 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1480 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001481 except ValueError:
1482 # Non-encodable path
1483 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001484
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001485 def expanduser(self):
1486 """ Return a new path with expanded ~ and ~user constructs
1487 (as returned by os.path.expanduser)
1488 """
1489 if (not (self._drv or self._root) and
1490 self._parts and self._parts[0][:1] == '~'):
Barney Gale3f3d82b2021-04-07 23:50:13 +01001491 homedir = self._accessor.expanduser(self._parts[0])
1492 if homedir[:1] == "~":
1493 raise RuntimeError("Could not determine home directory.")
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001494 return self._from_parts([homedir] + self._parts[1:])
1495
1496 return self
1497
Antoine Pitrou31119e42013-11-22 17:38:12 +01001498
1499class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001500 """Path subclass for non-Windows systems.
1501
1502 On a POSIX system, instantiating a Path should return this object.
1503 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001504 __slots__ = ()
1505
1506class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001507 """Path subclass for Windows systems.
1508
1509 On a Windows system, instantiating a Path should return this object.
1510 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001511 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001512
Cooper Lees173ff4a2017-08-01 15:35:45 -07001513 def is_mount(self):
1514 raise NotImplementedError("Path.is_mount() is unsupported on this system")