blob: 851aabd479725fac0e5cdbc18e6886208ac3be09 [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
16supports_symlinks = True
Antoine Pitroudb118f52014-11-19 00:32:08 +010017if os.name == 'nt':
Antoine Pitrou31119e42013-11-22 17:38:12 +010018 import nt
Antoine Pitrou31119e42013-11-22 17:38:12 +010019 if sys.getwindowsversion()[:2] >= (6, 0):
20 from nt import _getfinalpathname
21 else:
22 supports_symlinks = False
23 _getfinalpathname = None
Antoine Pitroudb118f52014-11-19 00:32:08 +010024else:
25 nt = None
Antoine Pitrou31119e42013-11-22 17:38:12 +010026
27
28__all__ = [
29 "PurePath", "PurePosixPath", "PureWindowsPath",
30 "Path", "PosixPath", "WindowsPath",
31 ]
32
33#
34# Internals
35#
36
penguindustin96466302019-05-06 14:57:17 -040037# EBADF - guard against macOS `stat` throwing EBADF
Jörg Stucked5c120f2019-05-21 19:44:40 +020038_IGNORED_ERROS = (ENOENT, ENOTDIR, EBADF, ELOOP)
Przemysław Spodymek216b7452018-08-27 23:33:45 +020039
Steve Dower2f6fae62019-02-03 23:08:18 -080040_IGNORED_WINERRORS = (
41 21, # ERROR_NOT_READY - drive exists but is not accessible
Jörg Stucked5c120f2019-05-21 19:44:40 +020042 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
Steve Dower2f6fae62019-02-03 23:08:18 -080043)
44
45def _ignore_error(exception):
46 return (getattr(exception, 'errno', None) in _IGNORED_ERROS or
47 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
48
49
Antoine Pitrou31119e42013-11-22 17:38:12 +010050def _is_wildcard_pattern(pat):
51 # Whether this pattern needs actual matching using fnmatch, or can
52 # be looked up directly as a file.
53 return "*" in pat or "?" in pat or "[" in pat
54
55
56class _Flavour(object):
57 """A flavour implements a particular (platform-specific) set of path
58 semantics."""
59
60 def __init__(self):
61 self.join = self.sep.join
62
63 def parse_parts(self, parts):
64 parsed = []
65 sep = self.sep
66 altsep = self.altsep
67 drv = root = ''
68 it = reversed(parts)
69 for part in it:
70 if not part:
71 continue
72 if altsep:
73 part = part.replace(altsep, sep)
74 drv, root, rel = self.splitroot(part)
75 if sep in rel:
76 for x in reversed(rel.split(sep)):
77 if x and x != '.':
78 parsed.append(sys.intern(x))
79 else:
80 if rel and rel != '.':
81 parsed.append(sys.intern(rel))
82 if drv or root:
83 if not drv:
84 # If no drive is present, try to find one in the previous
85 # parts. This makes the result of parsing e.g.
86 # ("C:", "/", "a") reasonably intuitive.
87 for part in it:
Antoine Pitrou57fffd62015-02-15 18:03:59 +010088 if not part:
89 continue
90 if altsep:
91 part = part.replace(altsep, sep)
Antoine Pitrou31119e42013-11-22 17:38:12 +010092 drv = self.splitroot(part)[0]
93 if drv:
94 break
95 break
96 if drv or root:
97 parsed.append(drv + root)
98 parsed.reverse()
99 return drv, root, parsed
100
101 def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
102 """
103 Join the two paths represented by the respective
104 (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
105 """
106 if root2:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200107 if not drv2 and drv:
108 return drv, root2, [drv + root2] + parts2[1:]
109 elif drv2:
110 if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
111 # Same drive => second path is relative to the first
112 return drv, root, parts + parts2[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100113 else:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200114 # Second path is non-anchored (common case)
115 return drv, root, parts + parts2
116 return drv2, root2, parts2
Antoine Pitrou31119e42013-11-22 17:38:12 +0100117
118
119class _WindowsFlavour(_Flavour):
120 # Reference for Windows paths can be found at
121 # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
122
123 sep = '\\'
124 altsep = '/'
125 has_drv = True
126 pathmod = ntpath
127
Antoine Pitroudb118f52014-11-19 00:32:08 +0100128 is_supported = (os.name == 'nt')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100129
Jon Dufresne39726282017-05-18 07:35:54 -0700130 drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100131 ext_namespace_prefix = '\\\\?\\'
132
133 reserved_names = (
134 {'CON', 'PRN', 'AUX', 'NUL'} |
135 {'COM%d' % i for i in range(1, 10)} |
136 {'LPT%d' % i for i in range(1, 10)}
137 )
138
139 # Interesting findings about extended paths:
140 # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
141 # but '\\?\c:/a' is not
142 # - extended paths are always absolute; "relative" extended paths will
143 # fail.
144
145 def splitroot(self, part, sep=sep):
146 first = part[0:1]
147 second = part[1:2]
148 if (second == sep and first == sep):
149 # XXX extended paths should also disable the collapsing of "."
150 # components (according to MSDN docs).
151 prefix, part = self._split_extended_path(part)
152 first = part[0:1]
153 second = part[1:2]
154 else:
155 prefix = ''
156 third = part[2:3]
157 if (second == sep and first == sep and third != sep):
158 # is a UNC path:
159 # vvvvvvvvvvvvvvvvvvvvv root
160 # \\machine\mountpoint\directory\etc\...
161 # directory ^^^^^^^^^^^^^^
162 index = part.find(sep, 2)
163 if index != -1:
164 index2 = part.find(sep, index + 1)
165 # a UNC path can't have two slashes in a row
166 # (after the initial two)
167 if index2 != index + 1:
168 if index2 == -1:
169 index2 = len(part)
170 if prefix:
171 return prefix + part[1:index2], sep, part[index2+1:]
172 else:
173 return part[:index2], sep, part[index2+1:]
174 drv = root = ''
175 if second == ':' and first in self.drive_letters:
176 drv = part[:2]
177 part = part[2:]
178 first = third
179 if first == sep:
180 root = first
181 part = part.lstrip(sep)
182 return prefix + drv, root, part
183
184 def casefold(self, s):
185 return s.lower()
186
187 def casefold_parts(self, parts):
188 return [p.lower() for p in parts]
189
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300190 def compile_pattern(self, pattern):
191 return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
192
Steve Dower98eb3602016-11-09 12:58:17 -0800193 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100194 s = str(path)
195 if not s:
196 return os.getcwd()
Steve Dower98eb3602016-11-09 12:58:17 -0800197 previous_s = None
Antoine Pitrou31119e42013-11-22 17:38:12 +0100198 if _getfinalpathname is not None:
Steve Dower98eb3602016-11-09 12:58:17 -0800199 if strict:
200 return self._ext_to_normal(_getfinalpathname(s))
201 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200202 tail_parts = [] # End of the path after the first one not found
Steve Dower98eb3602016-11-09 12:58:17 -0800203 while True:
204 try:
205 s = self._ext_to_normal(_getfinalpathname(s))
206 except FileNotFoundError:
207 previous_s = s
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200208 s, tail = os.path.split(s)
209 tail_parts.append(tail)
Steve Dower4b1e98b2016-12-28 16:02:59 -0800210 if previous_s == s:
211 return path
Steve Dower98eb3602016-11-09 12:58:17 -0800212 else:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200213 return os.path.join(s, *reversed(tail_parts))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100214 # Means fallback on absolute
215 return None
216
217 def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
218 prefix = ''
219 if s.startswith(ext_prefix):
220 prefix = s[:4]
221 s = s[4:]
222 if s.startswith('UNC\\'):
223 prefix += s[:3]
224 s = '\\' + s[3:]
225 return prefix, s
226
227 def _ext_to_normal(self, s):
228 # Turn back an extended path into a normal DOS-like path
229 return self._split_extended_path(s)[1]
230
231 def is_reserved(self, parts):
232 # NOTE: the rules for reserved names seem somewhat complicated
233 # (e.g. r"..\NUL" is reserved but not r"foo\NUL").
234 # We err on the side of caution and return True for paths which are
235 # not considered reserved by Windows.
236 if not parts:
237 return False
238 if parts[0].startswith('\\\\'):
239 # UNC paths are never reserved
240 return False
241 return parts[-1].partition('.')[0].upper() in self.reserved_names
242
243 def make_uri(self, path):
244 # Under Windows, file URIs use the UTF-8 encoding.
245 drive = path.drive
246 if len(drive) == 2 and drive[1] == ':':
247 # It's a path on a local drive => 'file:///c:/a/b'
248 rest = path.as_posix()[2:].lstrip('/')
249 return 'file:///%s/%s' % (
250 drive, urlquote_from_bytes(rest.encode('utf-8')))
251 else:
252 # It's a path on a network drive => 'file://host/share/a/b'
253 return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
254
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100255 def gethomedir(self, username):
Christoph Reiterc45a2aa2020-01-28 10:41:50 +0100256 if 'USERPROFILE' in os.environ:
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100257 userhome = os.environ['USERPROFILE']
258 elif 'HOMEPATH' in os.environ:
Antoine Pitrou5d4e27e2014-12-30 22:09:42 +0100259 try:
260 drv = os.environ['HOMEDRIVE']
261 except KeyError:
262 drv = ''
263 userhome = drv + os.environ['HOMEPATH']
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100264 else:
265 raise RuntimeError("Can't determine home directory")
266
267 if username:
268 # Try to guess user home directory. By default all users
269 # directories are located in the same place and are named by
270 # corresponding usernames. If current user home directory points
271 # to nonstandard place, this guess is likely wrong.
272 if os.environ['USERNAME'] != username:
273 drv, root, parts = self.parse_parts((userhome,))
274 if parts[-1] != os.environ['USERNAME']:
275 raise RuntimeError("Can't determine home directory "
276 "for %r" % username)
277 parts[-1] = username
278 if drv or root:
279 userhome = drv + root + self.join(parts[1:])
280 else:
281 userhome = self.join(parts)
282 return userhome
Antoine Pitrou31119e42013-11-22 17:38:12 +0100283
284class _PosixFlavour(_Flavour):
285 sep = '/'
286 altsep = ''
287 has_drv = False
288 pathmod = posixpath
289
290 is_supported = (os.name != 'nt')
291
292 def splitroot(self, part, sep=sep):
293 if part and part[0] == sep:
294 stripped_part = part.lstrip(sep)
295 # According to POSIX path resolution:
296 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
297 # "A pathname that begins with two successive slashes may be
298 # interpreted in an implementation-defined manner, although more
299 # than two leading slashes shall be treated as a single slash".
300 if len(part) - len(stripped_part) == 2:
301 return '', sep * 2, stripped_part
302 else:
303 return '', sep, stripped_part
304 else:
305 return '', '', part
306
307 def casefold(self, s):
308 return s
309
310 def casefold_parts(self, parts):
311 return parts
312
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300313 def compile_pattern(self, pattern):
314 return re.compile(fnmatch.translate(pattern)).fullmatch
315
Steve Dower98eb3602016-11-09 12:58:17 -0800316 def resolve(self, path, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100317 sep = self.sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100318 accessor = path._accessor
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100319 seen = {}
320 def _resolve(path, rest):
321 if rest.startswith(sep):
322 path = ''
323
324 for name in rest.split(sep):
325 if not name or name == '.':
326 # current dir
327 continue
328 if name == '..':
329 # parent dir
330 path, _, _ = path.rpartition(sep)
331 continue
332 newpath = path + sep + name
333 if newpath in seen:
334 # Already seen this path
335 path = seen[newpath]
336 if path is not None:
337 # use cached value
338 continue
339 # The symlink is not resolved, so we must have a symlink loop.
340 raise RuntimeError("Symlink loop from %r" % newpath)
341 # Resolve the symbolic link
342 try:
343 target = accessor.readlink(newpath)
344 except OSError as e:
Antoine Pietriadd98eb2017-06-07 17:29:17 +0200345 if e.errno != EINVAL and strict:
346 raise
347 # Not a symlink, or non-strict mode. We just leave the path
348 # untouched.
Antoine Pitrouc274fd22013-12-16 19:57:41 +0100349 path = newpath
350 else:
351 seen[newpath] = None # not resolved symlink
352 path = _resolve(path, target)
353 seen[newpath] = path # resolved symlink
354
355 return path
356 # NOTE: according to POSIX, getcwd() cannot contain path components
357 # which are symlinks.
358 base = '' if path.is_absolute() else os.getcwd()
359 return _resolve(base, str(path)) or sep
Antoine Pitrou31119e42013-11-22 17:38:12 +0100360
361 def is_reserved(self, parts):
362 return False
363
364 def make_uri(self, path):
365 # We represent the path using the local filesystem encoding,
366 # for portability to other applications.
367 bpath = bytes(path)
368 return 'file://' + urlquote_from_bytes(bpath)
369
Antoine Pitrou8477ed62014-12-30 20:54:45 +0100370 def gethomedir(self, username):
371 if not username:
372 try:
373 return os.environ['HOME']
374 except KeyError:
375 import pwd
376 return pwd.getpwuid(os.getuid()).pw_dir
377 else:
378 import pwd
379 try:
380 return pwd.getpwnam(username).pw_dir
381 except KeyError:
382 raise RuntimeError("Can't determine home directory "
383 "for %r" % username)
384
Antoine Pitrou31119e42013-11-22 17:38:12 +0100385
386_windows_flavour = _WindowsFlavour()
387_posix_flavour = _PosixFlavour()
388
389
390class _Accessor:
391 """An accessor implements a particular (system-specific or not) way of
392 accessing paths on the filesystem."""
393
394
395class _NormalAccessor(_Accessor):
396
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200397 stat = os.stat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100398
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200399 lstat = os.lstat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100400
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200401 open = os.open
Antoine Pitrou31119e42013-11-22 17:38:12 +0100402
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200403 listdir = os.listdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100404
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200405 scandir = os.scandir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100406
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200407 chmod = os.chmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100408
409 if hasattr(os, "lchmod"):
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200410 lchmod = os.lchmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100411 else:
412 def lchmod(self, pathobj, mode):
413 raise NotImplementedError("lchmod() not available on this system")
414
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200415 mkdir = os.mkdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100416
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200417 unlink = os.unlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100418
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100419 if hasattr(os, "link"):
420 link_to = os.link
421 else:
422 @staticmethod
423 def link_to(self, target):
424 raise NotImplementedError("os.link() not available on this system")
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -0400425
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200426 rmdir = os.rmdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100427
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200428 rename = os.rename
Antoine Pitrou31119e42013-11-22 17:38:12 +0100429
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200430 replace = os.replace
Antoine Pitrou31119e42013-11-22 17:38:12 +0100431
432 if nt:
433 if supports_symlinks:
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200434 symlink = os.symlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100435 else:
436 def symlink(a, b, target_is_directory):
437 raise NotImplementedError("symlink() not available on this system")
438 else:
439 # Under POSIX, os.symlink() takes two args
440 @staticmethod
441 def symlink(a, b, target_is_directory):
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200442 return os.symlink(a, b)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100443
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200444 utime = os.utime
Antoine Pitrou31119e42013-11-22 17:38:12 +0100445
446 # Helper for resolve()
447 def readlink(self, path):
448 return os.readlink(path)
449
450
451_normal_accessor = _NormalAccessor()
452
453
454#
455# Globbing helpers
456#
457
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300458def _make_selector(pattern_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100459 pat = pattern_parts[0]
460 child_parts = pattern_parts[1:]
461 if pat == '**':
462 cls = _RecursiveWildcardSelector
463 elif '**' in pat:
464 raise ValueError("Invalid pattern: '**' can only be an entire path component")
465 elif _is_wildcard_pattern(pat):
466 cls = _WildcardSelector
467 else:
468 cls = _PreciseSelector
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300469 return cls(pat, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100470
471if hasattr(functools, "lru_cache"):
472 _make_selector = functools.lru_cache()(_make_selector)
473
474
475class _Selector:
476 """A selector matches a specific glob pattern part against the children
477 of a given path."""
478
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300479 def __init__(self, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100480 self.child_parts = child_parts
481 if child_parts:
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300482 self.successor = _make_selector(child_parts, flavour)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300483 self.dironly = True
Antoine Pitrou31119e42013-11-22 17:38:12 +0100484 else:
485 self.successor = _TerminatingSelector()
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300486 self.dironly = False
Antoine Pitrou31119e42013-11-22 17:38:12 +0100487
488 def select_from(self, parent_path):
489 """Iterate over all child paths of `parent_path` matched by this
490 selector. This can contain parent_path itself."""
491 path_cls = type(parent_path)
492 is_dir = path_cls.is_dir
493 exists = path_cls.exists
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300494 scandir = parent_path._accessor.scandir
495 if not is_dir(parent_path):
496 return iter([])
497 return self._select_from(parent_path, is_dir, exists, scandir)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100498
499
500class _TerminatingSelector:
501
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300502 def _select_from(self, parent_path, is_dir, exists, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100503 yield parent_path
504
505
506class _PreciseSelector(_Selector):
507
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300508 def __init__(self, name, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100509 self.name = name
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300510 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100511
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300512 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800513 try:
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800514 path = parent_path._make_child_relpath(self.name)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300515 if (is_dir if self.dironly else exists)(path):
516 for p in self.successor._select_from(path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800517 yield p
518 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100519 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100520
521
522class _WildcardSelector(_Selector):
523
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300524 def __init__(self, pat, child_parts, flavour):
525 self.match = flavour.compile_pattern(pat)
526 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100527
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300528 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800529 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300530 entries = list(scandir(parent_path))
531 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000532 if self.dironly:
533 try:
534 # "entry.is_dir()" can raise PermissionError
535 # in some cases (see bpo-38894), which is not
536 # among the errors ignored by _ignore_error()
537 if not entry.is_dir():
538 continue
539 except OSError as e:
540 if not _ignore_error(e):
541 raise
542 continue
543 name = entry.name
544 if self.match(name):
545 path = parent_path._make_child_relpath(name)
546 for p in self.successor._select_from(path, is_dir, exists, scandir):
547 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800548 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100549 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800550
Antoine Pitrou31119e42013-11-22 17:38:12 +0100551
Antoine Pitrou31119e42013-11-22 17:38:12 +0100552class _RecursiveWildcardSelector(_Selector):
553
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300554 def __init__(self, pat, child_parts, flavour):
555 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100556
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300557 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100558 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800559 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300560 entries = list(scandir(parent_path))
561 for entry in entries:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200562 entry_is_dir = False
563 try:
564 entry_is_dir = entry.is_dir()
565 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800566 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200567 raise
568 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300569 path = parent_path._make_child_relpath(entry.name)
570 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800571 yield p
572 except PermissionError:
573 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100574
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300575 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800576 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300577 yielded = set()
578 try:
579 successor_select = self.successor._select_from
580 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
581 for p in successor_select(starting_point, is_dir, exists, scandir):
582 if p not in yielded:
583 yield p
584 yielded.add(p)
585 finally:
586 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800587 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100588 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100589
590
591#
592# Public API
593#
594
595class _PathParents(Sequence):
596 """This object provides sequence-like access to the logical ancestors
597 of a path. Don't try to construct it yourself."""
598 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
599
600 def __init__(self, path):
601 # We don't store the instance to avoid reference cycles
602 self._pathcls = type(path)
603 self._drv = path._drv
604 self._root = path._root
605 self._parts = path._parts
606
607 def __len__(self):
608 if self._drv or self._root:
609 return len(self._parts) - 1
610 else:
611 return len(self._parts)
612
613 def __getitem__(self, idx):
614 if idx < 0 or idx >= len(self):
615 raise IndexError(idx)
616 return self._pathcls._from_parsed_parts(self._drv, self._root,
617 self._parts[:-idx - 1])
618
619 def __repr__(self):
620 return "<{}.parents>".format(self._pathcls.__name__)
621
622
623class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900624 """Base class for manipulating paths without I/O.
625
626 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100627 don't imply any actual filesystem I/O. Depending on your system,
628 instantiating a PurePath will return either a PurePosixPath or a
629 PureWindowsPath object. You can also instantiate either of these classes
630 directly, regardless of your system.
631 """
632 __slots__ = (
633 '_drv', '_root', '_parts',
634 '_str', '_hash', '_pparts', '_cached_cparts',
635 )
636
637 def __new__(cls, *args):
638 """Construct a PurePath from one or several strings and or existing
639 PurePath objects. The strings and path objects are combined so as
640 to yield a canonicalized path, which is incorporated into the
641 new PurePath object.
642 """
643 if cls is PurePath:
644 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
645 return cls._from_parts(args)
646
647 def __reduce__(self):
648 # Using the parts tuple helps share interned path parts
649 # when pickling related paths.
650 return (self.__class__, tuple(self._parts))
651
652 @classmethod
653 def _parse_args(cls, args):
654 # This is useful when you don't want to create an instance, just
655 # canonicalize some constructor arguments.
656 parts = []
657 for a in args:
658 if isinstance(a, PurePath):
659 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100660 else:
Brett Cannon568be632016-06-10 12:20:49 -0700661 a = os.fspath(a)
662 if isinstance(a, str):
663 # Force-cast str subclasses to str (issue #21127)
664 parts.append(str(a))
665 else:
666 raise TypeError(
667 "argument should be a str object or an os.PathLike "
668 "object returning str, not %r"
669 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100670 return cls._flavour.parse_parts(parts)
671
672 @classmethod
673 def _from_parts(cls, args, init=True):
674 # We need to call _parse_args on the instance, so as to get the
675 # right flavour.
676 self = object.__new__(cls)
677 drv, root, parts = self._parse_args(args)
678 self._drv = drv
679 self._root = root
680 self._parts = parts
681 if init:
682 self._init()
683 return self
684
685 @classmethod
686 def _from_parsed_parts(cls, drv, root, parts, init=True):
687 self = object.__new__(cls)
688 self._drv = drv
689 self._root = root
690 self._parts = parts
691 if init:
692 self._init()
693 return self
694
695 @classmethod
696 def _format_parsed_parts(cls, drv, root, parts):
697 if drv or root:
698 return drv + root + cls._flavour.join(parts[1:])
699 else:
700 return cls._flavour.join(parts)
701
702 def _init(self):
Martin Pantere26da7c2016-06-02 10:07:09 +0000703 # Overridden in concrete Path
Antoine Pitrou31119e42013-11-22 17:38:12 +0100704 pass
705
706 def _make_child(self, args):
707 drv, root, parts = self._parse_args(args)
708 drv, root, parts = self._flavour.join_parsed_parts(
709 self._drv, self._root, self._parts, drv, root, parts)
710 return self._from_parsed_parts(drv, root, parts)
711
712 def __str__(self):
713 """Return the string representation of the path, suitable for
714 passing to system calls."""
715 try:
716 return self._str
717 except AttributeError:
718 self._str = self._format_parsed_parts(self._drv, self._root,
719 self._parts) or '.'
720 return self._str
721
Brett Cannon568be632016-06-10 12:20:49 -0700722 def __fspath__(self):
723 return str(self)
724
Antoine Pitrou31119e42013-11-22 17:38:12 +0100725 def as_posix(self):
726 """Return the string representation of the path with forward (/)
727 slashes."""
728 f = self._flavour
729 return str(self).replace(f.sep, '/')
730
731 def __bytes__(self):
732 """Return the bytes representation of the path. This is only
733 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200734 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100735
736 def __repr__(self):
737 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
738
739 def as_uri(self):
740 """Return the path as a 'file' URI."""
741 if not self.is_absolute():
742 raise ValueError("relative path can't be expressed as a file URI")
743 return self._flavour.make_uri(self)
744
745 @property
746 def _cparts(self):
747 # Cached casefolded parts, for hashing and comparison
748 try:
749 return self._cached_cparts
750 except AttributeError:
751 self._cached_cparts = self._flavour.casefold_parts(self._parts)
752 return self._cached_cparts
753
754 def __eq__(self, other):
755 if not isinstance(other, PurePath):
756 return NotImplemented
757 return self._cparts == other._cparts and self._flavour is other._flavour
758
Antoine Pitrou31119e42013-11-22 17:38:12 +0100759 def __hash__(self):
760 try:
761 return self._hash
762 except AttributeError:
763 self._hash = hash(tuple(self._cparts))
764 return self._hash
765
766 def __lt__(self, other):
767 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
768 return NotImplemented
769 return self._cparts < other._cparts
770
771 def __le__(self, other):
772 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
773 return NotImplemented
774 return self._cparts <= other._cparts
775
776 def __gt__(self, other):
777 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
778 return NotImplemented
779 return self._cparts > other._cparts
780
781 def __ge__(self, other):
782 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
783 return NotImplemented
784 return self._cparts >= other._cparts
785
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300786 def __class_getitem__(cls, type):
787 return cls
788
Antoine Pitrou31119e42013-11-22 17:38:12 +0100789 drive = property(attrgetter('_drv'),
790 doc="""The drive prefix (letter or UNC path), if any.""")
791
792 root = property(attrgetter('_root'),
793 doc="""The root of the path, if any.""")
794
795 @property
796 def anchor(self):
797 """The concatenation of the drive and root, or ''."""
798 anchor = self._drv + self._root
799 return anchor
800
801 @property
802 def name(self):
803 """The final path component, if any."""
804 parts = self._parts
805 if len(parts) == (1 if (self._drv or self._root) else 0):
806 return ''
807 return parts[-1]
808
809 @property
810 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200811 """
812 The final component's last suffix, if any.
813
814 This includes the leading period. For example: '.txt'
815 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100816 name = self.name
817 i = name.rfind('.')
818 if 0 < i < len(name) - 1:
819 return name[i:]
820 else:
821 return ''
822
823 @property
824 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200825 """
826 A list of the final component's suffixes, if any.
827
828 These include the leading periods. For example: ['.tar', '.gz']
829 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100830 name = self.name
831 if name.endswith('.'):
832 return []
833 name = name.lstrip('.')
834 return ['.' + suffix for suffix in name.split('.')[1:]]
835
836 @property
837 def stem(self):
838 """The final path component, minus its last suffix."""
839 name = self.name
840 i = name.rfind('.')
841 if 0 < i < len(name) - 1:
842 return name[:i]
843 else:
844 return name
845
846 def with_name(self, name):
847 """Return a new path with the file name changed."""
848 if not self.name:
849 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400850 drv, root, parts = self._flavour.parse_parts((name,))
851 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
852 or drv or root or len(parts) != 1):
853 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100854 return self._from_parsed_parts(self._drv, self._root,
855 self._parts[:-1] + [name])
856
857 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200858 """Return a new path with the file suffix changed. If the path
859 has no suffix, add given suffix. If the given suffix is an empty
860 string, remove the suffix from the path.
861 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400862 f = self._flavour
863 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300864 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400865 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100866 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100867 name = self.name
868 if not name:
869 raise ValueError("%r has an empty name" % (self,))
870 old_suffix = self.suffix
871 if not old_suffix:
872 name = name + suffix
873 else:
874 name = name[:-len(old_suffix)] + suffix
875 return self._from_parsed_parts(self._drv, self._root,
876 self._parts[:-1] + [name])
877
878 def relative_to(self, *other):
879 """Return the relative path to another path identified by the passed
880 arguments. If the operation is not possible (because this is not
881 a subpath of the other path), raise ValueError.
882 """
883 # For the purpose of this method, drive and root are considered
884 # separate parts, i.e.:
885 # Path('c:/').relative_to('c:') gives Path('/')
886 # Path('c:/').relative_to('/') raise ValueError
887 if not other:
888 raise TypeError("need at least one argument")
889 parts = self._parts
890 drv = self._drv
891 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100892 if root:
893 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100894 else:
895 abs_parts = parts
896 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100897 if to_root:
898 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100899 else:
900 to_abs_parts = to_parts
901 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100902 cf = self._flavour.casefold_parts
903 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100904 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
905 raise ValueError("{!r} does not start with {!r}"
906 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100907 return self._from_parsed_parts('', root if n == 1 else '',
908 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100909
Hai Shi82642a02019-08-13 14:54:02 -0500910 def is_relative_to(self, *other):
911 """Return True if the path is relative to another path or False.
912 """
913 try:
914 self.relative_to(*other)
915 return True
916 except ValueError:
917 return False
918
Antoine Pitrou31119e42013-11-22 17:38:12 +0100919 @property
920 def parts(self):
921 """An object providing sequence-like access to the
922 components in the filesystem path."""
923 # We cache the tuple to avoid building a new one each time .parts
924 # is accessed. XXX is this necessary?
925 try:
926 return self._pparts
927 except AttributeError:
928 self._pparts = tuple(self._parts)
929 return self._pparts
930
931 def joinpath(self, *args):
932 """Combine this path with one or several arguments, and return a
933 new path representing either a subpath (if all arguments are relative
934 paths) or a totally different path (if one of the arguments is
935 anchored).
936 """
937 return self._make_child(args)
938
939 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400940 try:
941 return self._make_child((key,))
942 except TypeError:
943 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100944
945 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400946 try:
947 return self._from_parts([key] + self._parts)
948 except TypeError:
949 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100950
951 @property
952 def parent(self):
953 """The logical parent of the path."""
954 drv = self._drv
955 root = self._root
956 parts = self._parts
957 if len(parts) == 1 and (drv or root):
958 return self
959 return self._from_parsed_parts(drv, root, parts[:-1])
960
961 @property
962 def parents(self):
963 """A sequence of this path's logical parents."""
964 return _PathParents(self)
965
966 def is_absolute(self):
967 """True if the path is absolute (has both a root and, if applicable,
968 a drive)."""
969 if not self._root:
970 return False
971 return not self._flavour.has_drv or bool(self._drv)
972
973 def is_reserved(self):
974 """Return True if the path contains one of the special names reserved
975 by the system, if any."""
976 return self._flavour.is_reserved(self._parts)
977
978 def match(self, path_pattern):
979 """
980 Return True if this path matches the given pattern.
981 """
982 cf = self._flavour.casefold
983 path_pattern = cf(path_pattern)
984 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
985 if not pat_parts:
986 raise ValueError("empty pattern")
987 if drv and drv != cf(self._drv):
988 return False
989 if root and root != cf(self._root):
990 return False
991 parts = self._cparts
992 if drv or root:
993 if len(pat_parts) != len(parts):
994 return False
995 pat_parts = pat_parts[1:]
996 elif len(pat_parts) > len(parts):
997 return False
998 for part, pat in zip(reversed(parts), reversed(pat_parts)):
999 if not fnmatch.fnmatchcase(part, pat):
1000 return False
1001 return True
1002
Brett Cannon568be632016-06-10 12:20:49 -07001003# Can't subclass os.PathLike from PurePath and keep the constructor
1004# optimizations in PurePath._parse_args().
1005os.PathLike.register(PurePath)
1006
Antoine Pitrou31119e42013-11-22 17:38:12 +01001007
1008class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001009 """PurePath subclass for non-Windows systems.
1010
1011 On a POSIX system, instantiating a PurePath should return this object.
1012 However, you can also instantiate it directly on any system.
1013 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001014 _flavour = _posix_flavour
1015 __slots__ = ()
1016
1017
1018class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001019 """PurePath subclass for Windows systems.
1020
1021 On a Windows system, instantiating a PurePath should return this object.
1022 However, you can also instantiate it directly on any system.
1023 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001024 _flavour = _windows_flavour
1025 __slots__ = ()
1026
1027
1028# Filesystem-accessing classes
1029
1030
1031class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001032 """PurePath subclass that can make system calls.
1033
1034 Path represents a filesystem path but unlike PurePath, also offers
1035 methods to do system calls on path objects. Depending on your system,
1036 instantiating a Path will return either a PosixPath or a WindowsPath
1037 object. You can also instantiate a PosixPath or WindowsPath directly,
1038 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1039 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001040 __slots__ = (
1041 '_accessor',
1042 '_closed',
1043 )
1044
1045 def __new__(cls, *args, **kwargs):
1046 if cls is Path:
1047 cls = WindowsPath if os.name == 'nt' else PosixPath
1048 self = cls._from_parts(args, init=False)
1049 if not self._flavour.is_supported:
1050 raise NotImplementedError("cannot instantiate %r on your system"
1051 % (cls.__name__,))
1052 self._init()
1053 return self
1054
1055 def _init(self,
1056 # Private non-constructor arguments
1057 template=None,
1058 ):
1059 self._closed = False
1060 if template is not None:
1061 self._accessor = template._accessor
1062 else:
1063 self._accessor = _normal_accessor
1064
1065 def _make_child_relpath(self, part):
1066 # This is an optimization used for dir walking. `part` must be
1067 # a single part relative to this path.
1068 parts = self._parts + [part]
1069 return self._from_parsed_parts(self._drv, self._root, parts)
1070
1071 def __enter__(self):
1072 if self._closed:
1073 self._raise_closed()
1074 return self
1075
1076 def __exit__(self, t, v, tb):
1077 self._closed = True
1078
1079 def _raise_closed(self):
1080 raise ValueError("I/O operation on closed path")
1081
1082 def _opener(self, name, flags, mode=0o666):
1083 # A stub for the opener argument to built-in open()
1084 return self._accessor.open(self, flags, mode)
1085
Antoine Pitrou4a60d422013-12-02 21:25:18 +01001086 def _raw_open(self, flags, mode=0o777):
1087 """
1088 Open the file pointed by this path and return a file descriptor,
1089 as os.open() does.
1090 """
1091 if self._closed:
1092 self._raise_closed()
1093 return self._accessor.open(self, flags, mode)
1094
Antoine Pitrou31119e42013-11-22 17:38:12 +01001095 # Public API
1096
1097 @classmethod
1098 def cwd(cls):
1099 """Return a new path pointing to the current working directory
1100 (as returned by os.getcwd()).
1101 """
1102 return cls(os.getcwd())
1103
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001104 @classmethod
1105 def home(cls):
1106 """Return a new path pointing to the user's home directory (as
1107 returned by os.path.expanduser('~')).
1108 """
1109 return cls(cls()._flavour.gethomedir(None))
1110
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001111 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001112 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001113 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001114 """
1115 st = self.stat()
1116 try:
1117 other_st = other_path.stat()
1118 except AttributeError:
1119 other_st = os.stat(other_path)
1120 return os.path.samestat(st, other_st)
1121
Antoine Pitrou31119e42013-11-22 17:38:12 +01001122 def iterdir(self):
1123 """Iterate over the files in this directory. Does not yield any
1124 result for the special paths '.' and '..'.
1125 """
1126 if self._closed:
1127 self._raise_closed()
1128 for name in self._accessor.listdir(self):
1129 if name in {'.', '..'}:
1130 # Yielding a path object for these makes little sense
1131 continue
1132 yield self._make_child_relpath(name)
1133 if self._closed:
1134 self._raise_closed()
1135
1136 def glob(self, pattern):
1137 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001138 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001139 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001140 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001141 if not pattern:
1142 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001143 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1144 if drv or root:
1145 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001146 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001147 for p in selector.select_from(self):
1148 yield p
1149
1150 def rglob(self, pattern):
1151 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001152 directories) matching the given relative pattern, anywhere in
1153 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001154 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001155 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001156 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1157 if drv or root:
1158 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001159 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001160 for p in selector.select_from(self):
1161 yield p
1162
1163 def absolute(self):
1164 """Return an absolute version of this path. This function works
1165 even if the path doesn't point to anything.
1166
1167 No normalization is done, i.e. all '.' and '..' will be kept along.
1168 Use resolve() to get the canonical path to a file.
1169 """
1170 # XXX untested yet!
1171 if self._closed:
1172 self._raise_closed()
1173 if self.is_absolute():
1174 return self
1175 # FIXME this must defer to the specific flavour (and, under Windows,
1176 # use nt._getfullpathname())
1177 obj = self._from_parts([os.getcwd()] + self._parts, init=False)
1178 obj._init(template=self)
1179 return obj
1180
Steve Dower98eb3602016-11-09 12:58:17 -08001181 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001182 """
1183 Make the path absolute, resolving all symlinks on the way and also
1184 normalizing it (for example turning slashes into backslashes under
1185 Windows).
1186 """
1187 if self._closed:
1188 self._raise_closed()
Steve Dower98eb3602016-11-09 12:58:17 -08001189 s = self._flavour.resolve(self, strict=strict)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001190 if s is None:
1191 # No symlink resolution => for consistency, raise an error if
1192 # the path doesn't exist or is forbidden
1193 self.stat()
1194 s = str(self.absolute())
1195 # Now we have no symlinks in the path, it's safe to normalize it.
1196 normed = self._flavour.pathmod.normpath(s)
1197 obj = self._from_parts((normed,), init=False)
1198 obj._init(template=self)
1199 return obj
1200
1201 def stat(self):
1202 """
1203 Return the result of the stat() system call on this path, like
1204 os.stat() does.
1205 """
1206 return self._accessor.stat(self)
1207
1208 def owner(self):
1209 """
1210 Return the login name of the file owner.
1211 """
1212 import pwd
1213 return pwd.getpwuid(self.stat().st_uid).pw_name
1214
1215 def group(self):
1216 """
1217 Return the group name of the file gid.
1218 """
1219 import grp
1220 return grp.getgrgid(self.stat().st_gid).gr_name
1221
Antoine Pitrou31119e42013-11-22 17:38:12 +01001222 def open(self, mode='r', buffering=-1, encoding=None,
1223 errors=None, newline=None):
1224 """
1225 Open the file pointed by this path and return a file object, as
1226 the built-in open() function does.
1227 """
1228 if self._closed:
1229 self._raise_closed()
Serhiy Storchaka62a99512017-03-25 13:42:11 +02001230 return io.open(self, mode, buffering, encoding, errors, newline,
Antoine Pitrou31119e42013-11-22 17:38:12 +01001231 opener=self._opener)
1232
Georg Brandlea683982014-10-01 19:12:33 +02001233 def read_bytes(self):
1234 """
1235 Open the file in bytes mode, read it, and close the file.
1236 """
1237 with self.open(mode='rb') as f:
1238 return f.read()
1239
1240 def read_text(self, encoding=None, errors=None):
1241 """
1242 Open the file in text mode, read it, and close the file.
1243 """
1244 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1245 return f.read()
1246
1247 def write_bytes(self, data):
1248 """
1249 Open the file in bytes mode, write to it, and close the file.
1250 """
1251 # type-check for the buffer interface before truncating the file
1252 view = memoryview(data)
1253 with self.open(mode='wb') as f:
1254 return f.write(view)
1255
1256 def write_text(self, data, encoding=None, errors=None):
1257 """
1258 Open the file in text mode, write to it, and close the file.
1259 """
1260 if not isinstance(data, str):
1261 raise TypeError('data must be str, not %s' %
1262 data.__class__.__name__)
1263 with self.open(mode='w', encoding=encoding, errors=errors) as f:
1264 return f.write(data)
1265
Girtsa01ba332019-10-23 14:18:40 -07001266 def readlink(self):
1267 """
1268 Return the path to which the symbolic link points.
1269 """
1270 path = self._accessor.readlink(self)
1271 obj = self._from_parts((path,), init=False)
1272 obj._init(template=self)
1273 return obj
1274
Antoine Pitrou31119e42013-11-22 17:38:12 +01001275 def touch(self, mode=0o666, exist_ok=True):
1276 """
1277 Create this file with the given access mode, if it doesn't exist.
1278 """
1279 if self._closed:
1280 self._raise_closed()
1281 if exist_ok:
1282 # First try to bump modification time
1283 # Implementation note: GNU touch uses the UTIME_NOW option of
1284 # the utimensat() / futimens() functions.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001285 try:
Antoine Pitrou2cf39172013-11-23 15:25:59 +01001286 self._accessor.utime(self, None)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001287 except OSError:
1288 # Avoid exception chaining
1289 pass
1290 else:
1291 return
1292 flags = os.O_CREAT | os.O_WRONLY
1293 if not exist_ok:
1294 flags |= os.O_EXCL
1295 fd = self._raw_open(flags, mode)
1296 os.close(fd)
1297
Barry Warsaw7c549c42014-08-05 11:28:12 -04001298 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001299 """
1300 Create a new directory at this given path.
1301 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001302 if self._closed:
1303 self._raise_closed()
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001304 try:
1305 self._accessor.mkdir(self, mode)
1306 except FileNotFoundError:
1307 if not parents or self.parent == self:
1308 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001309 self.parent.mkdir(parents=True, exist_ok=True)
1310 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001311 except OSError:
1312 # Cannot rely on checking for EEXIST, since the operating system
1313 # could give priority to other errors like EACCES or EROFS
1314 if not exist_ok or not self.is_dir():
1315 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001316
1317 def chmod(self, mode):
1318 """
1319 Change the permissions of the path, like os.chmod().
1320 """
1321 if self._closed:
1322 self._raise_closed()
1323 self._accessor.chmod(self, mode)
1324
1325 def lchmod(self, mode):
1326 """
1327 Like chmod(), except if the path points to a symlink, the symlink's
1328 permissions are changed, rather than its target's.
1329 """
1330 if self._closed:
1331 self._raise_closed()
1332 self._accessor.lchmod(self, mode)
1333
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001334 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001335 """
1336 Remove this file or link.
1337 If the path is a directory, use rmdir() instead.
1338 """
1339 if self._closed:
1340 self._raise_closed()
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001341 try:
1342 self._accessor.unlink(self)
1343 except FileNotFoundError:
1344 if not missing_ok:
1345 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001346
1347 def rmdir(self):
1348 """
1349 Remove this directory. The directory must be empty.
1350 """
1351 if self._closed:
1352 self._raise_closed()
1353 self._accessor.rmdir(self)
1354
1355 def lstat(self):
1356 """
1357 Like stat(), except if the path points to a symlink, the symlink's
1358 status information is returned, rather than its target's.
1359 """
1360 if self._closed:
1361 self._raise_closed()
1362 return self._accessor.lstat(self)
1363
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -04001364 def link_to(self, target):
1365 """
1366 Create a hard link pointing to a path named target.
1367 """
1368 if self._closed:
1369 self._raise_closed()
1370 self._accessor.link_to(self, target)
1371
Antoine Pitrou31119e42013-11-22 17:38:12 +01001372 def rename(self, target):
1373 """
hui shang088a09a2019-09-11 21:26:49 +08001374 Rename this path to the given path,
1375 and return a new Path instance pointing to the given path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001376 """
1377 if self._closed:
1378 self._raise_closed()
1379 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001380 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001381
1382 def replace(self, target):
1383 """
1384 Rename this path to the given path, clobbering the existing
hui shang088a09a2019-09-11 21:26:49 +08001385 destination if it exists, and return a new Path instance
1386 pointing to the given path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001387 """
1388 if self._closed:
1389 self._raise_closed()
1390 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001391 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001392
1393 def symlink_to(self, target, target_is_directory=False):
1394 """
1395 Make this path a symlink pointing to the given path.
1396 Note the order of arguments (self, target) is the reverse of os.symlink's.
1397 """
1398 if self._closed:
1399 self._raise_closed()
1400 self._accessor.symlink(target, self, target_is_directory)
1401
1402 # Convenience functions for querying the stat results
1403
1404 def exists(self):
1405 """
1406 Whether this path exists.
1407 """
1408 try:
1409 self.stat()
1410 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001411 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001412 raise
1413 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001414 except ValueError:
1415 # Non-encodable path
1416 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001417 return True
1418
1419 def is_dir(self):
1420 """
1421 Whether this path is a directory.
1422 """
1423 try:
1424 return S_ISDIR(self.stat().st_mode)
1425 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001426 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001427 raise
1428 # Path doesn't exist or is a broken symlink
1429 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1430 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001431 except ValueError:
1432 # Non-encodable path
1433 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001434
1435 def is_file(self):
1436 """
1437 Whether this path is a regular file (also True for symlinks pointing
1438 to regular files).
1439 """
1440 try:
1441 return S_ISREG(self.stat().st_mode)
1442 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001443 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001444 raise
1445 # Path doesn't exist or is a broken symlink
1446 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1447 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001448 except ValueError:
1449 # Non-encodable path
1450 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001451
Cooper Lees173ff4a2017-08-01 15:35:45 -07001452 def is_mount(self):
1453 """
1454 Check if this path is a POSIX mount point
1455 """
1456 # Need to exist and be a dir
1457 if not self.exists() or not self.is_dir():
1458 return False
1459
1460 parent = Path(self.parent)
1461 try:
1462 parent_dev = parent.stat().st_dev
1463 except OSError:
1464 return False
1465
1466 dev = self.stat().st_dev
1467 if dev != parent_dev:
1468 return True
1469 ino = self.stat().st_ino
1470 parent_ino = parent.stat().st_ino
1471 return ino == parent_ino
1472
Antoine Pitrou31119e42013-11-22 17:38:12 +01001473 def is_symlink(self):
1474 """
1475 Whether this path is a symbolic link.
1476 """
1477 try:
1478 return S_ISLNK(self.lstat().st_mode)
1479 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001480 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001481 raise
1482 # Path doesn't exist
1483 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001484 except ValueError:
1485 # Non-encodable path
1486 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001487
1488 def is_block_device(self):
1489 """
1490 Whether this path is a block device.
1491 """
1492 try:
1493 return S_ISBLK(self.stat().st_mode)
1494 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001495 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001496 raise
1497 # Path doesn't exist or is a broken symlink
1498 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1499 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001500 except ValueError:
1501 # Non-encodable path
1502 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001503
1504 def is_char_device(self):
1505 """
1506 Whether this path is a character device.
1507 """
1508 try:
1509 return S_ISCHR(self.stat().st_mode)
1510 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001511 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001512 raise
1513 # Path doesn't exist or is a broken symlink
1514 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1515 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001516 except ValueError:
1517 # Non-encodable path
1518 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001519
1520 def is_fifo(self):
1521 """
1522 Whether this path is a FIFO.
1523 """
1524 try:
1525 return S_ISFIFO(self.stat().st_mode)
1526 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001527 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001528 raise
1529 # Path doesn't exist or is a broken symlink
1530 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1531 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001532 except ValueError:
1533 # Non-encodable path
1534 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001535
1536 def is_socket(self):
1537 """
1538 Whether this path is a socket.
1539 """
1540 try:
1541 return S_ISSOCK(self.stat().st_mode)
1542 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001543 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001544 raise
1545 # Path doesn't exist or is a broken symlink
1546 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1547 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001548 except ValueError:
1549 # Non-encodable path
1550 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001551
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001552 def expanduser(self):
1553 """ Return a new path with expanded ~ and ~user constructs
1554 (as returned by os.path.expanduser)
1555 """
1556 if (not (self._drv or self._root) and
1557 self._parts and self._parts[0][:1] == '~'):
1558 homedir = self._flavour.gethomedir(self._parts[0][1:])
1559 return self._from_parts([homedir] + self._parts[1:])
1560
1561 return self
1562
Antoine Pitrou31119e42013-11-22 17:38:12 +01001563
1564class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001565 """Path subclass for non-Windows systems.
1566
1567 On a POSIX system, instantiating a Path should return this object.
1568 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001569 __slots__ = ()
1570
1571class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001572 """Path subclass for Windows systems.
1573
1574 On a Windows system, instantiating a Path should return this object.
1575 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001576 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001577
1578 def owner(self):
1579 raise NotImplementedError("Path.owner() is unsupported on this system")
1580
1581 def group(self):
1582 raise NotImplementedError("Path.group() is unsupported on this system")
Cooper Lees173ff4a2017-08-01 15:35:45 -07001583
1584 def is_mount(self):
1585 raise NotImplementedError("Path.is_mount() is unsupported on this system")