1 import fnmatch
2 import functools
3 import io
4 import ntpath
5 import os
6 import posixpath
7 import re
8 import sys
9 import warnings
10 from _collections_abc import Sequence
11 from errno import ENOENT, ENOTDIR, EBADF, ELOOP
12 from operator import attrgetter
13 from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
14 from urllib.parse import quote_from_bytes as urlquote_from_bytes
15
16
17 __all__ = [
18 "PurePath", "PurePosixPath", "PureWindowsPath",
19 "Path", "PosixPath", "WindowsPath",
20 ]
21
22 #
23 # Internals
24 #
25
26 _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
30 # EBADF - guard against macOS `stat` throwing EBADF
31 _IGNORED_ERRNOS = (ENOENT, ENOTDIR, EBADF, ELOOP)
32
33 _IGNORED_WINERRORS = (
34 _WINERROR_NOT_READY,
35 _WINERROR_INVALID_NAME,
36 _WINERROR_CANT_RESOLVE_FILENAME)
37
38 def _ignore_error(exception):
39 return (getattr(exception, 'errno', None) in _IGNORED_ERRNOS or
40 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
41
42
43 def _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
49 class ESC[4;38;5;81m_Flavour(ESC[4;38;5;149mobject):
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:
81 if not part:
82 continue
83 if altsep:
84 part = part.replace(altsep, sep)
85 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:
100 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:]
106 else:
107 # Second path is non-anchored (common case)
108 return drv, root, parts + parts2
109 return drv2, root2, parts2
110
111
112 class ESC[4;38;5;81m_WindowsFlavour(ESC[4;38;5;149m_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
121 is_supported = (os.name == 'nt')
122
123 drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
124 ext_namespace_prefix = '\\\\?\\'
125
126 reserved_names = (
127 {'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'}
130 )
131
132 # Interesting findings about extended paths:
133 # * '\\?\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.
146
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
192 def compile_pattern(self, pattern):
193 return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
194
195 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
205 def is_reserved(self, parts):
206 # NOTE: the rules for reserved names seem somewhat complicated
207 # (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.
210 if not parts:
211 return False
212 if parts[0].startswith('\\\\'):
213 # UNC paths are never reserved
214 return False
215 name = parts[-1].partition('.')[0].partition(':')[0].rstrip(' ')
216 return name.upper() in self.reserved_names
217
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
231 class ESC[4;38;5;81m_PosixFlavour(ESC[4;38;5;149m_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
260 def compile_pattern(self, pattern):
261 return re.compile(fnmatch.translate(pattern)).fullmatch
262
263 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
277 #
278 # Globbing helpers
279 #
280
281 def _make_selector(pattern_parts, flavour):
282 pat = pattern_parts[0]
283 child_parts = pattern_parts[1:]
284 if not pat:
285 return _TerminatingSelector()
286 if pat == '**':
287 cls = _RecursiveWildcardSelector
288 elif '**' in pat:
289 raise ValueError("Invalid pattern: '**' can only be an entire path component")
290 elif _is_wildcard_pattern(pat):
291 cls = _WildcardSelector
292 else:
293 cls = _PreciseSelector
294 return cls(pat, child_parts, flavour)
295
296 if hasattr(functools, "lru_cache"):
297 _make_selector = functools.lru_cache()(_make_selector)
298
299
300 class ESC[4;38;5;81m_Selector:
301 """A selector matches a specific glob pattern part against the children
302 of a given path."""
303
304 def __init__(self, child_parts, flavour):
305 self.child_parts = child_parts
306 if child_parts:
307 self.successor = _make_selector(child_parts, flavour)
308 self.dironly = True
309 else:
310 self.successor = _TerminatingSelector()
311 self.dironly = False
312
313 def select_from(self, parent_path):
314 """Iterate over all child paths of `parent_path` matched by this
315 selector. This can contain parent_path itself."""
316 path_cls = type(parent_path)
317 is_dir = path_cls.is_dir
318 exists = path_cls.exists
319 scandir = path_cls._scandir
320 if not is_dir(parent_path):
321 return iter([])
322 return self._select_from(parent_path, is_dir, exists, scandir)
323
324
325 class ESC[4;38;5;81m_TerminatingSelector:
326
327 def _select_from(self, parent_path, is_dir, exists, scandir):
328 yield parent_path
329
330
331 class ESC[4;38;5;81m_PreciseSelector(ESC[4;38;5;149m_Selector):
332
333 def __init__(self, name, child_parts, flavour):
334 self.name = name
335 _Selector.__init__(self, child_parts, flavour)
336
337 def _select_from(self, parent_path, is_dir, exists, scandir):
338 try:
339 path = parent_path._make_child_relpath(self.name)
340 if (is_dir if self.dironly else exists)(path):
341 for p in self.successor._select_from(path, is_dir, exists, scandir):
342 yield p
343 except PermissionError:
344 return
345
346
347 class ESC[4;38;5;81m_WildcardSelector(ESC[4;38;5;149m_Selector):
348
349 def __init__(self, pat, child_parts, flavour):
350 self.match = flavour.compile_pattern(pat)
351 _Selector.__init__(self, child_parts, flavour)
352
353 def _select_from(self, parent_path, is_dir, exists, scandir):
354 try:
355 with scandir(parent_path) as scandir_it:
356 entries = list(scandir_it)
357 for entry in entries:
358 if self.dironly:
359 try:
360 # "entry.is_dir()" can raise PermissionError
361 # in some cases (see bpo-38894), which is not
362 # among the errors ignored by _ignore_error()
363 if not entry.is_dir():
364 continue
365 except OSError as e:
366 if not _ignore_error(e):
367 raise
368 continue
369 name = entry.name
370 if self.match(name):
371 path = parent_path._make_child_relpath(name)
372 for p in self.successor._select_from(path, is_dir, exists, scandir):
373 yield p
374 except PermissionError:
375 return
376
377
378 class ESC[4;38;5;81m_RecursiveWildcardSelector(ESC[4;38;5;149m_Selector):
379
380 def __init__(self, pat, child_parts, flavour):
381 _Selector.__init__(self, child_parts, flavour)
382
383 def _iterate_directories(self, parent_path, is_dir, scandir):
384 yield parent_path
385 try:
386 with scandir(parent_path) as scandir_it:
387 entries = list(scandir_it)
388 for entry in entries:
389 entry_is_dir = False
390 try:
391 entry_is_dir = entry.is_dir(follow_symlinks=False)
392 except OSError as e:
393 if not _ignore_error(e):
394 raise
395 if entry_is_dir:
396 path = parent_path._make_child_relpath(entry.name)
397 for p in self._iterate_directories(path, is_dir, scandir):
398 yield p
399 except PermissionError:
400 return
401
402 def _select_from(self, parent_path, is_dir, exists, scandir):
403 try:
404 yielded = set()
405 try:
406 successor_select = self.successor._select_from
407 for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
408 for p in successor_select(starting_point, is_dir, exists, scandir):
409 if p not in yielded:
410 yield p
411 yielded.add(p)
412 finally:
413 yielded.clear()
414 except PermissionError:
415 return
416
417
418 #
419 # Public API
420 #
421
422 class ESC[4;38;5;81m_PathParents(ESC[4;38;5;149mSequence):
423 """This object provides sequence-like access to the logical ancestors
424 of a path. Don't try to construct it yourself."""
425 __slots__ = ('_pathcls', '_drv', '_root', '_parts')
426
427 def __init__(self, path):
428 # We don't store the instance to avoid reference cycles
429 self._pathcls = type(path)
430 self._drv = path._drv
431 self._root = path._root
432 self._parts = path._parts
433
434 def __len__(self):
435 if self._drv or self._root:
436 return len(self._parts) - 1
437 else:
438 return len(self._parts)
439
440 def __getitem__(self, idx):
441 if isinstance(idx, slice):
442 return tuple(self[i] for i in range(*idx.indices(len(self))))
443
444 if idx >= len(self) or idx < -len(self):
445 raise IndexError(idx)
446 if idx < 0:
447 idx += len(self)
448 return self._pathcls._from_parsed_parts(self._drv, self._root,
449 self._parts[:-idx - 1])
450
451 def __repr__(self):
452 return "<{}.parents>".format(self._pathcls.__name__)
453
454
455 class ESC[4;38;5;81mPurePath(ESC[4;38;5;149mobject):
456 """Base class for manipulating paths without I/O.
457
458 PurePath represents a filesystem path and offers operations which
459 don't imply any actual filesystem I/O. Depending on your system,
460 instantiating a PurePath will return either a PurePosixPath or a
461 PureWindowsPath object. You can also instantiate either of these classes
462 directly, regardless of your system.
463 """
464 __slots__ = (
465 '_drv', '_root', '_parts',
466 '_str', '_hash', '_pparts', '_cached_cparts',
467 )
468
469 def __new__(cls, *args):
470 """Construct a PurePath from one or several strings and or existing
471 PurePath objects. The strings and path objects are combined so as
472 to yield a canonicalized path, which is incorporated into the
473 new PurePath object.
474 """
475 if cls is PurePath:
476 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
477 return cls._from_parts(args)
478
479 def __reduce__(self):
480 # Using the parts tuple helps share interned path parts
481 # when pickling related paths.
482 return (self.__class__, tuple(self._parts))
483
484 @classmethod
485 def _parse_args(cls, args):
486 # This is useful when you don't want to create an instance, just
487 # canonicalize some constructor arguments.
488 parts = []
489 for a in args:
490 if isinstance(a, PurePath):
491 parts += a._parts
492 else:
493 a = os.fspath(a)
494 if isinstance(a, str):
495 # Force-cast str subclasses to str (issue #21127)
496 parts.append(str(a))
497 else:
498 raise TypeError(
499 "argument should be a str object or an os.PathLike "
500 "object returning str, not %r"
501 % type(a))
502 return cls._flavour.parse_parts(parts)
503
504 @classmethod
505 def _from_parts(cls, args):
506 # We need to call _parse_args on the instance, so as to get the
507 # right flavour.
508 self = object.__new__(cls)
509 drv, root, parts = self._parse_args(args)
510 self._drv = drv
511 self._root = root
512 self._parts = parts
513 return self
514
515 @classmethod
516 def _from_parsed_parts(cls, drv, root, parts):
517 self = object.__new__(cls)
518 self._drv = drv
519 self._root = root
520 self._parts = parts
521 return self
522
523 @classmethod
524 def _format_parsed_parts(cls, drv, root, parts):
525 if drv or root:
526 return drv + root + cls._flavour.join(parts[1:])
527 else:
528 return cls._flavour.join(parts)
529
530 def _make_child(self, args):
531 drv, root, parts = self._parse_args(args)
532 drv, root, parts = self._flavour.join_parsed_parts(
533 self._drv, self._root, self._parts, drv, root, parts)
534 return self._from_parsed_parts(drv, root, parts)
535
536 def __str__(self):
537 """Return the string representation of the path, suitable for
538 passing to system calls."""
539 try:
540 return self._str
541 except AttributeError:
542 self._str = self._format_parsed_parts(self._drv, self._root,
543 self._parts) or '.'
544 return self._str
545
546 def __fspath__(self):
547 return str(self)
548
549 def as_posix(self):
550 """Return the string representation of the path with forward (/)
551 slashes."""
552 f = self._flavour
553 return str(self).replace(f.sep, '/')
554
555 def __bytes__(self):
556 """Return the bytes representation of the path. This is only
557 recommended to use under Unix."""
558 return os.fsencode(self)
559
560 def __repr__(self):
561 return "{}({!r})".format(self.__class__.__name__, self.as_posix())
562
563 def as_uri(self):
564 """Return the path as a 'file' URI."""
565 if not self.is_absolute():
566 raise ValueError("relative path can't be expressed as a file URI")
567 return self._flavour.make_uri(self)
568
569 @property
570 def _cparts(self):
571 # Cached casefolded parts, for hashing and comparison
572 try:
573 return self._cached_cparts
574 except AttributeError:
575 self._cached_cparts = self._flavour.casefold_parts(self._parts)
576 return self._cached_cparts
577
578 def __eq__(self, other):
579 if not isinstance(other, PurePath):
580 return NotImplemented
581 return self._cparts == other._cparts and self._flavour is other._flavour
582
583 def __hash__(self):
584 try:
585 return self._hash
586 except AttributeError:
587 self._hash = hash(tuple(self._cparts))
588 return self._hash
589
590 def __lt__(self, other):
591 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
592 return NotImplemented
593 return self._cparts < other._cparts
594
595 def __le__(self, other):
596 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
597 return NotImplemented
598 return self._cparts <= other._cparts
599
600 def __gt__(self, other):
601 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
602 return NotImplemented
603 return self._cparts > other._cparts
604
605 def __ge__(self, other):
606 if not isinstance(other, PurePath) or self._flavour is not other._flavour:
607 return NotImplemented
608 return self._cparts >= other._cparts
609
610 drive = property(attrgetter('_drv'),
611 doc="""The drive prefix (letter or UNC path), if any.""")
612
613 root = property(attrgetter('_root'),
614 doc="""The root of the path, if any.""")
615
616 @property
617 def anchor(self):
618 """The concatenation of the drive and root, or ''."""
619 anchor = self._drv + self._root
620 return anchor
621
622 @property
623 def name(self):
624 """The final path component, if any."""
625 parts = self._parts
626 if len(parts) == (1 if (self._drv or self._root) else 0):
627 return ''
628 return parts[-1]
629
630 @property
631 def suffix(self):
632 """
633 The final component's last suffix, if any.
634
635 This includes the leading period. For example: '.txt'
636 """
637 name = self.name
638 i = name.rfind('.')
639 if 0 < i < len(name) - 1:
640 return name[i:]
641 else:
642 return ''
643
644 @property
645 def suffixes(self):
646 """
647 A list of the final component's suffixes, if any.
648
649 These include the leading periods. For example: ['.tar', '.gz']
650 """
651 name = self.name
652 if name.endswith('.'):
653 return []
654 name = name.lstrip('.')
655 return ['.' + suffix for suffix in name.split('.')[1:]]
656
657 @property
658 def stem(self):
659 """The final path component, minus its last suffix."""
660 name = self.name
661 i = name.rfind('.')
662 if 0 < i < len(name) - 1:
663 return name[:i]
664 else:
665 return name
666
667 def with_name(self, name):
668 """Return a new path with the file name changed."""
669 if not self.name:
670 raise ValueError("%r has an empty name" % (self,))
671 drv, root, parts = self._flavour.parse_parts((name,))
672 if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
673 or drv or root or len(parts) != 1):
674 raise ValueError("Invalid name %r" % (name))
675 return self._from_parsed_parts(self._drv, self._root,
676 self._parts[:-1] + [name])
677
678 def with_stem(self, stem):
679 """Return a new path with the stem changed."""
680 return self.with_name(stem + self.suffix)
681
682 def with_suffix(self, suffix):
683 """Return a new path with the file suffix changed. If the path
684 has no suffix, add given suffix. If the given suffix is an empty
685 string, remove the suffix from the path.
686 """
687 f = self._flavour
688 if f.sep in suffix or f.altsep and f.altsep in suffix:
689 raise ValueError("Invalid suffix %r" % (suffix,))
690 if suffix and not suffix.startswith('.') or suffix == '.':
691 raise ValueError("Invalid suffix %r" % (suffix))
692 name = self.name
693 if not name:
694 raise ValueError("%r has an empty name" % (self,))
695 old_suffix = self.suffix
696 if not old_suffix:
697 name = name + suffix
698 else:
699 name = name[:-len(old_suffix)] + suffix
700 return self._from_parsed_parts(self._drv, self._root,
701 self._parts[:-1] + [name])
702
703 def relative_to(self, *other):
704 """Return the relative path to another path identified by the passed
705 arguments. If the operation is not possible (because this is not
706 a subpath of the other path), raise ValueError.
707 """
708 # For the purpose of this method, drive and root are considered
709 # separate parts, i.e.:
710 # Path('c:/').relative_to('c:') gives Path('/')
711 # Path('c:/').relative_to('/') raise ValueError
712 if not other:
713 raise TypeError("need at least one argument")
714 parts = self._parts
715 drv = self._drv
716 root = self._root
717 if root:
718 abs_parts = [drv, root] + parts[1:]
719 else:
720 abs_parts = parts
721 to_drv, to_root, to_parts = self._parse_args(other)
722 if to_root:
723 to_abs_parts = [to_drv, to_root] + to_parts[1:]
724 else:
725 to_abs_parts = to_parts
726 n = len(to_abs_parts)
727 cf = self._flavour.casefold_parts
728 if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
729 formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
730 raise ValueError("{!r} is not in the subpath of {!r}"
731 " OR one path is relative and the other is absolute."
732 .format(str(self), str(formatted)))
733 return self._from_parsed_parts('', root if n == 1 else '',
734 abs_parts[n:])
735
736 def is_relative_to(self, *other):
737 """Return True if the path is relative to another path or False.
738 """
739 try:
740 self.relative_to(*other)
741 return True
742 except ValueError:
743 return False
744
745 @property
746 def parts(self):
747 """An object providing sequence-like access to the
748 components in the filesystem path."""
749 # We cache the tuple to avoid building a new one each time .parts
750 # is accessed. XXX is this necessary?
751 try:
752 return self._pparts
753 except AttributeError:
754 self._pparts = tuple(self._parts)
755 return self._pparts
756
757 def joinpath(self, *args):
758 """Combine this path with one or several arguments, and return a
759 new path representing either a subpath (if all arguments are relative
760 paths) or a totally different path (if one of the arguments is
761 anchored).
762 """
763 return self._make_child(args)
764
765 def __truediv__(self, key):
766 try:
767 return self._make_child((key,))
768 except TypeError:
769 return NotImplemented
770
771 def __rtruediv__(self, key):
772 try:
773 return self._from_parts([key] + self._parts)
774 except TypeError:
775 return NotImplemented
776
777 @property
778 def parent(self):
779 """The logical parent of the path."""
780 drv = self._drv
781 root = self._root
782 parts = self._parts
783 if len(parts) == 1 and (drv or root):
784 return self
785 return self._from_parsed_parts(drv, root, parts[:-1])
786
787 @property
788 def parents(self):
789 """A sequence of this path's logical parents."""
790 return _PathParents(self)
791
792 def is_absolute(self):
793 """True if the path is absolute (has both a root and, if applicable,
794 a drive)."""
795 if not self._root:
796 return False
797 return not self._flavour.has_drv or bool(self._drv)
798
799 def is_reserved(self):
800 """Return True if the path contains one of the special names reserved
801 by the system, if any."""
802 return self._flavour.is_reserved(self._parts)
803
804 def match(self, path_pattern):
805 """
806 Return True if this path matches the given pattern.
807 """
808 cf = self._flavour.casefold
809 path_pattern = cf(path_pattern)
810 drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
811 if not pat_parts:
812 raise ValueError("empty pattern")
813 if drv and drv != cf(self._drv):
814 return False
815 if root and root != cf(self._root):
816 return False
817 parts = self._cparts
818 if drv or root:
819 if len(pat_parts) != len(parts):
820 return False
821 pat_parts = pat_parts[1:]
822 elif len(pat_parts) > len(parts):
823 return False
824 for part, pat in zip(reversed(parts), reversed(pat_parts)):
825 if not fnmatch.fnmatchcase(part, pat):
826 return False
827 return True
828
829 # Can't subclass os.PathLike from PurePath and keep the constructor
830 # optimizations in PurePath._parse_args().
831 os.PathLike.register(PurePath)
832
833
834 class ESC[4;38;5;81mPurePosixPath(ESC[4;38;5;149mPurePath):
835 """PurePath subclass for non-Windows systems.
836
837 On a POSIX system, instantiating a PurePath should return this object.
838 However, you can also instantiate it directly on any system.
839 """
840 _flavour = _posix_flavour
841 __slots__ = ()
842
843
844 class ESC[4;38;5;81mPureWindowsPath(ESC[4;38;5;149mPurePath):
845 """PurePath subclass for Windows systems.
846
847 On a Windows system, instantiating a PurePath should return this object.
848 However, you can also instantiate it directly on any system.
849 """
850 _flavour = _windows_flavour
851 __slots__ = ()
852
853
854 # Filesystem-accessing classes
855
856
857 class ESC[4;38;5;81mPath(ESC[4;38;5;149mPurePath):
858 """PurePath subclass that can make system calls.
859
860 Path represents a filesystem path but unlike PurePath, also offers
861 methods to do system calls on path objects. Depending on your system,
862 instantiating a Path will return either a PosixPath or a WindowsPath
863 object. You can also instantiate a PosixPath or WindowsPath directly,
864 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
865 """
866 __slots__ = ()
867
868 def __new__(cls, *args, **kwargs):
869 if cls is Path:
870 cls = WindowsPath if os.name == 'nt' else PosixPath
871 self = cls._from_parts(args)
872 if not self._flavour.is_supported:
873 raise NotImplementedError("cannot instantiate %r on your system"
874 % (cls.__name__,))
875 return self
876
877 def _make_child_relpath(self, part):
878 # This is an optimization used for dir walking. `part` must be
879 # a single part relative to this path.
880 parts = self._parts + [part]
881 return self._from_parsed_parts(self._drv, self._root, parts)
882
883 def __enter__(self):
884 # In previous versions of pathlib, __exit__() marked this path as
885 # closed; subsequent attempts to perform I/O would raise an IOError.
886 # This functionality was never documented, and had the effect of
887 # making Path objects mutable, contrary to PEP 428.
888 # In Python 3.9 __exit__() was made a no-op.
889 # In Python 3.11 __enter__() began emitting DeprecationWarning.
890 # In Python 3.13 __enter__() and __exit__() should be removed.
891 warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled "
892 "for removal in Python 3.13; Path objects as a context "
893 "manager is a no-op",
894 DeprecationWarning, stacklevel=2)
895 return self
896
897 def __exit__(self, t, v, tb):
898 pass
899
900 # Public API
901
902 @classmethod
903 def cwd(cls):
904 """Return a new path pointing to the current working directory
905 (as returned by os.getcwd()).
906 """
907 return cls(os.getcwd())
908
909 @classmethod
910 def home(cls):
911 """Return a new path pointing to the user's home directory (as
912 returned by os.path.expanduser('~')).
913 """
914 return cls("~").expanduser()
915
916 def samefile(self, other_path):
917 """Return whether other_path is the same or not as this file
918 (as returned by os.path.samefile()).
919 """
920 st = self.stat()
921 try:
922 other_st = other_path.stat()
923 except AttributeError:
924 other_st = self.__class__(other_path).stat()
925 return os.path.samestat(st, other_st)
926
927 def iterdir(self):
928 """Iterate over the files in this directory. Does not yield any
929 result for the special paths '.' and '..'.
930 """
931 for name in os.listdir(self):
932 yield self._make_child_relpath(name)
933
934 def _scandir(self):
935 # bpo-24132: a future version of pathlib will support subclassing of
936 # pathlib.Path to customize how the filesystem is accessed. This
937 # includes scandir(), which is used to implement glob().
938 return os.scandir(self)
939
940 def glob(self, pattern):
941 """Iterate over this subtree and yield all existing files (of any
942 kind, including directories) matching the given relative pattern.
943 """
944 sys.audit("pathlib.Path.glob", self, pattern)
945 if not pattern:
946 raise ValueError("Unacceptable pattern: {!r}".format(pattern))
947 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
948 if drv or root:
949 raise NotImplementedError("Non-relative patterns are unsupported")
950 if pattern[-1] in (self._flavour.sep, self._flavour.altsep):
951 pattern_parts.append('')
952 selector = _make_selector(tuple(pattern_parts), self._flavour)
953 for p in selector.select_from(self):
954 yield p
955
956 def rglob(self, pattern):
957 """Recursively yield all existing files (of any kind, including
958 directories) matching the given relative pattern, anywhere in
959 this subtree.
960 """
961 sys.audit("pathlib.Path.rglob", self, pattern)
962 drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
963 if drv or root:
964 raise NotImplementedError("Non-relative patterns are unsupported")
965 if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep):
966 pattern_parts.append('')
967 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
968 for p in selector.select_from(self):
969 yield p
970
971 def absolute(self):
972 """Return an absolute version of this path by prepending the current
973 working directory. No normalization or symlink resolution is performed.
974
975 Use resolve() to get the canonical path to a file.
976 """
977 if self.is_absolute():
978 return self
979 return self._from_parts([self.cwd()] + self._parts)
980
981 def resolve(self, strict=False):
982 """
983 Make the path absolute, resolving all symlinks on the way and also
984 normalizing it.
985 """
986
987 def check_eloop(e):
988 winerror = getattr(e, 'winerror', 0)
989 if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME:
990 raise RuntimeError("Symlink loop from %r" % e.filename)
991
992 try:
993 s = os.path.realpath(self, strict=strict)
994 except OSError as e:
995 check_eloop(e)
996 raise
997 p = self._from_parts((s,))
998
999 # In non-strict mode, realpath() doesn't raise on symlink loops.
1000 # Ensure we get an exception by calling stat()
1001 if not strict:
1002 try:
1003 p.stat()
1004 except OSError as e:
1005 check_eloop(e)
1006 return p
1007
1008 def stat(self, *, follow_symlinks=True):
1009 """
1010 Return the result of the stat() system call on this path, like
1011 os.stat() does.
1012 """
1013 return os.stat(self, follow_symlinks=follow_symlinks)
1014
1015 def owner(self):
1016 """
1017 Return the login name of the file owner.
1018 """
1019 try:
1020 import pwd
1021 return pwd.getpwuid(self.stat().st_uid).pw_name
1022 except ImportError:
1023 raise NotImplementedError("Path.owner() is unsupported on this system")
1024
1025 def group(self):
1026 """
1027 Return the group name of the file gid.
1028 """
1029
1030 try:
1031 import grp
1032 return grp.getgrgid(self.stat().st_gid).gr_name
1033 except ImportError:
1034 raise NotImplementedError("Path.group() is unsupported on this system")
1035
1036 def open(self, mode='r', buffering=-1, encoding=None,
1037 errors=None, newline=None):
1038 """
1039 Open the file pointed by this path and return a file object, as
1040 the built-in open() function does.
1041 """
1042 if "b" not in mode:
1043 encoding = io.text_encoding(encoding)
1044 return io.open(self, mode, buffering, encoding, errors, newline)
1045
1046 def read_bytes(self):
1047 """
1048 Open the file in bytes mode, read it, and close the file.
1049 """
1050 with self.open(mode='rb') as f:
1051 return f.read()
1052
1053 def read_text(self, encoding=None, errors=None):
1054 """
1055 Open the file in text mode, read it, and close the file.
1056 """
1057 encoding = io.text_encoding(encoding)
1058 with self.open(mode='r', encoding=encoding, errors=errors) as f:
1059 return f.read()
1060
1061 def write_bytes(self, data):
1062 """
1063 Open the file in bytes mode, write to it, and close the file.
1064 """
1065 # type-check for the buffer interface before truncating the file
1066 view = memoryview(data)
1067 with self.open(mode='wb') as f:
1068 return f.write(view)
1069
1070 def write_text(self, data, encoding=None, errors=None, newline=None):
1071 """
1072 Open the file in text mode, write to it, and close the file.
1073 """
1074 if not isinstance(data, str):
1075 raise TypeError('data must be str, not %s' %
1076 data.__class__.__name__)
1077 encoding = io.text_encoding(encoding)
1078 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
1079 return f.write(data)
1080
1081 def readlink(self):
1082 """
1083 Return the path to which the symbolic link points.
1084 """
1085 if not hasattr(os, "readlink"):
1086 raise NotImplementedError("os.readlink() not available on this system")
1087 return self._from_parts((os.readlink(self),))
1088
1089 def touch(self, mode=0o666, exist_ok=True):
1090 """
1091 Create this file with the given access mode, if it doesn't exist.
1092 """
1093
1094 if exist_ok:
1095 # First try to bump modification time
1096 # Implementation note: GNU touch uses the UTIME_NOW option of
1097 # the utimensat() / futimens() functions.
1098 try:
1099 os.utime(self, None)
1100 except OSError:
1101 # Avoid exception chaining
1102 pass
1103 else:
1104 return
1105 flags = os.O_CREAT | os.O_WRONLY
1106 if not exist_ok:
1107 flags |= os.O_EXCL
1108 fd = os.open(self, flags, mode)
1109 os.close(fd)
1110
1111 def mkdir(self, mode=0o777, parents=False, exist_ok=False):
1112 """
1113 Create a new directory at this given path.
1114 """
1115 try:
1116 os.mkdir(self, mode)
1117 except FileNotFoundError:
1118 if not parents or self.parent == self:
1119 raise
1120 self.parent.mkdir(parents=True, exist_ok=True)
1121 self.mkdir(mode, parents=False, exist_ok=exist_ok)
1122 except OSError:
1123 # Cannot rely on checking for EEXIST, since the operating system
1124 # could give priority to other errors like EACCES or EROFS
1125 if not exist_ok or not self.is_dir():
1126 raise
1127
1128 def chmod(self, mode, *, follow_symlinks=True):
1129 """
1130 Change the permissions of the path, like os.chmod().
1131 """
1132 os.chmod(self, mode, follow_symlinks=follow_symlinks)
1133
1134 def lchmod(self, mode):
1135 """
1136 Like chmod(), except if the path points to a symlink, the symlink's
1137 permissions are changed, rather than its target's.
1138 """
1139 self.chmod(mode, follow_symlinks=False)
1140
1141 def unlink(self, missing_ok=False):
1142 """
1143 Remove this file or link.
1144 If the path is a directory, use rmdir() instead.
1145 """
1146 try:
1147 os.unlink(self)
1148 except FileNotFoundError:
1149 if not missing_ok:
1150 raise
1151
1152 def rmdir(self):
1153 """
1154 Remove this directory. The directory must be empty.
1155 """
1156 os.rmdir(self)
1157
1158 def lstat(self):
1159 """
1160 Like stat(), except if the path points to a symlink, the symlink's
1161 status information is returned, rather than its target's.
1162 """
1163 return self.stat(follow_symlinks=False)
1164
1165 def rename(self, target):
1166 """
1167 Rename this path to the target path.
1168
1169 The target path may be absolute or relative. Relative paths are
1170 interpreted relative to the current working directory, *not* the
1171 directory of the Path object.
1172
1173 Returns the new Path instance pointing to the target path.
1174 """
1175 os.rename(self, target)
1176 return self.__class__(target)
1177
1178 def replace(self, target):
1179 """
1180 Rename this path to the target path, overwriting if that path exists.
1181
1182 The target path may be absolute or relative. Relative paths are
1183 interpreted relative to the current working directory, *not* the
1184 directory of the Path object.
1185
1186 Returns the new Path instance pointing to the target path.
1187 """
1188 os.replace(self, target)
1189 return self.__class__(target)
1190
1191 def symlink_to(self, target, target_is_directory=False):
1192 """
1193 Make this path a symlink pointing to the target path.
1194 Note the order of arguments (link, target) is the reverse of os.symlink.
1195 """
1196 if not hasattr(os, "symlink"):
1197 raise NotImplementedError("os.symlink() not available on this system")
1198 os.symlink(target, self, target_is_directory)
1199
1200 def hardlink_to(self, target):
1201 """
1202 Make this path a hard link pointing to the same file as *target*.
1203
1204 Note the order of arguments (self, target) is the reverse of os.link's.
1205 """
1206 if not hasattr(os, "link"):
1207 raise NotImplementedError("os.link() not available on this system")
1208 os.link(target, self)
1209
1210 def link_to(self, target):
1211 """
1212 Make the target path a hard link pointing to this path.
1213
1214 Note this function does not make this path a hard link to *target*,
1215 despite the implication of the function and argument names. The order
1216 of arguments (target, link) is the reverse of Path.symlink_to, but
1217 matches that of os.link.
1218
1219 Deprecated since Python 3.10 and scheduled for removal in Python 3.12.
1220 Use `hardlink_to()` instead.
1221 """
1222 warnings.warn("pathlib.Path.link_to() is deprecated and is scheduled "
1223 "for removal in Python 3.12. "
1224 "Use pathlib.Path.hardlink_to() instead.",
1225 DeprecationWarning, stacklevel=2)
1226 self.__class__(target).hardlink_to(self)
1227
1228 # Convenience functions for querying the stat results
1229
1230 def exists(self):
1231 """
1232 Whether this path exists.
1233 """
1234 try:
1235 self.stat()
1236 except OSError as e:
1237 if not _ignore_error(e):
1238 raise
1239 return False
1240 except ValueError:
1241 # Non-encodable path
1242 return False
1243 return True
1244
1245 def is_dir(self):
1246 """
1247 Whether this path is a directory.
1248 """
1249 try:
1250 return S_ISDIR(self.stat().st_mode)
1251 except OSError as e:
1252 if not _ignore_error(e):
1253 raise
1254 # Path doesn't exist or is a broken symlink
1255 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
1256 return False
1257 except ValueError:
1258 # Non-encodable path
1259 return False
1260
1261 def is_file(self):
1262 """
1263 Whether this path is a regular file (also True for symlinks pointing
1264 to regular files).
1265 """
1266 try:
1267 return S_ISREG(self.stat().st_mode)
1268 except OSError as e:
1269 if not _ignore_error(e):
1270 raise
1271 # Path doesn't exist or is a broken symlink
1272 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
1273 return False
1274 except ValueError:
1275 # Non-encodable path
1276 return False
1277
1278 def is_mount(self):
1279 """
1280 Check if this path is a POSIX mount point
1281 """
1282 # Need to exist and be a dir
1283 if not self.exists() or not self.is_dir():
1284 return False
1285
1286 try:
1287 parent_dev = self.parent.stat().st_dev
1288 except OSError:
1289 return False
1290
1291 dev = self.stat().st_dev
1292 if dev != parent_dev:
1293 return True
1294 ino = self.stat().st_ino
1295 parent_ino = self.parent.stat().st_ino
1296 return ino == parent_ino
1297
1298 def is_symlink(self):
1299 """
1300 Whether this path is a symbolic link.
1301 """
1302 try:
1303 return S_ISLNK(self.lstat().st_mode)
1304 except OSError as e:
1305 if not _ignore_error(e):
1306 raise
1307 # Path doesn't exist
1308 return False
1309 except ValueError:
1310 # Non-encodable path
1311 return False
1312
1313 def is_block_device(self):
1314 """
1315 Whether this path is a block device.
1316 """
1317 try:
1318 return S_ISBLK(self.stat().st_mode)
1319 except OSError as e:
1320 if not _ignore_error(e):
1321 raise
1322 # Path doesn't exist or is a broken symlink
1323 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
1324 return False
1325 except ValueError:
1326 # Non-encodable path
1327 return False
1328
1329 def is_char_device(self):
1330 """
1331 Whether this path is a character device.
1332 """
1333 try:
1334 return S_ISCHR(self.stat().st_mode)
1335 except OSError as e:
1336 if not _ignore_error(e):
1337 raise
1338 # Path doesn't exist or is a broken symlink
1339 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
1340 return False
1341 except ValueError:
1342 # Non-encodable path
1343 return False
1344
1345 def is_fifo(self):
1346 """
1347 Whether this path is a FIFO.
1348 """
1349 try:
1350 return S_ISFIFO(self.stat().st_mode)
1351 except OSError as e:
1352 if not _ignore_error(e):
1353 raise
1354 # Path doesn't exist or is a broken symlink
1355 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
1356 return False
1357 except ValueError:
1358 # Non-encodable path
1359 return False
1360
1361 def is_socket(self):
1362 """
1363 Whether this path is a socket.
1364 """
1365 try:
1366 return S_ISSOCK(self.stat().st_mode)
1367 except OSError as e:
1368 if not _ignore_error(e):
1369 raise
1370 # Path doesn't exist or is a broken symlink
1371 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
1372 return False
1373 except ValueError:
1374 # Non-encodable path
1375 return False
1376
1377 def expanduser(self):
1378 """ Return a new path with expanded ~ and ~user constructs
1379 (as returned by os.path.expanduser)
1380 """
1381 if (not (self._drv or self._root) and
1382 self._parts and self._parts[0][:1] == '~'):
1383 homedir = os.path.expanduser(self._parts[0])
1384 if homedir[:1] == "~":
1385 raise RuntimeError("Could not determine home directory.")
1386 return self._from_parts([homedir] + self._parts[1:])
1387
1388 return self
1389
1390
1391 class ESC[4;38;5;81mPosixPath(ESC[4;38;5;149mPath, ESC[4;38;5;149mPurePosixPath):
1392 """Path subclass for non-Windows systems.
1393
1394 On a POSIX system, instantiating a Path should return this object.
1395 """
1396 __slots__ = ()
1397
1398 class ESC[4;38;5;81mWindowsPath(ESC[4;38;5;149mPath, ESC[4;38;5;149mPureWindowsPath):
1399 """Path subclass for Windows systems.
1400
1401 On a Windows system, instantiating a Path should return this object.
1402 """
1403 __slots__ = ()
1404
1405 def is_mount(self):
1406 raise NotImplementedError("Path.is_mount() is unsupported on this system")