blob: 96b8b59530c72397b2f5449859d9eb73e7a8505c [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 Storchaka704e2062020-03-11 18:42:03 +0200530 with scandir(parent_path) as scandir_it:
531 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300532 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000533 if self.dironly:
534 try:
535 # "entry.is_dir()" can raise PermissionError
536 # in some cases (see bpo-38894), which is not
537 # among the errors ignored by _ignore_error()
538 if not entry.is_dir():
539 continue
540 except OSError as e:
541 if not _ignore_error(e):
542 raise
543 continue
544 name = entry.name
545 if self.match(name):
546 path = parent_path._make_child_relpath(name)
547 for p in self.successor._select_from(path, is_dir, exists, scandir):
548 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800549 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100550 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800551
Antoine Pitrou31119e42013-11-22 17:38:12 +0100552
Antoine Pitrou31119e42013-11-22 17:38:12 +0100553class _RecursiveWildcardSelector(_Selector):
554
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300555 def __init__(self, pat, child_parts, flavour):
556 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100557
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300558 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100559 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800560 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200561 with scandir(parent_path) as scandir_it:
562 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300563 for entry in entries:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200564 entry_is_dir = False
565 try:
566 entry_is_dir = entry.is_dir()
567 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800568 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200569 raise
570 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300571 path = parent_path._make_child_relpath(entry.name)
572 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800573 yield p
574 except PermissionError:
575 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100576
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300577 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800578 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300579 yielded = set()
580 try:
581 successor_select = self.successor._select_from
582 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
583 for p in successor_select(starting_point, is_dir, exists, scandir):
584 if p not in yielded:
585 yield p
586 yielded.add(p)
587 finally:
588 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800589 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100590 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100591
592
593#
594# Public API
595#
596
597class _PathParents(Sequence):
598 """This object provides sequence-like access to the logical ancestors
599 of a path. Don't try to construct it yourself."""
600 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
601
602 def __init__(self, path):
603 # We don't store the instance to avoid reference cycles
604 self._pathcls = type(path)
605 self._drv = path._drv
606 self._root = path._root
607 self._parts = path._parts
608
609 def __len__(self):
610 if self._drv or self._root:
611 return len(self._parts) - 1
612 else:
613 return len(self._parts)
614
615 def __getitem__(self, idx):
616 if idx < 0 or idx >= len(self):
617 raise IndexError(idx)
618 return self._pathcls._from_parsed_parts(self._drv, self._root,
619 self._parts[:-idx - 1])
620
621 def __repr__(self):
622 return "<{}.parents>".format(self._pathcls.__name__)
623
624
625class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900626 """Base class for manipulating paths without I/O.
627
628 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100629 don't imply any actual filesystem I/O. Depending on your system,
630 instantiating a PurePath will return either a PurePosixPath or a
631 PureWindowsPath object. You can also instantiate either of these classes
632 directly, regardless of your system.
633 """
634 __slots__ = (
635 '_drv', '_root', '_parts',
636 '_str', '_hash', '_pparts', '_cached_cparts',
637 )
638
639 def __new__(cls, *args):
640 """Construct a PurePath from one or several strings and or existing
641 PurePath objects. The strings and path objects are combined so as
642 to yield a canonicalized path, which is incorporated into the
643 new PurePath object.
644 """
645 if cls is PurePath:
646 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
647 return cls._from_parts(args)
648
649 def __reduce__(self):
650 # Using the parts tuple helps share interned path parts
651 # when pickling related paths.
652 return (self.__class__, tuple(self._parts))
653
654 @classmethod
655 def _parse_args(cls, args):
656 # This is useful when you don't want to create an instance, just
657 # canonicalize some constructor arguments.
658 parts = []
659 for a in args:
660 if isinstance(a, PurePath):
661 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100662 else:
Brett Cannon568be632016-06-10 12:20:49 -0700663 a = os.fspath(a)
664 if isinstance(a, str):
665 # Force-cast str subclasses to str (issue #21127)
666 parts.append(str(a))
667 else:
668 raise TypeError(
669 "argument should be a str object or an os.PathLike "
670 "object returning str, not %r"
671 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100672 return cls._flavour.parse_parts(parts)
673
674 @classmethod
675 def _from_parts(cls, args, init=True):
676 # We need to call _parse_args on the instance, so as to get the
677 # right flavour.
678 self = object.__new__(cls)
679 drv, root, parts = self._parse_args(args)
680 self._drv = drv
681 self._root = root
682 self._parts = parts
683 if init:
684 self._init()
685 return self
686
687 @classmethod
688 def _from_parsed_parts(cls, drv, root, parts, init=True):
689 self = object.__new__(cls)
690 self._drv = drv
691 self._root = root
692 self._parts = parts
693 if init:
694 self._init()
695 return self
696
697 @classmethod
698 def _format_parsed_parts(cls, drv, root, parts):
699 if drv or root:
700 return drv + root + cls._flavour.join(parts[1:])
701 else:
702 return cls._flavour.join(parts)
703
704 def _init(self):
Martin Pantere26da7c2016-06-02 10:07:09 +0000705 # Overridden in concrete Path
Antoine Pitrou31119e42013-11-22 17:38:12 +0100706 pass
707
708 def _make_child(self, args):
709 drv, root, parts = self._parse_args(args)
710 drv, root, parts = self._flavour.join_parsed_parts(
711 self._drv, self._root, self._parts, drv, root, parts)
712 return self._from_parsed_parts(drv, root, parts)
713
714 def __str__(self):
715 """Return the string representation of the path, suitable for
716 passing to system calls."""
717 try:
718 return self._str
719 except AttributeError:
720 self._str = self._format_parsed_parts(self._drv, self._root,
721 self._parts) or '.'
722 return self._str
723
Brett Cannon568be632016-06-10 12:20:49 -0700724 def __fspath__(self):
725 return str(self)
726
Antoine Pitrou31119e42013-11-22 17:38:12 +0100727 def as_posix(self):
728 """Return the string representation of the path with forward (/)
729 slashes."""
730 f = self._flavour
731 return str(self).replace(f.sep, '/')
732
733 def __bytes__(self):
734 """Return the bytes representation of the path. This is only
735 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200736 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100737
738 def __repr__(self):
739 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
740
741 def as_uri(self):
742 """Return the path as a 'file' URI."""
743 if not self.is_absolute():
744 raise ValueError("relative path can't be expressed as a file URI")
745 return self._flavour.make_uri(self)
746
747 @property
748 def _cparts(self):
749 # Cached casefolded parts, for hashing and comparison
750 try:
751 return self._cached_cparts
752 except AttributeError:
753 self._cached_cparts = self._flavour.casefold_parts(self._parts)
754 return self._cached_cparts
755
756 def __eq__(self, other):
757 if not isinstance(other, PurePath):
758 return NotImplemented
759 return self._cparts == other._cparts and self._flavour is other._flavour
760
Antoine Pitrou31119e42013-11-22 17:38:12 +0100761 def __hash__(self):
762 try:
763 return self._hash
764 except AttributeError:
765 self._hash = hash(tuple(self._cparts))
766 return self._hash
767
768 def __lt__(self, other):
769 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
770 return NotImplemented
771 return self._cparts < other._cparts
772
773 def __le__(self, other):
774 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
775 return NotImplemented
776 return self._cparts <= other._cparts
777
778 def __gt__(self, other):
779 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
780 return NotImplemented
781 return self._cparts > other._cparts
782
783 def __ge__(self, other):
784 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
785 return NotImplemented
786 return self._cparts >= other._cparts
787
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300788 def __class_getitem__(cls, type):
789 return cls
790
Antoine Pitrou31119e42013-11-22 17:38:12 +0100791 drive = property(attrgetter('_drv'),
792 doc="""The drive prefix (letter or UNC path), if any.""")
793
794 root = property(attrgetter('_root'),
795 doc="""The root of the path, if any.""")
796
797 @property
798 def anchor(self):
799 """The concatenation of the drive and root, or ''."""
800 anchor = self._drv + self._root
801 return anchor
802
803 @property
804 def name(self):
805 """The final path component, if any."""
806 parts = self._parts
807 if len(parts) == (1 if (self._drv or self._root) else 0):
808 return ''
809 return parts[-1]
810
811 @property
812 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200813 """
814 The final component's last suffix, if any.
815
816 This includes the leading period. For example: '.txt'
817 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100818 name = self.name
819 i = name.rfind('.')
820 if 0 < i < len(name) - 1:
821 return name[i:]
822 else:
823 return ''
824
825 @property
826 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200827 """
828 A list of the final component's suffixes, if any.
829
830 These include the leading periods. For example: ['.tar', '.gz']
831 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100832 name = self.name
833 if name.endswith('.'):
834 return []
835 name = name.lstrip('.')
836 return ['.' + suffix for suffix in name.split('.')[1:]]
837
838 @property
839 def stem(self):
840 """The final path component, minus its last suffix."""
841 name = self.name
842 i = name.rfind('.')
843 if 0 < i < len(name) - 1:
844 return name[:i]
845 else:
846 return name
847
848 def with_name(self, name):
849 """Return a new path with the file name changed."""
850 if not self.name:
851 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400852 drv, root, parts = self._flavour.parse_parts((name,))
853 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
854 or drv or root or len(parts) != 1):
855 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100856 return self._from_parsed_parts(self._drv, self._root,
857 self._parts[:-1] + [name])
858
859 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200860 """Return a new path with the file suffix changed. If the path
861 has no suffix, add given suffix. If the given suffix is an empty
862 string, remove the suffix from the path.
863 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400864 f = self._flavour
865 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300866 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400867 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100868 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100869 name = self.name
870 if not name:
871 raise ValueError("%r has an empty name" % (self,))
872 old_suffix = self.suffix
873 if not old_suffix:
874 name = name + suffix
875 else:
876 name = name[:-len(old_suffix)] + suffix
877 return self._from_parsed_parts(self._drv, self._root,
878 self._parts[:-1] + [name])
879
880 def relative_to(self, *other):
881 """Return the relative path to another path identified by the passed
882 arguments. If the operation is not possible (because this is not
883 a subpath of the other path), raise ValueError.
884 """
885 # For the purpose of this method, drive and root are considered
886 # separate parts, i.e.:
887 # Path('c:/').relative_to('c:') gives Path('/')
888 # Path('c:/').relative_to('/') raise ValueError
889 if not other:
890 raise TypeError("need at least one argument")
891 parts = self._parts
892 drv = self._drv
893 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100894 if root:
895 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100896 else:
897 abs_parts = parts
898 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100899 if to_root:
900 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100901 else:
902 to_abs_parts = to_parts
903 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100904 cf = self._flavour.casefold_parts
905 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100906 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
907 raise ValueError("{!r} does not start with {!r}"
908 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100909 return self._from_parsed_parts('', root if n == 1 else '',
910 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100911
Hai Shi82642a02019-08-13 14:54:02 -0500912 def is_relative_to(self, *other):
913 """Return True if the path is relative to another path or False.
914 """
915 try:
916 self.relative_to(*other)
917 return True
918 except ValueError:
919 return False
920
Antoine Pitrou31119e42013-11-22 17:38:12 +0100921 @property
922 def parts(self):
923 """An object providing sequence-like access to the
924 components in the filesystem path."""
925 # We cache the tuple to avoid building a new one each time .parts
926 # is accessed. XXX is this necessary?
927 try:
928 return self._pparts
929 except AttributeError:
930 self._pparts = tuple(self._parts)
931 return self._pparts
932
933 def joinpath(self, *args):
934 """Combine this path with one or several arguments, and return a
935 new path representing either a subpath (if all arguments are relative
936 paths) or a totally different path (if one of the arguments is
937 anchored).
938 """
939 return self._make_child(args)
940
941 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400942 try:
943 return self._make_child((key,))
944 except TypeError:
945 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100946
947 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400948 try:
949 return self._from_parts([key] + self._parts)
950 except TypeError:
951 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100952
953 @property
954 def parent(self):
955 """The logical parent of the path."""
956 drv = self._drv
957 root = self._root
958 parts = self._parts
959 if len(parts) == 1 and (drv or root):
960 return self
961 return self._from_parsed_parts(drv, root, parts[:-1])
962
963 @property
964 def parents(self):
965 """A sequence of this path's logical parents."""
966 return _PathParents(self)
967
968 def is_absolute(self):
969 """True if the path is absolute (has both a root and, if applicable,
970 a drive)."""
971 if not self._root:
972 return False
973 return not self._flavour.has_drv or bool(self._drv)
974
975 def is_reserved(self):
976 """Return True if the path contains one of the special names reserved
977 by the system, if any."""
978 return self._flavour.is_reserved(self._parts)
979
980 def match(self, path_pattern):
981 """
982 Return True if this path matches the given pattern.
983 """
984 cf = self._flavour.casefold
985 path_pattern = cf(path_pattern)
986 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
987 if not pat_parts:
988 raise ValueError("empty pattern")
989 if drv and drv != cf(self._drv):
990 return False
991 if root and root != cf(self._root):
992 return False
993 parts = self._cparts
994 if drv or root:
995 if len(pat_parts) != len(parts):
996 return False
997 pat_parts = pat_parts[1:]
998 elif len(pat_parts) > len(parts):
999 return False
1000 for part, pat in zip(reversed(parts), reversed(pat_parts)):
1001 if not fnmatch.fnmatchcase(part, pat):
1002 return False
1003 return True
1004
Brett Cannon568be632016-06-10 12:20:49 -07001005# Can't subclass os.PathLike from PurePath and keep the constructor
1006# optimizations in PurePath._parse_args().
1007os.PathLike.register(PurePath)
1008
Antoine Pitrou31119e42013-11-22 17:38:12 +01001009
1010class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001011 """PurePath subclass for non-Windows systems.
1012
1013 On a POSIX system, instantiating a PurePath should return this object.
1014 However, you can also instantiate it directly on any system.
1015 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001016 _flavour = _posix_flavour
1017 __slots__ = ()
1018
1019
1020class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001021 """PurePath subclass for Windows systems.
1022
1023 On a Windows system, instantiating a PurePath should return this object.
1024 However, you can also instantiate it directly on any system.
1025 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001026 _flavour = _windows_flavour
1027 __slots__ = ()
1028
1029
1030# Filesystem-accessing classes
1031
1032
1033class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +09001034 """PurePath subclass that can make system calls.
1035
1036 Path represents a filesystem path but unlike PurePath, also offers
1037 methods to do system calls on path objects. Depending on your system,
1038 instantiating a Path will return either a PosixPath or a WindowsPath
1039 object. You can also instantiate a PosixPath or WindowsPath directly,
1040 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1041 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001042 __slots__ = (
1043 '_accessor',
Antoine Pitrou31119e42013-11-22 17:38:12 +01001044 )
1045
1046 def __new__(cls, *args, **kwargs):
1047 if cls is Path:
1048 cls = WindowsPath if os.name == 'nt' else PosixPath
1049 self = cls._from_parts(args, init=False)
1050 if not self._flavour.is_supported:
1051 raise NotImplementedError("cannot instantiate %r on your system"
1052 % (cls.__name__,))
1053 self._init()
1054 return self
1055
1056 def _init(self,
1057 # Private non-constructor arguments
1058 template=None,
1059 ):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001060 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):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001072 return self
1073
1074 def __exit__(self, t, v, tb):
Barney Gale00002e62020-04-01 15:10:51 +01001075 # https://bugs.python.org/issue39682
1076 # In previous versions of pathlib, this method marked this path as
1077 # closed; subsequent attempts to perform I/O would raise an IOError.
1078 # This functionality was never documented, and had the effect of
1079 # making Path objects mutable, contrary to PEP 428. In Python 3.9 the
1080 # _closed attribute was removed, and this method made a no-op.
1081 # This method and __enter__()/__exit__() should be deprecated and
1082 # removed in the future.
1083 pass
Antoine Pitrou31119e42013-11-22 17:38:12 +01001084
1085 def _opener(self, name, flags, mode=0o666):
1086 # A stub for the opener argument to built-in open()
1087 return self._accessor.open(self, flags, mode)
1088
Antoine Pitrou4a60d422013-12-02 21:25:18 +01001089 def _raw_open(self, flags, mode=0o777):
1090 """
1091 Open the file pointed by this path and return a file descriptor,
1092 as os.open() does.
1093 """
Antoine Pitrou4a60d422013-12-02 21:25:18 +01001094 return self._accessor.open(self, flags, mode)
1095
Antoine Pitrou31119e42013-11-22 17:38:12 +01001096 # Public API
1097
1098 @classmethod
1099 def cwd(cls):
1100 """Return a new path pointing to the current working directory
1101 (as returned by os.getcwd()).
1102 """
1103 return cls(os.getcwd())
1104
Antoine Pitrou17cba7d2015-01-12 21:03:41 +01001105 @classmethod
1106 def home(cls):
1107 """Return a new path pointing to the user's home directory (as
1108 returned by os.path.expanduser('~')).
1109 """
1110 return cls(cls()._flavour.gethomedir(None))
1111
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001112 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001113 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001114 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001115 """
1116 st = self.stat()
1117 try:
1118 other_st = other_path.stat()
1119 except AttributeError:
1120 other_st = os.stat(other_path)
1121 return os.path.samestat(st, other_st)
1122
Antoine Pitrou31119e42013-11-22 17:38:12 +01001123 def iterdir(self):
1124 """Iterate over the files in this directory. Does not yield any
1125 result for the special paths '.' and '..'.
1126 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001127 for name in self._accessor.listdir(self):
1128 if name in {'.', '..'}:
1129 # Yielding a path object for these makes little sense
1130 continue
1131 yield self._make_child_relpath(name)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001132
1133 def glob(self, pattern):
1134 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001135 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001136 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001137 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001138 if not pattern:
1139 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001140 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1141 if drv or root:
1142 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001143 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001144 for p in selector.select_from(self):
1145 yield p
1146
1147 def rglob(self, pattern):
1148 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001149 directories) matching the given relative pattern, anywhere in
1150 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001151 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001152 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001153 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1154 if drv or root:
1155 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001156 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001157 for p in selector.select_from(self):
1158 yield p
1159
1160 def absolute(self):
1161 """Return an absolute version of this path. This function works
1162 even if the path doesn't point to anything.
1163
1164 No normalization is done, i.e. all '.' and '..' will be kept along.
1165 Use resolve() to get the canonical path to a file.
1166 """
1167 # XXX untested yet!
Antoine Pitrou31119e42013-11-22 17:38:12 +01001168 if self.is_absolute():
1169 return self
1170 # FIXME this must defer to the specific flavour (and, under Windows,
1171 # use nt._getfullpathname())
1172 obj = self._from_parts([os.getcwd()] + self._parts, init=False)
1173 obj._init(template=self)
1174 return obj
1175
Steve Dower98eb3602016-11-09 12:58:17 -08001176 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001177 """
1178 Make the path absolute, resolving all symlinks on the way and also
1179 normalizing it (for example turning slashes into backslashes under
1180 Windows).
1181 """
Steve Dower98eb3602016-11-09 12:58:17 -08001182 s = self._flavour.resolve(self, strict=strict)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001183 if s is None:
1184 # No symlink resolution => for consistency, raise an error if
1185 # the path doesn't exist or is forbidden
1186 self.stat()
1187 s = str(self.absolute())
1188 # Now we have no symlinks in the path, it's safe to normalize it.
1189 normed = self._flavour.pathmod.normpath(s)
1190 obj = self._from_parts((normed,), init=False)
1191 obj._init(template=self)
1192 return obj
1193
1194 def stat(self):
1195 """
1196 Return the result of the stat() system call on this path, like
1197 os.stat() does.
1198 """
1199 return self._accessor.stat(self)
1200
1201 def owner(self):
1202 """
1203 Return the login name of the file owner.
1204 """
1205 import pwd
1206 return pwd.getpwuid(self.stat().st_uid).pw_name
1207
1208 def group(self):
1209 """
1210 Return the group name of the file gid.
1211 """
1212 import grp
1213 return grp.getgrgid(self.stat().st_gid).gr_name
1214
Antoine Pitrou31119e42013-11-22 17:38:12 +01001215 def open(self, mode='r', buffering=-1, encoding=None,
1216 errors=None, newline=None):
1217 """
1218 Open the file pointed by this path and return a file object, as
1219 the built-in open() function does.
1220 """
Serhiy Storchaka62a99512017-03-25 13:42:11 +02001221 return io.open(self, mode, buffering, encoding, errors, newline,
Antoine Pitrou31119e42013-11-22 17:38:12 +01001222 opener=self._opener)
1223
Georg Brandlea683982014-10-01 19:12:33 +02001224 def read_bytes(self):
1225 """
1226 Open the file in bytes mode, read it, and close the file.
1227 """
1228 with self.open(mode='rb') as f:
1229 return f.read()
1230
1231 def read_text(self, encoding=None, errors=None):
1232 """
1233 Open the file in text mode, read it, and close the file.
1234 """
1235 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1236 return f.read()
1237
1238 def write_bytes(self, data):
1239 """
1240 Open the file in bytes mode, write to it, and close the file.
1241 """
1242 # type-check for the buffer interface before truncating the file
1243 view = memoryview(data)
1244 with self.open(mode='wb') as f:
1245 return f.write(view)
1246
1247 def write_text(self, data, encoding=None, errors=None):
1248 """
1249 Open the file in text mode, write to it, and close the file.
1250 """
1251 if not isinstance(data, str):
1252 raise TypeError('data must be str, not %s' %
1253 data.__class__.__name__)
1254 with self.open(mode='w', encoding=encoding, errors=errors) as f:
1255 return f.write(data)
1256
Girtsa01ba332019-10-23 14:18:40 -07001257 def readlink(self):
1258 """
1259 Return the path to which the symbolic link points.
1260 """
1261 path = self._accessor.readlink(self)
1262 obj = self._from_parts((path,), init=False)
1263 obj._init(template=self)
1264 return obj
1265
Antoine Pitrou31119e42013-11-22 17:38:12 +01001266 def touch(self, mode=0o666, exist_ok=True):
1267 """
1268 Create this file with the given access mode, if it doesn't exist.
1269 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001270 if exist_ok:
1271 # First try to bump modification time
1272 # Implementation note: GNU touch uses the UTIME_NOW option of
1273 # the utimensat() / futimens() functions.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001274 try:
Antoine Pitrou2cf39172013-11-23 15:25:59 +01001275 self._accessor.utime(self, None)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001276 except OSError:
1277 # Avoid exception chaining
1278 pass
1279 else:
1280 return
1281 flags = os.O_CREAT | os.O_WRONLY
1282 if not exist_ok:
1283 flags |= os.O_EXCL
1284 fd = self._raw_open(flags, mode)
1285 os.close(fd)
1286
Barry Warsaw7c549c42014-08-05 11:28:12 -04001287 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001288 """
1289 Create a new directory at this given path.
1290 """
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001291 try:
1292 self._accessor.mkdir(self, mode)
1293 except FileNotFoundError:
1294 if not parents or self.parent == self:
1295 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001296 self.parent.mkdir(parents=True, exist_ok=True)
1297 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001298 except OSError:
1299 # Cannot rely on checking for EEXIST, since the operating system
1300 # could give priority to other errors like EACCES or EROFS
1301 if not exist_ok or not self.is_dir():
1302 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001303
1304 def chmod(self, mode):
1305 """
1306 Change the permissions of the path, like os.chmod().
1307 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001308 self._accessor.chmod(self, mode)
1309
1310 def lchmod(self, mode):
1311 """
1312 Like chmod(), except if the path points to a symlink, the symlink's
1313 permissions are changed, rather than its target's.
1314 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001315 self._accessor.lchmod(self, mode)
1316
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001317 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001318 """
1319 Remove this file or link.
1320 If the path is a directory, use rmdir() instead.
1321 """
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001322 try:
1323 self._accessor.unlink(self)
1324 except FileNotFoundError:
1325 if not missing_ok:
1326 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001327
1328 def rmdir(self):
1329 """
1330 Remove this directory. The directory must be empty.
1331 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001332 self._accessor.rmdir(self)
1333
1334 def lstat(self):
1335 """
1336 Like stat(), except if the path points to a symlink, the symlink's
1337 status information is returned, rather than its target's.
1338 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001339 return self._accessor.lstat(self)
1340
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -04001341 def link_to(self, target):
1342 """
1343 Create a hard link pointing to a path named target.
1344 """
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -04001345 self._accessor.link_to(self, target)
1346
Antoine Pitrou31119e42013-11-22 17:38:12 +01001347 def rename(self, target):
1348 """
hui shang088a09a2019-09-11 21:26:49 +08001349 Rename this path to the given path,
1350 and return a new Path instance pointing to the given path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001351 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001352 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001353 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001354
1355 def replace(self, target):
1356 """
1357 Rename this path to the given path, clobbering the existing
hui shang088a09a2019-09-11 21:26:49 +08001358 destination if it exists, and return a new Path instance
1359 pointing to the given path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001360 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001361 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001362 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001363
1364 def symlink_to(self, target, target_is_directory=False):
1365 """
1366 Make this path a symlink pointing to the given path.
1367 Note the order of arguments (self, target) is the reverse of os.symlink's.
1368 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001369 self._accessor.symlink(target, self, target_is_directory)
1370
1371 # Convenience functions for querying the stat results
1372
1373 def exists(self):
1374 """
1375 Whether this path exists.
1376 """
1377 try:
1378 self.stat()
1379 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001380 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001381 raise
1382 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001383 except ValueError:
1384 # Non-encodable path
1385 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001386 return True
1387
1388 def is_dir(self):
1389 """
1390 Whether this path is a directory.
1391 """
1392 try:
1393 return S_ISDIR(self.stat().st_mode)
1394 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001395 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001396 raise
1397 # Path doesn't exist or is a broken symlink
1398 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1399 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001400 except ValueError:
1401 # Non-encodable path
1402 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001403
1404 def is_file(self):
1405 """
1406 Whether this path is a regular file (also True for symlinks pointing
1407 to regular files).
1408 """
1409 try:
1410 return S_ISREG(self.stat().st_mode)
1411 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001412 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001413 raise
1414 # Path doesn't exist or is a broken symlink
1415 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1416 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001417 except ValueError:
1418 # Non-encodable path
1419 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001420
Cooper Lees173ff4a2017-08-01 15:35:45 -07001421 def is_mount(self):
1422 """
1423 Check if this path is a POSIX mount point
1424 """
1425 # Need to exist and be a dir
1426 if not self.exists() or not self.is_dir():
1427 return False
1428
1429 parent = Path(self.parent)
1430 try:
1431 parent_dev = parent.stat().st_dev
1432 except OSError:
1433 return False
1434
1435 dev = self.stat().st_dev
1436 if dev != parent_dev:
1437 return True
1438 ino = self.stat().st_ino
1439 parent_ino = parent.stat().st_ino
1440 return ino == parent_ino
1441
Antoine Pitrou31119e42013-11-22 17:38:12 +01001442 def is_symlink(self):
1443 """
1444 Whether this path is a symbolic link.
1445 """
1446 try:
1447 return S_ISLNK(self.lstat().st_mode)
1448 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001449 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001450 raise
1451 # Path doesn't exist
1452 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001453 except ValueError:
1454 # Non-encodable path
1455 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001456
1457 def is_block_device(self):
1458 """
1459 Whether this path is a block device.
1460 """
1461 try:
1462 return S_ISBLK(self.stat().st_mode)
1463 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001464 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001465 raise
1466 # Path doesn't exist or is a broken symlink
1467 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1468 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001469 except ValueError:
1470 # Non-encodable path
1471 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001472
1473 def is_char_device(self):
1474 """
1475 Whether this path is a character device.
1476 """
1477 try:
1478 return S_ISCHR(self.stat().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 or is a broken symlink
1483 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1484 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001485 except ValueError:
1486 # Non-encodable path
1487 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001488
1489 def is_fifo(self):
1490 """
1491 Whether this path is a FIFO.
1492 """
1493 try:
1494 return S_ISFIFO(self.stat().st_mode)
1495 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001496 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001497 raise
1498 # Path doesn't exist or is a broken symlink
1499 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1500 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001501 except ValueError:
1502 # Non-encodable path
1503 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001504
1505 def is_socket(self):
1506 """
1507 Whether this path is a socket.
1508 """
1509 try:
1510 return S_ISSOCK(self.stat().st_mode)
1511 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001512 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001513 raise
1514 # Path doesn't exist or is a broken symlink
1515 # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
1516 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001517 except ValueError:
1518 # Non-encodable path
1519 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001520
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001521 def expanduser(self):
1522 """ Return a new path with expanded ~ and ~user constructs
1523 (as returned by os.path.expanduser)
1524 """
1525 if (not (self._drv or self._root) and
1526 self._parts and self._parts[0][:1] == '~'):
1527 homedir = self._flavour.gethomedir(self._parts[0][1:])
1528 return self._from_parts([homedir] + self._parts[1:])
1529
1530 return self
1531
Antoine Pitrou31119e42013-11-22 17:38:12 +01001532
1533class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001534 """Path subclass for non-Windows systems.
1535
1536 On a POSIX system, instantiating a Path should return this object.
1537 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001538 __slots__ = ()
1539
1540class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001541 """Path subclass for Windows systems.
1542
1543 On a Windows system, instantiating a Path should return this object.
1544 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001545 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001546
1547 def owner(self):
1548 raise NotImplementedError("Path.owner() is unsupported on this system")
1549
1550 def group(self):
1551 raise NotImplementedError("Path.group() is unsupported on this system")
Cooper Lees173ff4a2017-08-01 15:35:45 -07001552
1553 def is_mount(self):
1554 raise NotImplementedError("Path.is_mount() is unsupported on this system")