blob: 621fba0e75c0f7c085ff61810640b0e2e791c737 [file] [log] [blame]
Antoine Pitrou31119e42013-11-22 17:38:12 +01001import fnmatch
2import functools
3import io
4import ntpath
5import os
6import posixpath
7import re
8import sys
Barney Galef24e2e52021-04-23 21:48:52 +01009import warnings
Serhiy Storchaka81108372017-09-26 00:55:55 +030010from _collections_abc import Sequence
Jörg Stucked5c120f2019-05-21 19:44:40 +020011from errno import EINVAL, ENOENT, ENOTDIR, EBADF, ELOOP
Antoine Pitrou31119e42013-11-22 17:38:12 +010012from operator import attrgetter
13from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
Antoine Pitrou069a5e12013-12-03 09:41:35 +010014from urllib.parse import quote_from_bytes as urlquote_from_bytes
Antoine Pitrou31119e42013-11-22 17:38:12 +010015
16
Antoine Pitrou31119e42013-11-22 17:38:12 +010017__all__ = [
18 "PurePath", "PurePosixPath", "PureWindowsPath",
19 "Path", "PosixPath", "WindowsPath",
20 ]
21
22#
23# Internals
24#
25
Barney Galebaecfbd2021-04-28 16:50:17 +010026_WINERROR_NOT_READY = 21 # drive exists but is not accessible
27_WINERROR_INVALID_NAME = 123 # fix for bpo-35306
28_WINERROR_CANT_RESOLVE_FILENAME = 1921 # broken symlink pointing to itself
29
penguindustin96466302019-05-06 14:57:17 -040030# EBADF - guard against macOS `stat` throwing EBADF
Jörg Stucked5c120f2019-05-21 19:44:40 +020031_IGNORED_ERROS = (ENOENT, ENOTDIR, EBADF, ELOOP)
Przemysław Spodymek216b7452018-08-27 23:33:45 +020032
Steve Dower2f6fae62019-02-03 23:08:18 -080033_IGNORED_WINERRORS = (
Barney Galebaecfbd2021-04-28 16:50:17 +010034 _WINERROR_NOT_READY,
35 _WINERROR_INVALID_NAME,
36 _WINERROR_CANT_RESOLVE_FILENAME)
Steve Dower2f6fae62019-02-03 23:08:18 -080037
38def _ignore_error(exception):
39 return (getattr(exception, 'errno', None) in _IGNORED_ERROS or
40 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
41
42
Antoine Pitrou31119e42013-11-22 17:38:12 +010043def _is_wildcard_pattern(pat):
44 # Whether this pattern needs actual matching using fnmatch, or can
45 # be looked up directly as a file.
46 return "*" in pat or "?" in pat or "[" in pat
47
48
49class _Flavour(object):
50 """A flavour implements a particular (platform-specific) set of path
51 semantics."""
52
53 def __init__(self):
54 self.join = self.sep.join
55
56 def parse_parts(self, parts):
57 parsed = []
58 sep = self.sep
59 altsep = self.altsep
60 drv = root = ''
61 it = reversed(parts)
62 for part in it:
63 if not part:
64 continue
65 if altsep:
66 part = part.replace(altsep, sep)
67 drv, root, rel = self.splitroot(part)
68 if sep in rel:
69 for x in reversed(rel.split(sep)):
70 if x and x != '.':
71 parsed.append(sys.intern(x))
72 else:
73 if rel and rel != '.':
74 parsed.append(sys.intern(rel))
75 if drv or root:
76 if not drv:
77 # If no drive is present, try to find one in the previous
78 # parts. This makes the result of parsing e.g.
79 # ("C:", "/", "a") reasonably intuitive.
80 for part in it:
Antoine Pitrou57fffd62015-02-15 18:03:59 +010081 if not part:
82 continue
83 if altsep:
84 part = part.replace(altsep, sep)
Antoine Pitrou31119e42013-11-22 17:38:12 +010085 drv = self.splitroot(part)[0]
86 if drv:
87 break
88 break
89 if drv or root:
90 parsed.append(drv + root)
91 parsed.reverse()
92 return drv, root, parsed
93
94 def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
95 """
96 Join the two paths represented by the respective
97 (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
98 """
99 if root2:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200100 if not drv2 and drv:
101 return drv, root2, [drv + root2] + parts2[1:]
102 elif drv2:
103 if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
104 # Same drive => second path is relative to the first
105 return drv, root, parts + parts2[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100106 else:
Serhiy Storchakaa9939022013-12-06 17:14:12 +0200107 # Second path is non-anchored (common case)
108 return drv, root, parts + parts2
109 return drv2, root2, parts2
Antoine Pitrou31119e42013-11-22 17:38:12 +0100110
111
112class _WindowsFlavour(_Flavour):
113 # Reference for Windows paths can be found at
114 # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
115
116 sep = '\\'
117 altsep = '/'
118 has_drv = True
119 pathmod = ntpath
120
Antoine Pitroudb118f52014-11-19 00:32:08 +0100121 is_supported = (os.name == 'nt')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100122
Jon Dufresne39726282017-05-18 07:35:54 -0700123 drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
Antoine Pitrou31119e42013-11-22 17:38:12 +0100124 ext_namespace_prefix = '\\\\?\\'
125
126 reserved_names = (
Miss Islington (bot)8789add2021-07-28 08:01:47 -0700127 {'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
128 {'COM%s' % c for c in '123456789\xb9\xb2\xb3'} |
129 {'LPT%s' % c for c in '123456789\xb9\xb2\xb3'}
Antoine Pitrou31119e42013-11-22 17:38:12 +0100130 )
131
132 # Interesting findings about extended paths:
Miss Islington (bot)8789add2021-07-28 08:01:47 -0700133 # * '\\?\c:\a' is an extended path, which bypasses normal Windows API
134 # path processing. Thus relative paths are not resolved and slash is not
135 # translated to backslash. It has the native NT path limit of 32767
136 # characters, but a bit less after resolving device symbolic links,
137 # such as '\??\C:' => '\Device\HarddiskVolume2'.
138 # * '\\?\c:/a' looks for a device named 'C:/a' because slash is a
139 # regular name character in the object namespace.
140 # * '\\?\c:\foo/bar' is invalid because '/' is illegal in NT filesystems.
141 # The only path separator at the filesystem level is backslash.
142 # * '//?/c:\a' and '//?/c:/a' are effectively equivalent to '\\.\c:\a' and
143 # thus limited to MAX_PATH.
144 # * Prior to Windows 8, ANSI API bytes paths are limited to MAX_PATH,
145 # even with the '\\?\' prefix.
Antoine Pitrou31119e42013-11-22 17:38:12 +0100146
147 def splitroot(self, part, sep=sep):
148 first = part[0:1]
149 second = part[1:2]
150 if (second == sep and first == sep):
151 # XXX extended paths should also disable the collapsing of "."
152 # components (according to MSDN docs).
153 prefix, part = self._split_extended_path(part)
154 first = part[0:1]
155 second = part[1:2]
156 else:
157 prefix = ''
158 third = part[2:3]
159 if (second == sep and first == sep and third != sep):
160 # is a UNC path:
161 # vvvvvvvvvvvvvvvvvvvvv root
162 # \\machine\mountpoint\directory\etc\...
163 # directory ^^^^^^^^^^^^^^
164 index = part.find(sep, 2)
165 if index != -1:
166 index2 = part.find(sep, index + 1)
167 # a UNC path can't have two slashes in a row
168 # (after the initial two)
169 if index2 != index + 1:
170 if index2 == -1:
171 index2 = len(part)
172 if prefix:
173 return prefix + part[1:index2], sep, part[index2+1:]
174 else:
175 return part[:index2], sep, part[index2+1:]
176 drv = root = ''
177 if second == ':' and first in self.drive_letters:
178 drv = part[:2]
179 part = part[2:]
180 first = third
181 if first == sep:
182 root = first
183 part = part.lstrip(sep)
184 return prefix + drv, root, part
185
186 def casefold(self, s):
187 return s.lower()
188
189 def casefold_parts(self, parts):
190 return [p.lower() for p in parts]
191
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300192 def compile_pattern(self, pattern):
193 return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
194
Antoine Pitrou31119e42013-11-22 17:38:12 +0100195 def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
196 prefix = ''
197 if s.startswith(ext_prefix):
198 prefix = s[:4]
199 s = s[4:]
200 if s.startswith('UNC\\'):
201 prefix += s[:3]
202 s = '\\' + s[3:]
203 return prefix, s
204
Antoine Pitrou31119e42013-11-22 17:38:12 +0100205 def is_reserved(self, parts):
206 # NOTE: the rules for reserved names seem somewhat complicated
Miss Islington (bot)8789add2021-07-28 08:01:47 -0700207 # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
208 # exist). We err on the side of caution and return True for paths
209 # which are not considered reserved by Windows.
Antoine Pitrou31119e42013-11-22 17:38:12 +0100210 if not parts:
211 return False
212 if parts[0].startswith('\\\\'):
213 # UNC paths are never reserved
214 return False
Miss Islington (bot)8789add2021-07-28 08:01:47 -0700215 name = parts[-1].partition('.')[0].partition(':')[0].rstrip(' ')
216 return name.upper() in self.reserved_names
Antoine Pitrou31119e42013-11-22 17:38:12 +0100217
218 def make_uri(self, path):
219 # Under Windows, file URIs use the UTF-8 encoding.
220 drive = path.drive
221 if len(drive) == 2 and drive[1] == ':':
222 # It's a path on a local drive => 'file:///c:/a/b'
223 rest = path.as_posix()[2:].lstrip('/')
224 return 'file:///%s/%s' % (
225 drive, urlquote_from_bytes(rest.encode('utf-8')))
226 else:
227 # It's a path on a network drive => 'file://host/share/a/b'
228 return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
229
230
231class _PosixFlavour(_Flavour):
232 sep = '/'
233 altsep = ''
234 has_drv = False
235 pathmod = posixpath
236
237 is_supported = (os.name != 'nt')
238
239 def splitroot(self, part, sep=sep):
240 if part and part[0] == sep:
241 stripped_part = part.lstrip(sep)
242 # According to POSIX path resolution:
243 # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
244 # "A pathname that begins with two successive slashes may be
245 # interpreted in an implementation-defined manner, although more
246 # than two leading slashes shall be treated as a single slash".
247 if len(part) - len(stripped_part) == 2:
248 return '', sep * 2, stripped_part
249 else:
250 return '', sep, stripped_part
251 else:
252 return '', '', part
253
254 def casefold(self, s):
255 return s
256
257 def casefold_parts(self, parts):
258 return parts
259
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300260 def compile_pattern(self, pattern):
261 return re.compile(fnmatch.translate(pattern)).fullmatch
262
Antoine Pitrou31119e42013-11-22 17:38:12 +0100263 def is_reserved(self, parts):
264 return False
265
266 def make_uri(self, path):
267 # We represent the path using the local filesystem encoding,
268 # for portability to other applications.
269 bpath = bytes(path)
270 return 'file://' + urlquote_from_bytes(bpath)
271
272
273_windows_flavour = _WindowsFlavour()
274_posix_flavour = _PosixFlavour()
275
276
277class _Accessor:
278 """An accessor implements a particular (system-specific or not) way of
279 accessing paths on the filesystem."""
280
281
282class _NormalAccessor(_Accessor):
283
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200284 stat = os.stat
Antoine Pitrou31119e42013-11-22 17:38:12 +0100285
Barney Gale11c3bd32021-04-09 21:52:49 +0100286 open = io.open
Antoine Pitrou31119e42013-11-22 17:38:12 +0100287
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200288 listdir = os.listdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100289
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200290 scandir = os.scandir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100291
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200292 chmod = os.chmod
Antoine Pitrou31119e42013-11-22 17:38:12 +0100293
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200294 mkdir = os.mkdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100295
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200296 unlink = os.unlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100297
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100298 if hasattr(os, "link"):
Barney Galeb57e0452021-04-07 00:01:22 +0100299 link = os.link
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100300 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100301 def link(self, src, dst):
Toke Høiland-Jørgensen092435e2019-12-16 13:23:55 +0100302 raise NotImplementedError("os.link() not available on this system")
Joannah Nanjekye6b5b0132019-05-04 11:27:10 -0400303
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200304 rmdir = os.rmdir
Antoine Pitrou31119e42013-11-22 17:38:12 +0100305
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200306 rename = os.rename
Antoine Pitrou31119e42013-11-22 17:38:12 +0100307
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200308 replace = os.replace
Antoine Pitrou31119e42013-11-22 17:38:12 +0100309
Barney Galeb57e0452021-04-07 00:01:22 +0100310 if hasattr(os, "symlink"):
311 symlink = os.symlink
Antoine Pitrou31119e42013-11-22 17:38:12 +0100312 else:
Barney Galeb57e0452021-04-07 00:01:22 +0100313 def symlink(self, src, dst, target_is_directory=False):
314 raise NotImplementedError("os.symlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100315
Barney Gale986da8e2021-04-07 01:25:37 +0100316 def touch(self, path, mode=0o666, exist_ok=True):
317 if exist_ok:
318 # First try to bump modification time
319 # Implementation note: GNU touch uses the UTIME_NOW option of
320 # the utimensat() / futimens() functions.
321 try:
322 os.utime(path, None)
323 except OSError:
324 # Avoid exception chaining
325 pass
326 else:
327 return
328 flags = os.O_CREAT | os.O_WRONLY
329 if not exist_ok:
330 flags |= os.O_EXCL
331 fd = os.open(path, flags, mode)
332 os.close(fd)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100333
Barney Galeb57e0452021-04-07 00:01:22 +0100334 if hasattr(os, "readlink"):
335 readlink = os.readlink
336 else:
337 def readlink(self, path):
338 raise NotImplementedError("os.readlink() not available on this system")
Antoine Pitrou31119e42013-11-22 17:38:12 +0100339
Barney Gale22386bb2020-04-17 17:41:07 +0100340 def owner(self, path):
341 try:
342 import pwd
343 return pwd.getpwuid(self.stat(path).st_uid).pw_name
344 except ImportError:
345 raise NotImplementedError("Path.owner() is unsupported on this system")
346
347 def group(self, path):
348 try:
349 import grp
350 return grp.getgrgid(self.stat(path).st_gid).gr_name
351 except ImportError:
352 raise NotImplementedError("Path.group() is unsupported on this system")
353
Barney Galeb05440c2021-04-07 17:31:49 +0100354 getcwd = os.getcwd
355
Barney Gale3f3d82b2021-04-07 23:50:13 +0100356 expanduser = staticmethod(os.path.expanduser)
357
Barney Galebaecfbd2021-04-28 16:50:17 +0100358 realpath = staticmethod(os.path.realpath)
359
Antoine Pitrou31119e42013-11-22 17:38:12 +0100360
361_normal_accessor = _NormalAccessor()
362
363
364#
365# Globbing helpers
366#
367
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300368def _make_selector(pattern_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100369 pat = pattern_parts[0]
370 child_parts = pattern_parts[1:]
371 if pat == '**':
372 cls = _RecursiveWildcardSelector
373 elif '**' in pat:
374 raise ValueError("Invalid pattern: '**' can only be an entire path component")
375 elif _is_wildcard_pattern(pat):
376 cls = _WildcardSelector
377 else:
378 cls = _PreciseSelector
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300379 return cls(pat, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100380
381if hasattr(functools, "lru_cache"):
382 _make_selector = functools.lru_cache()(_make_selector)
383
384
385class _Selector:
386 """A selector matches a specific glob pattern part against the children
387 of a given path."""
388
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300389 def __init__(self, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100390 self.child_parts = child_parts
391 if child_parts:
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300392 self.successor = _make_selector(child_parts, flavour)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300393 self.dironly = True
Antoine Pitrou31119e42013-11-22 17:38:12 +0100394 else:
395 self.successor = _TerminatingSelector()
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300396 self.dironly = False
Antoine Pitrou31119e42013-11-22 17:38:12 +0100397
398 def select_from(self, parent_path):
399 """Iterate over all child paths of `parent_path` matched by this
400 selector. This can contain parent_path itself."""
401 path_cls = type(parent_path)
402 is_dir = path_cls.is_dir
403 exists = path_cls.exists
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300404 scandir = parent_path._accessor.scandir
405 if not is_dir(parent_path):
406 return iter([])
407 return self._select_from(parent_path, is_dir, exists, scandir)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100408
409
410class _TerminatingSelector:
411
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300412 def _select_from(self, parent_path, is_dir, exists, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100413 yield parent_path
414
415
416class _PreciseSelector(_Selector):
417
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300418 def __init__(self, name, child_parts, flavour):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100419 self.name = name
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300420 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100421
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300422 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800423 try:
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800424 path = parent_path._make_child_relpath(self.name)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300425 if (is_dir if self.dironly else exists)(path):
426 for p in self.successor._select_from(path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800427 yield p
428 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100429 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100430
431
432class _WildcardSelector(_Selector):
433
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300434 def __init__(self, pat, child_parts, flavour):
435 self.match = flavour.compile_pattern(pat)
436 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100437
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300438 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800439 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200440 with scandir(parent_path) as scandir_it:
441 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300442 for entry in entries:
Pablo Galindoeb7560a2020-03-07 17:53:20 +0000443 if self.dironly:
444 try:
445 # "entry.is_dir()" can raise PermissionError
446 # in some cases (see bpo-38894), which is not
447 # among the errors ignored by _ignore_error()
448 if not entry.is_dir():
449 continue
450 except OSError as e:
451 if not _ignore_error(e):
452 raise
453 continue
454 name = entry.name
455 if self.match(name):
456 path = parent_path._make_child_relpath(name)
457 for p in self.successor._select_from(path, is_dir, exists, scandir):
458 yield p
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800459 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100460 return
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800461
Antoine Pitrou31119e42013-11-22 17:38:12 +0100462
Antoine Pitrou31119e42013-11-22 17:38:12 +0100463class _RecursiveWildcardSelector(_Selector):
464
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +0300465 def __init__(self, pat, child_parts, flavour):
466 _Selector.__init__(self, child_parts, flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100467
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300468 def _iterate_directories(self, parent_path, is_dir, scandir):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100469 yield parent_path
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800470 try:
Serhiy Storchaka704e2062020-03-11 18:42:03 +0200471 with scandir(parent_path) as scandir_it:
472 entries = list(scandir_it)
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300473 for entry in entries:
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200474 entry_is_dir = False
475 try:
476 entry_is_dir = entry.is_dir()
477 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -0800478 if not _ignore_error(e):
Przemysław Spodymek216b7452018-08-27 23:33:45 +0200479 raise
480 if entry_is_dir and not entry.is_symlink():
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300481 path = parent_path._make_child_relpath(entry.name)
482 for p in self._iterate_directories(path, is_dir, scandir):
Guido van Rossumbc9fdda2016-01-07 10:56:36 -0800483 yield p
484 except PermissionError:
485 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100486
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300487 def _select_from(self, parent_path, is_dir, exists, scandir):
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800488 try:
Serhiy Storchaka680cb152016-09-07 10:58:05 +0300489 yielded = set()
490 try:
491 successor_select = self.successor._select_from
492 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
493 for p in successor_select(starting_point, is_dir, exists, scandir):
494 if p not in yielded:
495 yield p
496 yielded.add(p)
497 finally:
498 yielded.clear()
Guido van Rossum6c2d33a2016-01-06 09:42:07 -0800499 except PermissionError:
Antoine Pitrou31119e42013-11-22 17:38:12 +0100500 return
Antoine Pitrou31119e42013-11-22 17:38:12 +0100501
502
503#
504# Public API
505#
506
507class _PathParents(Sequence):
508 """This object provides sequence-like access to the logical ancestors
509 of a path. Don't try to construct it yourself."""
510 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
511
512 def __init__(self, path):
513 # We don't store the instance to avoid reference cycles
514 self._pathcls = type(path)
515 self._drv = path._drv
516 self._root = path._root
517 self._parts = path._parts
518
519 def __len__(self):
520 if self._drv or self._root:
521 return len(self._parts) - 1
522 else:
523 return len(self._parts)
524
525 def __getitem__(self, idx):
Joshua Cannon45205842020-11-20 09:40:39 -0600526 if isinstance(idx, slice):
527 return tuple(self[i] for i in range(*idx.indices(len(self))))
Yaroslav Pankovych79d2e622020-11-23 22:06:22 +0200528
529 if idx >= len(self) or idx < -len(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100530 raise IndexError(idx)
531 return self._pathcls._from_parsed_parts(self._drv, self._root,
532 self._parts[:-idx - 1])
533
534 def __repr__(self):
535 return "<{}.parents>".format(self._pathcls.__name__)
536
537
538class PurePath(object):
chasondfa015c2018-02-19 08:36:32 +0900539 """Base class for manipulating paths without I/O.
540
541 PurePath represents a filesystem path and offers operations which
Antoine Pitrou31119e42013-11-22 17:38:12 +0100542 don't imply any actual filesystem I/O. Depending on your system,
543 instantiating a PurePath will return either a PurePosixPath or a
544 PureWindowsPath object. You can also instantiate either of these classes
545 directly, regardless of your system.
546 """
547 __slots__ = (
548 '_drv', '_root', '_parts',
549 '_str', '_hash', '_pparts', '_cached_cparts',
550 )
551
552 def __new__(cls, *args):
553 """Construct a PurePath from one or several strings and or existing
554 PurePath objects. The strings and path objects are combined so as
555 to yield a canonicalized path, which is incorporated into the
556 new PurePath object.
557 """
558 if cls is PurePath:
559 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
560 return cls._from_parts(args)
561
562 def __reduce__(self):
563 # Using the parts tuple helps share interned path parts
564 # when pickling related paths.
565 return (self.__class__, tuple(self._parts))
566
567 @classmethod
568 def _parse_args(cls, args):
569 # This is useful when you don't want to create an instance, just
570 # canonicalize some constructor arguments.
571 parts = []
572 for a in args:
573 if isinstance(a, PurePath):
574 parts += a._parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100575 else:
Brett Cannon568be632016-06-10 12:20:49 -0700576 a = os.fspath(a)
577 if isinstance(a, str):
578 # Force-cast str subclasses to str (issue #21127)
579 parts.append(str(a))
580 else:
581 raise TypeError(
582 "argument should be a str object or an os.PathLike "
583 "object returning str, not %r"
584 % type(a))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100585 return cls._flavour.parse_parts(parts)
586
587 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100588 def _from_parts(cls, args):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100589 # We need to call _parse_args on the instance, so as to get the
590 # right flavour.
591 self = object.__new__(cls)
592 drv, root, parts = self._parse_args(args)
593 self._drv = drv
594 self._root = root
595 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100596 return self
597
598 @classmethod
Barney Gale22191872021-04-07 01:26:37 +0100599 def _from_parsed_parts(cls, drv, root, parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100600 self = object.__new__(cls)
601 self._drv = drv
602 self._root = root
603 self._parts = parts
Antoine Pitrou31119e42013-11-22 17:38:12 +0100604 return self
605
606 @classmethod
607 def _format_parsed_parts(cls, drv, root, parts):
608 if drv or root:
609 return drv + root + cls._flavour.join(parts[1:])
610 else:
611 return cls._flavour.join(parts)
612
Antoine Pitrou31119e42013-11-22 17:38:12 +0100613 def _make_child(self, args):
614 drv, root, parts = self._parse_args(args)
615 drv, root, parts = self._flavour.join_parsed_parts(
616 self._drv, self._root, self._parts, drv, root, parts)
617 return self._from_parsed_parts(drv, root, parts)
618
619 def __str__(self):
620 """Return the string representation of the path, suitable for
621 passing to system calls."""
622 try:
623 return self._str
624 except AttributeError:
625 self._str = self._format_parsed_parts(self._drv, self._root,
626 self._parts) or '.'
627 return self._str
628
Brett Cannon568be632016-06-10 12:20:49 -0700629 def __fspath__(self):
630 return str(self)
631
Antoine Pitrou31119e42013-11-22 17:38:12 +0100632 def as_posix(self):
633 """Return the string representation of the path with forward (/)
634 slashes."""
635 f = self._flavour
636 return str(self).replace(f.sep, '/')
637
638 def __bytes__(self):
639 """Return the bytes representation of the path. This is only
640 recommended to use under Unix."""
Serhiy Storchaka62a99512017-03-25 13:42:11 +0200641 return os.fsencode(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100642
643 def __repr__(self):
644 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
645
646 def as_uri(self):
647 """Return the path as a 'file' URI."""
648 if not self.is_absolute():
649 raise ValueError("relative path can't be expressed as a file URI")
650 return self._flavour.make_uri(self)
651
652 @property
653 def _cparts(self):
654 # Cached casefolded parts, for hashing and comparison
655 try:
656 return self._cached_cparts
657 except AttributeError:
658 self._cached_cparts = self._flavour.casefold_parts(self._parts)
659 return self._cached_cparts
660
661 def __eq__(self, other):
662 if not isinstance(other, PurePath):
663 return NotImplemented
664 return self._cparts == other._cparts and self._flavour is other._flavour
665
Antoine Pitrou31119e42013-11-22 17:38:12 +0100666 def __hash__(self):
667 try:
668 return self._hash
669 except AttributeError:
670 self._hash = hash(tuple(self._cparts))
671 return self._hash
672
673 def __lt__(self, other):
674 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
675 return NotImplemented
676 return self._cparts < other._cparts
677
678 def __le__(self, other):
679 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
680 return NotImplemented
681 return self._cparts <= other._cparts
682
683 def __gt__(self, other):
684 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
685 return NotImplemented
686 return self._cparts > other._cparts
687
688 def __ge__(self, other):
689 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
690 return NotImplemented
691 return self._cparts >= other._cparts
692
Batuhan Taşkaya526606b2019-12-08 23:31:15 +0300693 def __class_getitem__(cls, type):
694 return cls
695
Antoine Pitrou31119e42013-11-22 17:38:12 +0100696 drive = property(attrgetter('_drv'),
697 doc="""The drive prefix (letter or UNC path), if any.""")
698
699 root = property(attrgetter('_root'),
700 doc="""The root of the path, if any.""")
701
702 @property
703 def anchor(self):
704 """The concatenation of the drive and root, or ''."""
705 anchor = self._drv + self._root
706 return anchor
707
708 @property
709 def name(self):
710 """The final path component, if any."""
711 parts = self._parts
712 if len(parts) == (1 if (self._drv or self._root) else 0):
713 return ''
714 return parts[-1]
715
716 @property
717 def suffix(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200718 """
719 The final component's last suffix, if any.
720
721 This includes the leading period. For example: '.txt'
722 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100723 name = self.name
724 i = name.rfind('.')
725 if 0 < i < len(name) - 1:
726 return name[i:]
727 else:
728 return ''
729
730 @property
731 def suffixes(self):
Ram Rachum8d4fef42019-11-02 18:46:24 +0200732 """
733 A list of the final component's suffixes, if any.
734
735 These include the leading periods. For example: ['.tar', '.gz']
736 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100737 name = self.name
738 if name.endswith('.'):
739 return []
740 name = name.lstrip('.')
741 return ['.' + suffix for suffix in name.split('.')[1:]]
742
743 @property
744 def stem(self):
745 """The final path component, minus its last suffix."""
746 name = self.name
747 i = name.rfind('.')
748 if 0 < i < len(name) - 1:
749 return name[:i]
750 else:
751 return name
752
753 def with_name(self, name):
754 """Return a new path with the file name changed."""
755 if not self.name:
756 raise ValueError("%r has an empty name" % (self,))
Antoine Pitrou7084e732014-07-06 21:31:12 -0400757 drv, root, parts = self._flavour.parse_parts((name,))
758 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
759 or drv or root or len(parts) != 1):
760 raise ValueError("Invalid name %r" % (name))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100761 return self._from_parsed_parts(self._drv, self._root,
762 self._parts[:-1] + [name])
763
Tim Hoffmann8aea4b32020-04-19 17:29:49 +0200764 def with_stem(self, stem):
765 """Return a new path with the stem changed."""
766 return self.with_name(stem + self.suffix)
767
Antoine Pitrou31119e42013-11-22 17:38:12 +0100768 def with_suffix(self, suffix):
Stefan Otte46dc4e32018-08-03 22:49:42 +0200769 """Return a new path with the file suffix changed. If the path
770 has no suffix, add given suffix. If the given suffix is an empty
771 string, remove the suffix from the path.
772 """
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400773 f = self._flavour
774 if f.sep in suffix or f.altsep and f.altsep in suffix:
Berker Peksag423d05f2018-08-11 08:45:06 +0300775 raise ValueError("Invalid suffix %r" % (suffix,))
Antoine Pitroue50dafc2014-07-06 21:37:15 -0400776 if suffix and not suffix.startswith('.') or suffix == '.':
Antoine Pitrou1b02da92014-01-03 00:07:17 +0100777 raise ValueError("Invalid suffix %r" % (suffix))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100778 name = self.name
779 if not name:
780 raise ValueError("%r has an empty name" % (self,))
781 old_suffix = self.suffix
782 if not old_suffix:
783 name = name + suffix
784 else:
785 name = name[:-len(old_suffix)] + suffix
786 return self._from_parsed_parts(self._drv, self._root,
787 self._parts[:-1] + [name])
788
789 def relative_to(self, *other):
790 """Return the relative path to another path identified by the passed
791 arguments. If the operation is not possible (because this is not
792 a subpath of the other path), raise ValueError.
793 """
794 # For the purpose of this method, drive and root are considered
795 # separate parts, i.e.:
796 # Path('c:/').relative_to('c:') gives Path('/')
797 # Path('c:/').relative_to('/') raise ValueError
798 if not other:
799 raise TypeError("need at least one argument")
800 parts = self._parts
801 drv = self._drv
802 root = self._root
Antoine Pitrou156b3612013-12-28 19:49:04 +0100803 if root:
804 abs_parts = [drv, root] + parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100805 else:
806 abs_parts = parts
807 to_drv, to_root, to_parts = self._parse_args(other)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100808 if to_root:
809 to_abs_parts = [to_drv, to_root] + to_parts[1:]
Antoine Pitrou31119e42013-11-22 17:38:12 +0100810 else:
811 to_abs_parts = to_parts
812 n = len(to_abs_parts)
Antoine Pitrou156b3612013-12-28 19:49:04 +0100813 cf = self._flavour.casefold_parts
814 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100815 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
Rotuna44832532020-05-25 21:42:28 +0200816 raise ValueError("{!r} is not in the subpath of {!r}"
817 " OR one path is relative and the other is absolute."
Antoine Pitrou31119e42013-11-22 17:38:12 +0100818 .format(str(self), str(formatted)))
Antoine Pitrou156b3612013-12-28 19:49:04 +0100819 return self._from_parsed_parts('', root if n == 1 else '',
820 abs_parts[n:])
Antoine Pitrou31119e42013-11-22 17:38:12 +0100821
Hai Shi82642a02019-08-13 14:54:02 -0500822 def is_relative_to(self, *other):
823 """Return True if the path is relative to another path or False.
824 """
825 try:
826 self.relative_to(*other)
827 return True
828 except ValueError:
829 return False
830
Antoine Pitrou31119e42013-11-22 17:38:12 +0100831 @property
832 def parts(self):
833 """An object providing sequence-like access to the
834 components in the filesystem path."""
835 # We cache the tuple to avoid building a new one each time .parts
836 # is accessed. XXX is this necessary?
837 try:
838 return self._pparts
839 except AttributeError:
840 self._pparts = tuple(self._parts)
841 return self._pparts
842
843 def joinpath(self, *args):
844 """Combine this path with one or several arguments, and return a
845 new path representing either a subpath (if all arguments are relative
846 paths) or a totally different path (if one of the arguments is
847 anchored).
848 """
849 return self._make_child(args)
850
851 def __truediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400852 try:
853 return self._make_child((key,))
854 except TypeError:
855 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100856
857 def __rtruediv__(self, key):
aiudirog4c69be22019-08-08 01:41:10 -0400858 try:
859 return self._from_parts([key] + self._parts)
860 except TypeError:
861 return NotImplemented
Antoine Pitrou31119e42013-11-22 17:38:12 +0100862
863 @property
864 def parent(self):
865 """The logical parent of the path."""
866 drv = self._drv
867 root = self._root
868 parts = self._parts
869 if len(parts) == 1 and (drv or root):
870 return self
871 return self._from_parsed_parts(drv, root, parts[:-1])
872
873 @property
874 def parents(self):
875 """A sequence of this path's logical parents."""
876 return _PathParents(self)
877
878 def is_absolute(self):
879 """True if the path is absolute (has both a root and, if applicable,
880 a drive)."""
881 if not self._root:
882 return False
883 return not self._flavour.has_drv or bool(self._drv)
884
885 def is_reserved(self):
886 """Return True if the path contains one of the special names reserved
887 by the system, if any."""
888 return self._flavour.is_reserved(self._parts)
889
890 def match(self, path_pattern):
891 """
892 Return True if this path matches the given pattern.
893 """
894 cf = self._flavour.casefold
895 path_pattern = cf(path_pattern)
896 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
897 if not pat_parts:
898 raise ValueError("empty pattern")
899 if drv and drv != cf(self._drv):
900 return False
901 if root and root != cf(self._root):
902 return False
903 parts = self._cparts
904 if drv or root:
905 if len(pat_parts) != len(parts):
906 return False
907 pat_parts = pat_parts[1:]
908 elif len(pat_parts) > len(parts):
909 return False
910 for part, pat in zip(reversed(parts), reversed(pat_parts)):
911 if not fnmatch.fnmatchcase(part, pat):
912 return False
913 return True
914
Brett Cannon568be632016-06-10 12:20:49 -0700915# Can't subclass os.PathLike from PurePath and keep the constructor
916# optimizations in PurePath._parse_args().
917os.PathLike.register(PurePath)
918
Antoine Pitrou31119e42013-11-22 17:38:12 +0100919
920class PurePosixPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900921 """PurePath subclass for non-Windows systems.
922
923 On a POSIX system, instantiating a PurePath should return this object.
924 However, you can also instantiate it directly on any system.
925 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100926 _flavour = _posix_flavour
927 __slots__ = ()
928
929
930class PureWindowsPath(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900931 """PurePath subclass for Windows systems.
932
933 On a Windows system, instantiating a PurePath should return this object.
934 However, you can also instantiate it directly on any system.
935 """
Antoine Pitrou31119e42013-11-22 17:38:12 +0100936 _flavour = _windows_flavour
937 __slots__ = ()
938
939
940# Filesystem-accessing classes
941
942
943class Path(PurePath):
chasondfa015c2018-02-19 08:36:32 +0900944 """PurePath subclass that can make system calls.
945
946 Path represents a filesystem path but unlike PurePath, also offers
947 methods to do system calls on path objects. Depending on your system,
948 instantiating a Path will return either a PosixPath or a WindowsPath
949 object. You can also instantiate a PosixPath or WindowsPath directly,
950 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
951 """
Barney Gale22191872021-04-07 01:26:37 +0100952 _accessor = _normal_accessor
953 __slots__ = ()
Antoine Pitrou31119e42013-11-22 17:38:12 +0100954
955 def __new__(cls, *args, **kwargs):
956 if cls is Path:
957 cls = WindowsPath if os.name == 'nt' else PosixPath
Barney Gale22191872021-04-07 01:26:37 +0100958 self = cls._from_parts(args)
Antoine Pitrou31119e42013-11-22 17:38:12 +0100959 if not self._flavour.is_supported:
960 raise NotImplementedError("cannot instantiate %r on your system"
961 % (cls.__name__,))
Antoine Pitrou31119e42013-11-22 17:38:12 +0100962 return self
963
Antoine Pitrou31119e42013-11-22 17:38:12 +0100964 def _make_child_relpath(self, part):
965 # This is an optimization used for dir walking. `part` must be
966 # a single part relative to this path.
967 parts = self._parts + [part]
968 return self._from_parsed_parts(self._drv, self._root, parts)
969
970 def __enter__(self):
Antoine Pitrou31119e42013-11-22 17:38:12 +0100971 return self
972
973 def __exit__(self, t, v, tb):
Barney Gale00002e62020-04-01 15:10:51 +0100974 # https://bugs.python.org/issue39682
975 # In previous versions of pathlib, this method marked this path as
976 # closed; subsequent attempts to perform I/O would raise an IOError.
977 # This functionality was never documented, and had the effect of
978 # making Path objects mutable, contrary to PEP 428. In Python 3.9 the
979 # _closed attribute was removed, and this method made a no-op.
980 # This method and __enter__()/__exit__() should be deprecated and
981 # removed in the future.
982 pass
Antoine Pitrou31119e42013-11-22 17:38:12 +0100983
Antoine Pitrou31119e42013-11-22 17:38:12 +0100984 # Public API
985
986 @classmethod
987 def cwd(cls):
988 """Return a new path pointing to the current working directory
989 (as returned by os.getcwd()).
990 """
kfollstad4a857182021-04-28 16:01:51 -0700991 return cls(cls._accessor.getcwd())
Antoine Pitrou31119e42013-11-22 17:38:12 +0100992
Antoine Pitrou17cba7d2015-01-12 21:03:41 +0100993 @classmethod
994 def home(cls):
995 """Return a new path pointing to the user's home directory (as
996 returned by os.path.expanduser('~')).
997 """
Barney Gale3f3d82b2021-04-07 23:50:13 +0100998 return cls("~").expanduser()
Antoine Pitrou17cba7d2015-01-12 21:03:41 +0100999
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001000 def samefile(self, other_path):
Berker Peksag05492b82015-10-22 03:34:16 +03001001 """Return whether other_path is the same or not as this file
Berker Peksag267597f2015-10-21 20:10:24 +03001002 (as returned by os.path.samefile()).
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001003 """
1004 st = self.stat()
1005 try:
1006 other_st = other_path.stat()
1007 except AttributeError:
Barney Gale5b1d9182020-04-17 18:47:27 +01001008 other_st = self._accessor.stat(other_path)
Antoine Pitrou43e3d942014-05-13 10:50:15 +02001009 return os.path.samestat(st, other_st)
1010
Antoine Pitrou31119e42013-11-22 17:38:12 +01001011 def iterdir(self):
1012 """Iterate over the files in this directory. Does not yield any
1013 result for the special paths '.' and '..'.
1014 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001015 for name in self._accessor.listdir(self):
1016 if name in {'.', '..'}:
1017 # Yielding a path object for these makes little sense
1018 continue
1019 yield self._make_child_relpath(name)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001020
1021 def glob(self, pattern):
1022 """Iterate over this subtree and yield all existing files (of any
Eivind Teig537b6ca2019-02-11 11:47:09 +01001023 kind, including directories) matching the given relative pattern.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001024 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001025 sys.audit("pathlib.Path.glob", self, pattern)
Berker Peksag4a208e42016-01-30 17:50:48 +02001026 if not pattern:
1027 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
Antoine Pitrou31119e42013-11-22 17:38:12 +01001028 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1029 if drv or root:
1030 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001031 selector = _make_selector(tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001032 for p in selector.select_from(self):
1033 yield p
1034
1035 def rglob(self, pattern):
1036 """Recursively yield all existing files (of any kind, including
Eivind Teig537b6ca2019-02-11 11:47:09 +01001037 directories) matching the given relative pattern, anywhere in
1038 this subtree.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001039 """
Serhiy Storchakaf4f445b2020-02-12 12:11:34 +02001040 sys.audit("pathlib.Path.rglob", self, pattern)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001041 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1042 if drv or root:
1043 raise NotImplementedError("Non-relative patterns are unsupported")
Serhiy Storchaka10ecbad2019-10-21 20:37:15 +03001044 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001045 for p in selector.select_from(self):
1046 yield p
1047
1048 def absolute(self):
1049 """Return an absolute version of this path. This function works
1050 even if the path doesn't point to anything.
1051
1052 No normalization is done, i.e. all '.' and '..' will be kept along.
1053 Use resolve() to get the canonical path to a file.
1054 """
1055 # XXX untested yet!
Antoine Pitrou31119e42013-11-22 17:38:12 +01001056 if self.is_absolute():
1057 return self
1058 # FIXME this must defer to the specific flavour (and, under Windows,
1059 # use nt._getfullpathname())
Barney Galeb05440c2021-04-07 17:31:49 +01001060 return self._from_parts([self._accessor.getcwd()] + self._parts)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001061
Steve Dower98eb3602016-11-09 12:58:17 -08001062 def resolve(self, strict=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001063 """
1064 Make the path absolute, resolving all symlinks on the way and also
1065 normalizing it (for example turning slashes into backslashes under
1066 Windows).
1067 """
Barney Galebaecfbd2021-04-28 16:50:17 +01001068
1069 def check_eloop(e):
1070 winerror = getattr(e, 'winerror', 0)
1071 if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME:
1072 raise RuntimeError("Symlink loop from %r" % e.filename)
1073
1074 try:
1075 s = self._accessor.realpath(self, strict=strict)
1076 except OSError as e:
1077 check_eloop(e)
1078 raise
1079 p = self._from_parts((s,))
1080
1081 # In non-strict mode, realpath() doesn't raise on symlink loops.
1082 # Ensure we get an exception by calling stat()
1083 if not strict:
1084 try:
1085 p.stat()
1086 except OSError as e:
1087 check_eloop(e)
1088 return p
Antoine Pitrou31119e42013-11-22 17:38:12 +01001089
Barney Galeabf96492021-04-07 16:53:39 +01001090 def stat(self, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001091 """
1092 Return the result of the stat() system call on this path, like
1093 os.stat() does.
1094 """
Barney Galeabf96492021-04-07 16:53:39 +01001095 return self._accessor.stat(self, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001096
1097 def owner(self):
1098 """
1099 Return the login name of the file owner.
1100 """
Barney Gale22386bb2020-04-17 17:41:07 +01001101 return self._accessor.owner(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001102
1103 def group(self):
1104 """
1105 Return the group name of the file gid.
1106 """
Barney Gale22386bb2020-04-17 17:41:07 +01001107 return self._accessor.group(self)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001108
Antoine Pitrou31119e42013-11-22 17:38:12 +01001109 def open(self, mode='r', buffering=-1, encoding=None,
1110 errors=None, newline=None):
1111 """
1112 Open the file pointed by this path and return a file object, as
1113 the built-in open() function does.
1114 """
Inada Naoki48274832021-03-29 12:28:14 +09001115 if "b" not in mode:
1116 encoding = io.text_encoding(encoding)
Barney Gale11c3bd32021-04-09 21:52:49 +01001117 return self._accessor.open(self, mode, buffering, encoding, errors,
1118 newline)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001119
Georg Brandlea683982014-10-01 19:12:33 +02001120 def read_bytes(self):
1121 """
1122 Open the file in bytes mode, read it, and close the file.
1123 """
1124 with self.open(mode='rb') as f:
1125 return f.read()
1126
1127 def read_text(self, encoding=None, errors=None):
1128 """
1129 Open the file in text mode, read it, and close the file.
1130 """
Inada Naoki48274832021-03-29 12:28:14 +09001131 encoding = io.text_encoding(encoding)
Georg Brandlea683982014-10-01 19:12:33 +02001132 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1133 return f.read()
1134
1135 def write_bytes(self, data):
1136 """
1137 Open the file in bytes mode, write to it, and close the file.
1138 """
1139 # type-check for the buffer interface before truncating the file
1140 view = memoryview(data)
1141 with self.open(mode='wb') as f:
1142 return f.write(view)
1143
Максим5f227412020-10-21 05:08:19 +03001144 def write_text(self, data, encoding=None, errors=None, newline=None):
Georg Brandlea683982014-10-01 19:12:33 +02001145 """
1146 Open the file in text mode, write to it, and close the file.
1147 """
1148 if not isinstance(data, str):
1149 raise TypeError('data must be str, not %s' %
1150 data.__class__.__name__)
Inada Naoki48274832021-03-29 12:28:14 +09001151 encoding = io.text_encoding(encoding)
Максим5f227412020-10-21 05:08:19 +03001152 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
Georg Brandlea683982014-10-01 19:12:33 +02001153 return f.write(data)
1154
Girtsa01ba332019-10-23 14:18:40 -07001155 def readlink(self):
1156 """
1157 Return the path to which the symbolic link points.
1158 """
1159 path = self._accessor.readlink(self)
Barney Gale22191872021-04-07 01:26:37 +01001160 return self._from_parts((path,))
Girtsa01ba332019-10-23 14:18:40 -07001161
Antoine Pitrou31119e42013-11-22 17:38:12 +01001162 def touch(self, mode=0o666, exist_ok=True):
1163 """
1164 Create this file with the given access mode, if it doesn't exist.
1165 """
Barney Gale986da8e2021-04-07 01:25:37 +01001166 self._accessor.touch(self, mode, exist_ok)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001167
Barry Warsaw7c549c42014-08-05 11:28:12 -04001168 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001169 """
1170 Create a new directory at this given path.
1171 """
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001172 try:
1173 self._accessor.mkdir(self, mode)
1174 except FileNotFoundError:
1175 if not parents or self.parent == self:
1176 raise
Armin Rigo22a594a2017-04-13 20:08:15 +02001177 self.parent.mkdir(parents=True, exist_ok=True)
1178 self.mkdir(mode, parents=False, exist_ok=exist_ok)
Serhiy Storchakaaf7b9ec2017-03-24 20:51:53 +02001179 except OSError:
1180 # Cannot rely on checking for EEXIST, since the operating system
1181 # could give priority to other errors like EACCES or EROFS
1182 if not exist_ok or not self.is_dir():
1183 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001184
Barney Galeabf96492021-04-07 16:53:39 +01001185 def chmod(self, mode, *, follow_symlinks=True):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001186 """
1187 Change the permissions of the path, like os.chmod().
1188 """
Barney Galeabf96492021-04-07 16:53:39 +01001189 self._accessor.chmod(self, mode, follow_symlinks=follow_symlinks)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001190
1191 def lchmod(self, mode):
1192 """
1193 Like chmod(), except if the path points to a symlink, the symlink's
1194 permissions are changed, rather than its target's.
1195 """
Barney Galeabf96492021-04-07 16:53:39 +01001196 self.chmod(mode, follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001197
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001198 def unlink(self, missing_ok=False):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001199 """
1200 Remove this file or link.
1201 If the path is a directory, use rmdir() instead.
1202 """
‮zlohhcuB treboRd9e006b2019-05-16 00:02:11 +02001203 try:
1204 self._accessor.unlink(self)
1205 except FileNotFoundError:
1206 if not missing_ok:
1207 raise
Antoine Pitrou31119e42013-11-22 17:38:12 +01001208
1209 def rmdir(self):
1210 """
1211 Remove this directory. The directory must be empty.
1212 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001213 self._accessor.rmdir(self)
1214
1215 def lstat(self):
1216 """
1217 Like stat(), except if the path points to a symlink, the symlink's
1218 status information is returned, rather than its target's.
1219 """
Barney Galeabf96492021-04-07 16:53:39 +01001220 return self.stat(follow_symlinks=False)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001221
1222 def rename(self, target):
1223 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001224 Rename this path to the target path.
1225
1226 The target path may be absolute or relative. Relative paths are
1227 interpreted relative to the current working directory, *not* the
1228 directory of the Path object.
1229
1230 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001231 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001232 self._accessor.rename(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001233 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001234
1235 def replace(self, target):
1236 """
Ram Rachumf97e42e2020-10-03 12:52:13 +03001237 Rename this path to the target path, overwriting if that path exists.
1238
1239 The target path may be absolute or relative. Relative paths are
1240 interpreted relative to the current working directory, *not* the
1241 directory of the Path object.
1242
1243 Returns the new Path instance pointing to the target path.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001244 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001245 self._accessor.replace(self, target)
hui shang088a09a2019-09-11 21:26:49 +08001246 return self.__class__(target)
Antoine Pitrou31119e42013-11-22 17:38:12 +01001247
1248 def symlink_to(self, target, target_is_directory=False):
1249 """
Barney Gale8aac1be2021-04-07 16:56:32 +01001250 Make this path a symlink pointing to the target path.
1251 Note the order of arguments (link, target) is the reverse of os.symlink.
Antoine Pitrou31119e42013-11-22 17:38:12 +01001252 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001253 self._accessor.symlink(target, self, target_is_directory)
1254
Barney Galef24e2e52021-04-23 21:48:52 +01001255 def hardlink_to(self, target):
1256 """
1257 Make this path a hard link pointing to the same file as *target*.
1258
1259 Note the order of arguments (self, target) is the reverse of os.link's.
1260 """
1261 self._accessor.link(target, self)
1262
Barney Gale8aac1be2021-04-07 16:56:32 +01001263 def link_to(self, target):
1264 """
1265 Make the target path a hard link pointing to this path.
1266
1267 Note this function does not make this path a hard link to *target*,
1268 despite the implication of the function and argument names. The order
1269 of arguments (target, link) is the reverse of Path.symlink_to, but
1270 matches that of os.link.
1271
Barney Galef24e2e52021-04-23 21:48:52 +01001272 Deprecated since Python 3.10 and scheduled for removal in Python 3.12.
1273 Use `hardlink_to()` instead.
Barney Gale8aac1be2021-04-07 16:56:32 +01001274 """
Barney Galef24e2e52021-04-23 21:48:52 +01001275 warnings.warn("pathlib.Path.link_to() is deprecated and is scheduled "
1276 "for removal in Python 3.12. "
1277 "Use pathlib.Path.hardlink_to() instead.",
Miss Islington (bot)b913f472021-05-16 15:35:44 -07001278 DeprecationWarning, stacklevel=2)
Barney Gale8aac1be2021-04-07 16:56:32 +01001279 self._accessor.link(self, target)
1280
Antoine Pitrou31119e42013-11-22 17:38:12 +01001281 # Convenience functions for querying the stat results
1282
1283 def exists(self):
1284 """
1285 Whether this path exists.
1286 """
1287 try:
1288 self.stat()
1289 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001290 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001291 raise
1292 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001293 except ValueError:
1294 # Non-encodable path
1295 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001296 return True
1297
1298 def is_dir(self):
1299 """
1300 Whether this path is a directory.
1301 """
1302 try:
1303 return S_ISDIR(self.stat().st_mode)
1304 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001305 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001306 raise
1307 # Path doesn't exist or is a broken symlink
Miss Islington (bot)ce4fee22021-05-05 01:54:05 -07001308 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
Antoine Pitrou31119e42013-11-22 17:38:12 +01001309 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001310 except ValueError:
1311 # Non-encodable path
1312 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001313
1314 def is_file(self):
1315 """
1316 Whether this path is a regular file (also True for symlinks pointing
1317 to regular files).
1318 """
1319 try:
1320 return S_ISREG(self.stat().st_mode)
1321 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001322 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001323 raise
1324 # Path doesn't exist or is a broken symlink
Miss Islington (bot)ce4fee22021-05-05 01:54:05 -07001325 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
Antoine Pitrou31119e42013-11-22 17:38:12 +01001326 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001327 except ValueError:
1328 # Non-encodable path
1329 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001330
Cooper Lees173ff4a2017-08-01 15:35:45 -07001331 def is_mount(self):
1332 """
1333 Check if this path is a POSIX mount point
1334 """
1335 # Need to exist and be a dir
1336 if not self.exists() or not self.is_dir():
1337 return False
1338
Cooper Lees173ff4a2017-08-01 15:35:45 -07001339 try:
Barney Galec746c4f2020-04-17 18:42:06 +01001340 parent_dev = self.parent.stat().st_dev
Cooper Lees173ff4a2017-08-01 15:35:45 -07001341 except OSError:
1342 return False
1343
1344 dev = self.stat().st_dev
1345 if dev != parent_dev:
1346 return True
1347 ino = self.stat().st_ino
Barney Galec746c4f2020-04-17 18:42:06 +01001348 parent_ino = self.parent.stat().st_ino
Cooper Lees173ff4a2017-08-01 15:35:45 -07001349 return ino == parent_ino
1350
Antoine Pitrou31119e42013-11-22 17:38:12 +01001351 def is_symlink(self):
1352 """
1353 Whether this path is a symbolic link.
1354 """
1355 try:
1356 return S_ISLNK(self.lstat().st_mode)
1357 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001358 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001359 raise
1360 # Path doesn't exist
1361 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001362 except ValueError:
1363 # Non-encodable path
1364 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001365
1366 def is_block_device(self):
1367 """
1368 Whether this path is a block device.
1369 """
1370 try:
1371 return S_ISBLK(self.stat().st_mode)
1372 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001373 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001374 raise
1375 # Path doesn't exist or is a broken symlink
Miss Islington (bot)ce4fee22021-05-05 01:54:05 -07001376 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
Antoine Pitrou31119e42013-11-22 17:38:12 +01001377 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001378 except ValueError:
1379 # Non-encodable path
1380 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001381
1382 def is_char_device(self):
1383 """
1384 Whether this path is a character device.
1385 """
1386 try:
1387 return S_ISCHR(self.stat().st_mode)
1388 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001389 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001390 raise
1391 # Path doesn't exist or is a broken symlink
Miss Islington (bot)ce4fee22021-05-05 01:54:05 -07001392 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
Antoine Pitrou31119e42013-11-22 17:38:12 +01001393 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001394 except ValueError:
1395 # Non-encodable path
1396 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001397
1398 def is_fifo(self):
1399 """
1400 Whether this path is a FIFO.
1401 """
1402 try:
1403 return S_ISFIFO(self.stat().st_mode)
1404 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001405 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001406 raise
1407 # Path doesn't exist or is a broken symlink
Miss Islington (bot)ce4fee22021-05-05 01:54:05 -07001408 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
Antoine Pitrou31119e42013-11-22 17:38:12 +01001409 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001410 except ValueError:
1411 # Non-encodable path
1412 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001413
1414 def is_socket(self):
1415 """
1416 Whether this path is a socket.
1417 """
1418 try:
1419 return S_ISSOCK(self.stat().st_mode)
1420 except OSError as e:
Steve Dower2f6fae62019-02-03 23:08:18 -08001421 if not _ignore_error(e):
Antoine Pitrou31119e42013-11-22 17:38:12 +01001422 raise
1423 # Path doesn't exist or is a broken symlink
Miss Islington (bot)ce4fee22021-05-05 01:54:05 -07001424 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
Antoine Pitrou31119e42013-11-22 17:38:12 +01001425 return False
Serhiy Storchaka0185f342018-09-18 11:28:51 +03001426 except ValueError:
1427 # Non-encodable path
1428 return False
Antoine Pitrou31119e42013-11-22 17:38:12 +01001429
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001430 def expanduser(self):
1431 """ Return a new path with expanded ~ and ~user constructs
1432 (as returned by os.path.expanduser)
1433 """
1434 if (not (self._drv or self._root) and
1435 self._parts and self._parts[0][:1] == '~'):
Barney Gale3f3d82b2021-04-07 23:50:13 +01001436 homedir = self._accessor.expanduser(self._parts[0])
1437 if homedir[:1] == "~":
1438 raise RuntimeError("Could not determine home directory.")
Antoine Pitrou8477ed62014-12-30 20:54:45 +01001439 return self._from_parts([homedir] + self._parts[1:])
1440
1441 return self
1442
Antoine Pitrou31119e42013-11-22 17:38:12 +01001443
1444class PosixPath(Path, PurePosixPath):
chasondfa015c2018-02-19 08:36:32 +09001445 """Path subclass for non-Windows systems.
1446
1447 On a POSIX system, instantiating a Path should return this object.
1448 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001449 __slots__ = ()
1450
1451class WindowsPath(Path, PureWindowsPath):
chasondfa015c2018-02-19 08:36:32 +09001452 """Path subclass for Windows systems.
1453
1454 On a Windows system, instantiating a Path should return this object.
1455 """
Antoine Pitrou31119e42013-11-22 17:38:12 +01001456 __slots__ = ()
Berker Peksag04d42292016-03-11 23:07:27 +02001457
Cooper Lees173ff4a2017-08-01 15:35:45 -07001458 def is_mount(self):
1459 raise NotImplementedError("Path.is_mount() is unsupported on this system")