pathlib
Object-oriented filesystem paths.
This module provides classes to represent abstract paths and concrete paths with operations that have semantics appropriate for different operating systems.
1"""Object-oriented filesystem paths. 2 3This module provides classes to represent abstract paths and concrete 4paths with operations that have semantics appropriate for different 5operating systems. 6""" 7 8import fnmatch 9import functools 10import io 11import ntpath 12import os 13import posixpath 14import re 15import sys 16import warnings 17from _collections_abc import Sequence 18from errno import ENOENT, ENOTDIR, EBADF, ELOOP 19from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO 20from urllib.parse import quote_from_bytes as urlquote_from_bytes 21 22 23__all__ = [ 24 "PurePath", "PurePosixPath", "PureWindowsPath", 25 "Path", "PosixPath", "WindowsPath", 26 ] 27 28# 29# Internals 30# 31 32# Reference for Windows paths can be found at 33# https://learn.microsoft.com/en-gb/windows/win32/fileio/naming-a-file . 34_WIN_RESERVED_NAMES = frozenset( 35 {'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} | 36 {f'COM{c}' for c in '123456789\xb9\xb2\xb3'} | 37 {f'LPT{c}' for c in '123456789\xb9\xb2\xb3'} 38) 39 40_WINERROR_NOT_READY = 21 # drive exists but is not accessible 41_WINERROR_INVALID_NAME = 123 # fix for bpo-35306 42_WINERROR_CANT_RESOLVE_FILENAME = 1921 # broken symlink pointing to itself 43 44# EBADF - guard against macOS `stat` throwing EBADF 45_IGNORED_ERRNOS = (ENOENT, ENOTDIR, EBADF, ELOOP) 46 47_IGNORED_WINERRORS = ( 48 _WINERROR_NOT_READY, 49 _WINERROR_INVALID_NAME, 50 _WINERROR_CANT_RESOLVE_FILENAME) 51 52def _ignore_error(exception): 53 return (getattr(exception, 'errno', None) in _IGNORED_ERRNOS or 54 getattr(exception, 'winerror', None) in _IGNORED_WINERRORS) 55 56 57@functools.cache 58def _is_case_sensitive(flavour): 59 return flavour.normcase('Aa') == 'Aa' 60 61# 62# Globbing helpers 63# 64 65 66# fnmatch.translate() returns a regular expression that includes a prefix and 67# a suffix, which enable matching newlines and ensure the end of the string is 68# matched, respectively. These features are undesirable for our implementation 69# of PurePatch.match(), which represents path separators as newlines and joins 70# pattern segments together. As a workaround, we define a slice object that 71# can remove the prefix and suffix from any translate() result. See the 72# _compile_pattern_lines() function for more details. 73_FNMATCH_PREFIX, _FNMATCH_SUFFIX = fnmatch.translate('_').split('_') 74_FNMATCH_SLICE = slice(len(_FNMATCH_PREFIX), -len(_FNMATCH_SUFFIX)) 75_SWAP_SEP_AND_NEWLINE = { 76 '/': str.maketrans({'/': '\n', '\n': '/'}), 77 '\\': str.maketrans({'\\': '\n', '\n': '\\'}), 78} 79 80 81@functools.lru_cache() 82def _make_selector(pattern_parts, flavour, case_sensitive): 83 pat = pattern_parts[0] 84 if not pat: 85 return _TerminatingSelector() 86 if pat == '**': 87 child_parts_idx = 1 88 while child_parts_idx < len(pattern_parts) and pattern_parts[child_parts_idx] == '**': 89 child_parts_idx += 1 90 child_parts = pattern_parts[child_parts_idx:] 91 if '**' in child_parts: 92 cls = _DoubleRecursiveWildcardSelector 93 else: 94 cls = _RecursiveWildcardSelector 95 else: 96 child_parts = pattern_parts[1:] 97 if pat == '..': 98 cls = _ParentSelector 99 elif '**' in pat: 100 raise ValueError("Invalid pattern: '**' can only be an entire path component") 101 else: 102 cls = _WildcardSelector 103 return cls(pat, child_parts, flavour, case_sensitive) 104 105 106@functools.lru_cache(maxsize=256) 107def _compile_pattern(pat, case_sensitive): 108 flags = re.NOFLAG if case_sensitive else re.IGNORECASE 109 return re.compile(fnmatch.translate(pat), flags).match 110 111 112@functools.lru_cache() 113def _compile_pattern_lines(pattern_lines, case_sensitive): 114 """Compile the given pattern lines to an `re.Pattern` object. 115 116 The *pattern_lines* argument is a glob-style pattern (e.g. '*/*.py') with 117 its path separators and newlines swapped (e.g. '*\n*.py`). By using 118 newlines to separate path components, and not setting `re.DOTALL`, we 119 ensure that the `*` wildcard cannot match path separators. 120 121 The returned `re.Pattern` object may have its `match()` method called to 122 match a complete pattern, or `search()` to match from the right. The 123 argument supplied to these methods must also have its path separators and 124 newlines swapped. 125 """ 126 127 # Match the start of the path, or just after a path separator 128 parts = ['^'] 129 for part in pattern_lines.splitlines(keepends=True): 130 if part == '*\n': 131 part = r'.+\n' 132 elif part == '*': 133 part = r'.+' 134 else: 135 # Any other component: pass to fnmatch.translate(). We slice off 136 # the common prefix and suffix added by translate() to ensure that 137 # re.DOTALL is not set, and the end of the string not matched, 138 # respectively. With DOTALL not set, '*' wildcards will not match 139 # path separators, because the '.' characters in the pattern will 140 # not match newlines. 141 part = fnmatch.translate(part)[_FNMATCH_SLICE] 142 parts.append(part) 143 # Match the end of the path, always. 144 parts.append(r'\Z') 145 flags = re.MULTILINE 146 if not case_sensitive: 147 flags |= re.IGNORECASE 148 return re.compile(''.join(parts), flags=flags) 149 150 151class _Selector: 152 """A selector matches a specific glob pattern part against the children 153 of a given path.""" 154 155 def __init__(self, child_parts, flavour, case_sensitive): 156 self.child_parts = child_parts 157 if child_parts: 158 self.successor = _make_selector(child_parts, flavour, case_sensitive) 159 self.dironly = True 160 else: 161 self.successor = _TerminatingSelector() 162 self.dironly = False 163 164 def select_from(self, parent_path): 165 """Iterate over all child paths of `parent_path` matched by this 166 selector. This can contain parent_path itself.""" 167 path_cls = type(parent_path) 168 scandir = path_cls._scandir 169 if not parent_path.is_dir(): 170 return iter([]) 171 return self._select_from(parent_path, scandir) 172 173 174class _TerminatingSelector: 175 176 def _select_from(self, parent_path, scandir): 177 yield parent_path 178 179 180class _ParentSelector(_Selector): 181 182 def __init__(self, name, child_parts, flavour, case_sensitive): 183 _Selector.__init__(self, child_parts, flavour, case_sensitive) 184 185 def _select_from(self, parent_path, scandir): 186 path = parent_path._make_child_relpath('..') 187 for p in self.successor._select_from(path, scandir): 188 yield p 189 190 191class _WildcardSelector(_Selector): 192 193 def __init__(self, pat, child_parts, flavour, case_sensitive): 194 _Selector.__init__(self, child_parts, flavour, case_sensitive) 195 if case_sensitive is None: 196 # TODO: evaluate case-sensitivity of each directory in _select_from() 197 case_sensitive = _is_case_sensitive(flavour) 198 self.match = _compile_pattern(pat, case_sensitive) 199 200 def _select_from(self, parent_path, scandir): 201 try: 202 # We must close the scandir() object before proceeding to 203 # avoid exhausting file descriptors when globbing deep trees. 204 with scandir(parent_path) as scandir_it: 205 entries = list(scandir_it) 206 except OSError: 207 pass 208 else: 209 for entry in entries: 210 if self.dironly: 211 try: 212 if not entry.is_dir(): 213 continue 214 except OSError: 215 continue 216 name = entry.name 217 if self.match(name): 218 path = parent_path._make_child_relpath(name) 219 for p in self.successor._select_from(path, scandir): 220 yield p 221 222 223class _RecursiveWildcardSelector(_Selector): 224 225 def __init__(self, pat, child_parts, flavour, case_sensitive): 226 _Selector.__init__(self, child_parts, flavour, case_sensitive) 227 228 def _iterate_directories(self, parent_path): 229 yield parent_path 230 for dirpath, dirnames, _ in parent_path.walk(): 231 for dirname in dirnames: 232 yield dirpath._make_child_relpath(dirname) 233 234 def _select_from(self, parent_path, scandir): 235 successor_select = self.successor._select_from 236 for starting_point in self._iterate_directories(parent_path): 237 for p in successor_select(starting_point, scandir): 238 yield p 239 240 241class _DoubleRecursiveWildcardSelector(_RecursiveWildcardSelector): 242 """ 243 Like _RecursiveWildcardSelector, but also de-duplicates results from 244 successive selectors. This is necessary if the pattern contains 245 multiple non-adjacent '**' segments. 246 """ 247 248 def _select_from(self, parent_path, scandir): 249 yielded = set() 250 try: 251 for p in super()._select_from(parent_path, scandir): 252 if p not in yielded: 253 yield p 254 yielded.add(p) 255 finally: 256 yielded.clear() 257 258 259# 260# Public API 261# 262 263class _PathParents(Sequence): 264 """This object provides sequence-like access to the logical ancestors 265 of a path. Don't try to construct it yourself.""" 266 __slots__ = ('_path', '_drv', '_root', '_tail') 267 268 def __init__(self, path): 269 self._path = path 270 self._drv = path.drive 271 self._root = path.root 272 self._tail = path._tail 273 274 def __len__(self): 275 return len(self._tail) 276 277 def __getitem__(self, idx): 278 if isinstance(idx, slice): 279 return tuple(self[i] for i in range(*idx.indices(len(self)))) 280 281 if idx >= len(self) or idx < -len(self): 282 raise IndexError(idx) 283 if idx < 0: 284 idx += len(self) 285 return self._path._from_parsed_parts(self._drv, self._root, 286 self._tail[:-idx - 1]) 287 288 def __repr__(self): 289 return "<{}.parents>".format(type(self._path).__name__) 290 291 292class PurePath(object): 293 """Base class for manipulating paths without I/O. 294 295 PurePath represents a filesystem path and offers operations which 296 don't imply any actual filesystem I/O. Depending on your system, 297 instantiating a PurePath will return either a PurePosixPath or a 298 PureWindowsPath object. You can also instantiate either of these classes 299 directly, regardless of your system. 300 """ 301 302 __slots__ = ( 303 # The `_raw_paths` slot stores unnormalized string paths. This is set 304 # in the `__init__()` method. 305 '_raw_paths', 306 307 # The `_drv`, `_root` and `_tail_cached` slots store parsed and 308 # normalized parts of the path. They are set when any of the `drive`, 309 # `root` or `_tail` properties are accessed for the first time. The 310 # three-part division corresponds to the result of 311 # `os.path.splitroot()`, except that the tail is further split on path 312 # separators (i.e. it is a list of strings), and that the root and 313 # tail are normalized. 314 '_drv', '_root', '_tail_cached', 315 316 # The `_str` slot stores the string representation of the path, 317 # computed from the drive, root and tail when `__str__()` is called 318 # for the first time. It's used to implement `_str_normcase` 319 '_str', 320 321 # The `_str_normcase_cached` slot stores the string path with 322 # normalized case. It is set when the `_str_normcase` property is 323 # accessed for the first time. It's used to implement `__eq__()` 324 # `__hash__()`, and `_parts_normcase` 325 '_str_normcase_cached', 326 327 # The `_parts_normcase_cached` slot stores the case-normalized 328 # string path after splitting on path separators. It's set when the 329 # `_parts_normcase` property is accessed for the first time. It's used 330 # to implement comparison methods like `__lt__()`. 331 '_parts_normcase_cached', 332 333 # The `_lines_cached` slot stores the string path with path separators 334 # and newlines swapped. This is used to implement `match()`. 335 '_lines_cached', 336 337 # The `_hash` slot stores the hash of the case-normalized string 338 # path. It's set when `__hash__()` is called for the first time. 339 '_hash', 340 ) 341 _flavour = os.path 342 343 def __new__(cls, *args, **kwargs): 344 """Construct a PurePath from one or several strings and or existing 345 PurePath objects. The strings and path objects are combined so as 346 to yield a canonicalized path, which is incorporated into the 347 new PurePath object. 348 """ 349 if cls is PurePath: 350 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath 351 return object.__new__(cls) 352 353 def __reduce__(self): 354 # Using the parts tuple helps share interned path parts 355 # when pickling related paths. 356 return (self.__class__, self.parts) 357 358 def __init__(self, *args): 359 paths = [] 360 for arg in args: 361 if isinstance(arg, PurePath): 362 if arg._flavour is ntpath and self._flavour is posixpath: 363 # GH-103631: Convert separators for backwards compatibility. 364 paths.extend(path.replace('\\', '/') for path in arg._raw_paths) 365 else: 366 paths.extend(arg._raw_paths) 367 else: 368 try: 369 path = os.fspath(arg) 370 except TypeError: 371 path = arg 372 if not isinstance(path, str): 373 raise TypeError( 374 "argument should be a str or an os.PathLike " 375 "object where __fspath__ returns a str, " 376 f"not {type(path).__name__!r}") 377 paths.append(path) 378 self._raw_paths = paths 379 380 def with_segments(self, *pathsegments): 381 """Construct a new path object from any number of path-like objects. 382 Subclasses may override this method to customize how new path objects 383 are created from methods like `iterdir()`. 384 """ 385 return type(self)(*pathsegments) 386 387 @classmethod 388 def _parse_path(cls, path): 389 if not path: 390 return '', '', [] 391 sep = cls._flavour.sep 392 altsep = cls._flavour.altsep 393 if altsep: 394 path = path.replace(altsep, sep) 395 drv, root, rel = cls._flavour.splitroot(path) 396 if not root and drv.startswith(sep) and not drv.endswith(sep): 397 drv_parts = drv.split(sep) 398 if len(drv_parts) == 4 and drv_parts[2] not in '?.': 399 # e.g. //server/share 400 root = sep 401 elif len(drv_parts) == 6: 402 # e.g. //?/unc/server/share 403 root = sep 404 parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.'] 405 return drv, root, parsed 406 407 def _load_parts(self): 408 paths = self._raw_paths 409 if len(paths) == 0: 410 path = '' 411 elif len(paths) == 1: 412 path = paths[0] 413 else: 414 path = self._flavour.join(*paths) 415 drv, root, tail = self._parse_path(path) 416 self._drv = drv 417 self._root = root 418 self._tail_cached = tail 419 420 def _from_parsed_parts(self, drv, root, tail): 421 path_str = self._format_parsed_parts(drv, root, tail) 422 path = self.with_segments(path_str) 423 path._str = path_str or '.' 424 path._drv = drv 425 path._root = root 426 path._tail_cached = tail 427 return path 428 429 @classmethod 430 def _format_parsed_parts(cls, drv, root, tail): 431 if drv or root: 432 return drv + root + cls._flavour.sep.join(tail) 433 elif tail and cls._flavour.splitdrive(tail[0])[0]: 434 tail = ['.'] + tail 435 return cls._flavour.sep.join(tail) 436 437 def __str__(self): 438 """Return the string representation of the path, suitable for 439 passing to system calls.""" 440 try: 441 return self._str 442 except AttributeError: 443 self._str = self._format_parsed_parts(self.drive, self.root, 444 self._tail) or '.' 445 return self._str 446 447 def __fspath__(self): 448 return str(self) 449 450 def as_posix(self): 451 """Return the string representation of the path with forward (/) 452 slashes.""" 453 f = self._flavour 454 return str(self).replace(f.sep, '/') 455 456 def __bytes__(self): 457 """Return the bytes representation of the path. This is only 458 recommended to use under Unix.""" 459 return os.fsencode(self) 460 461 def __repr__(self): 462 return "{}({!r})".format(self.__class__.__name__, self.as_posix()) 463 464 def as_uri(self): 465 """Return the path as a 'file' URI.""" 466 if not self.is_absolute(): 467 raise ValueError("relative path can't be expressed as a file URI") 468 469 drive = self.drive 470 if len(drive) == 2 and drive[1] == ':': 471 # It's a path on a local drive => 'file:///c:/a/b' 472 prefix = 'file:///' + drive 473 path = self.as_posix()[2:] 474 elif drive: 475 # It's a path on a network drive => 'file://host/share/a/b' 476 prefix = 'file:' 477 path = self.as_posix() 478 else: 479 # It's a posix path => 'file:///etc/hosts' 480 prefix = 'file://' 481 path = str(self) 482 return prefix + urlquote_from_bytes(os.fsencode(path)) 483 484 @property 485 def _str_normcase(self): 486 # String with normalized case, for hashing and equality checks 487 try: 488 return self._str_normcase_cached 489 except AttributeError: 490 if _is_case_sensitive(self._flavour): 491 self._str_normcase_cached = str(self) 492 else: 493 self._str_normcase_cached = str(self).lower() 494 return self._str_normcase_cached 495 496 @property 497 def _parts_normcase(self): 498 # Cached parts with normalized case, for comparisons. 499 try: 500 return self._parts_normcase_cached 501 except AttributeError: 502 self._parts_normcase_cached = self._str_normcase.split(self._flavour.sep) 503 return self._parts_normcase_cached 504 505 @property 506 def _lines(self): 507 # Path with separators and newlines swapped, for pattern matching. 508 try: 509 return self._lines_cached 510 except AttributeError: 511 path_str = str(self) 512 if path_str == '.': 513 self._lines_cached = '' 514 else: 515 trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] 516 self._lines_cached = path_str.translate(trans) 517 return self._lines_cached 518 519 def __eq__(self, other): 520 if not isinstance(other, PurePath): 521 return NotImplemented 522 return self._str_normcase == other._str_normcase and self._flavour is other._flavour 523 524 def __hash__(self): 525 try: 526 return self._hash 527 except AttributeError: 528 self._hash = hash(self._str_normcase) 529 return self._hash 530 531 def __lt__(self, other): 532 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 533 return NotImplemented 534 return self._parts_normcase < other._parts_normcase 535 536 def __le__(self, other): 537 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 538 return NotImplemented 539 return self._parts_normcase <= other._parts_normcase 540 541 def __gt__(self, other): 542 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 543 return NotImplemented 544 return self._parts_normcase > other._parts_normcase 545 546 def __ge__(self, other): 547 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 548 return NotImplemented 549 return self._parts_normcase >= other._parts_normcase 550 551 @property 552 def drive(self): 553 """The drive prefix (letter or UNC path), if any.""" 554 try: 555 return self._drv 556 except AttributeError: 557 self._load_parts() 558 return self._drv 559 560 @property 561 def root(self): 562 """The root of the path, if any.""" 563 try: 564 return self._root 565 except AttributeError: 566 self._load_parts() 567 return self._root 568 569 @property 570 def _tail(self): 571 try: 572 return self._tail_cached 573 except AttributeError: 574 self._load_parts() 575 return self._tail_cached 576 577 @property 578 def anchor(self): 579 """The concatenation of the drive and root, or ''.""" 580 anchor = self.drive + self.root 581 return anchor 582 583 @property 584 def name(self): 585 """The final path component, if any.""" 586 tail = self._tail 587 if not tail: 588 return '' 589 return tail[-1] 590 591 @property 592 def suffix(self): 593 """ 594 The final component's last suffix, if any. 595 596 This includes the leading period. For example: '.txt' 597 """ 598 name = self.name 599 i = name.rfind('.') 600 if 0 < i < len(name) - 1: 601 return name[i:] 602 else: 603 return '' 604 605 @property 606 def suffixes(self): 607 """ 608 A list of the final component's suffixes, if any. 609 610 These include the leading periods. For example: ['.tar', '.gz'] 611 """ 612 name = self.name 613 if name.endswith('.'): 614 return [] 615 name = name.lstrip('.') 616 return ['.' + suffix for suffix in name.split('.')[1:]] 617 618 @property 619 def stem(self): 620 """The final path component, minus its last suffix.""" 621 name = self.name 622 i = name.rfind('.') 623 if 0 < i < len(name) - 1: 624 return name[:i] 625 else: 626 return name 627 628 def with_name(self, name): 629 """Return a new path with the file name changed.""" 630 if not self.name: 631 raise ValueError("%r has an empty name" % (self,)) 632 f = self._flavour 633 drv, root, tail = f.splitroot(name) 634 if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail): 635 raise ValueError("Invalid name %r" % (name)) 636 return self._from_parsed_parts(self.drive, self.root, 637 self._tail[:-1] + [name]) 638 639 def with_stem(self, stem): 640 """Return a new path with the stem changed.""" 641 return self.with_name(stem + self.suffix) 642 643 def with_suffix(self, suffix): 644 """Return a new path with the file suffix changed. If the path 645 has no suffix, add given suffix. If the given suffix is an empty 646 string, remove the suffix from the path. 647 """ 648 f = self._flavour 649 if f.sep in suffix or f.altsep and f.altsep in suffix: 650 raise ValueError("Invalid suffix %r" % (suffix,)) 651 if suffix and not suffix.startswith('.') or suffix == '.': 652 raise ValueError("Invalid suffix %r" % (suffix)) 653 name = self.name 654 if not name: 655 raise ValueError("%r has an empty name" % (self,)) 656 old_suffix = self.suffix 657 if not old_suffix: 658 name = name + suffix 659 else: 660 name = name[:-len(old_suffix)] + suffix 661 return self._from_parsed_parts(self.drive, self.root, 662 self._tail[:-1] + [name]) 663 664 def relative_to(self, other, /, *_deprecated, walk_up=False): 665 """Return the relative path to another path identified by the passed 666 arguments. If the operation is not possible (because this is not 667 related to the other path), raise ValueError. 668 669 The *walk_up* parameter controls whether `..` may be used to resolve 670 the path. 671 """ 672 if _deprecated: 673 msg = ("support for supplying more than one positional argument " 674 "to pathlib.PurePath.relative_to() is deprecated and " 675 "scheduled for removal in Python {remove}") 676 warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg, 677 remove=(3, 14)) 678 other = self.with_segments(other, *_deprecated) 679 for step, path in enumerate([other] + list(other.parents)): 680 if self.is_relative_to(path): 681 break 682 elif not walk_up: 683 raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") 684 elif path.name == '..': 685 raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") 686 else: 687 raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") 688 parts = ['..'] * step + self._tail[len(path._tail):] 689 return self.with_segments(*parts) 690 691 def is_relative_to(self, other, /, *_deprecated): 692 """Return True if the path is relative to another path or False. 693 """ 694 if _deprecated: 695 msg = ("support for supplying more than one argument to " 696 "pathlib.PurePath.is_relative_to() is deprecated and " 697 "scheduled for removal in Python {remove}") 698 warnings._deprecated("pathlib.PurePath.is_relative_to(*args)", 699 msg, remove=(3, 14)) 700 other = self.with_segments(other, *_deprecated) 701 return other == self or other in self.parents 702 703 @property 704 def parts(self): 705 """An object providing sequence-like access to the 706 components in the filesystem path.""" 707 if self.drive or self.root: 708 return (self.drive + self.root,) + tuple(self._tail) 709 else: 710 return tuple(self._tail) 711 712 def joinpath(self, *pathsegments): 713 """Combine this path with one or several arguments, and return a 714 new path representing either a subpath (if all arguments are relative 715 paths) or a totally different path (if one of the arguments is 716 anchored). 717 """ 718 return self.with_segments(self, *pathsegments) 719 720 def __truediv__(self, key): 721 try: 722 return self.joinpath(key) 723 except TypeError: 724 return NotImplemented 725 726 def __rtruediv__(self, key): 727 try: 728 return self.with_segments(key, self) 729 except TypeError: 730 return NotImplemented 731 732 @property 733 def parent(self): 734 """The logical parent of the path.""" 735 drv = self.drive 736 root = self.root 737 tail = self._tail 738 if not tail: 739 return self 740 return self._from_parsed_parts(drv, root, tail[:-1]) 741 742 @property 743 def parents(self): 744 """A sequence of this path's logical parents.""" 745 # The value of this property should not be cached on the path object, 746 # as doing so would introduce a reference cycle. 747 return _PathParents(self) 748 749 def is_absolute(self): 750 """True if the path is absolute (has both a root and, if applicable, 751 a drive).""" 752 if self._flavour is ntpath: 753 # ntpath.isabs() is defective - see GH-44626. 754 return bool(self.drive and self.root) 755 elif self._flavour is posixpath: 756 # Optimization: work with raw paths on POSIX. 757 for path in self._raw_paths: 758 if path.startswith('/'): 759 return True 760 return False 761 else: 762 return self._flavour.isabs(str(self)) 763 764 def is_reserved(self): 765 """Return True if the path contains one of the special names reserved 766 by the system, if any.""" 767 if self._flavour is posixpath or not self._tail: 768 return False 769 770 # NOTE: the rules for reserved names seem somewhat complicated 771 # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not 772 # exist). We err on the side of caution and return True for paths 773 # which are not considered reserved by Windows. 774 if self.drive.startswith('\\\\'): 775 # UNC paths are never reserved. 776 return False 777 name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ') 778 return name.upper() in _WIN_RESERVED_NAMES 779 780 def match(self, path_pattern, *, case_sensitive=None): 781 """ 782 Return True if this path matches the given pattern. 783 """ 784 if not isinstance(path_pattern, PurePath): 785 path_pattern = self.with_segments(path_pattern) 786 if case_sensitive is None: 787 case_sensitive = _is_case_sensitive(self._flavour) 788 pattern = _compile_pattern_lines(path_pattern._lines, case_sensitive) 789 if path_pattern.drive or path_pattern.root: 790 return pattern.match(self._lines) is not None 791 elif path_pattern._tail: 792 return pattern.search(self._lines) is not None 793 else: 794 raise ValueError("empty pattern") 795 796 797# Can't subclass os.PathLike from PurePath and keep the constructor 798# optimizations in PurePath.__slots__. 799os.PathLike.register(PurePath) 800 801 802class PurePosixPath(PurePath): 803 """PurePath subclass for non-Windows systems. 804 805 On a POSIX system, instantiating a PurePath should return this object. 806 However, you can also instantiate it directly on any system. 807 """ 808 _flavour = posixpath 809 __slots__ = () 810 811 812class PureWindowsPath(PurePath): 813 """PurePath subclass for Windows systems. 814 815 On a Windows system, instantiating a PurePath should return this object. 816 However, you can also instantiate it directly on any system. 817 """ 818 _flavour = ntpath 819 __slots__ = () 820 821 822# Filesystem-accessing classes 823 824 825class Path(PurePath): 826 """PurePath subclass that can make system calls. 827 828 Path represents a filesystem path but unlike PurePath, also offers 829 methods to do system calls on path objects. Depending on your system, 830 instantiating a Path will return either a PosixPath or a WindowsPath 831 object. You can also instantiate a PosixPath or WindowsPath directly, 832 but cannot instantiate a WindowsPath on a POSIX system or vice versa. 833 """ 834 __slots__ = () 835 836 def stat(self, *, follow_symlinks=True): 837 """ 838 Return the result of the stat() system call on this path, like 839 os.stat() does. 840 """ 841 return os.stat(self, follow_symlinks=follow_symlinks) 842 843 def lstat(self): 844 """ 845 Like stat(), except if the path points to a symlink, the symlink's 846 status information is returned, rather than its target's. 847 """ 848 return self.stat(follow_symlinks=False) 849 850 851 # Convenience functions for querying the stat results 852 853 def exists(self, *, follow_symlinks=True): 854 """ 855 Whether this path exists. 856 857 This method normally follows symlinks; to check whether a symlink exists, 858 add the argument follow_symlinks=False. 859 """ 860 try: 861 self.stat(follow_symlinks=follow_symlinks) 862 except OSError as e: 863 if not _ignore_error(e): 864 raise 865 return False 866 except ValueError: 867 # Non-encodable path 868 return False 869 return True 870 871 def is_dir(self): 872 """ 873 Whether this path is a directory. 874 """ 875 try: 876 return S_ISDIR(self.stat().st_mode) 877 except OSError as e: 878 if not _ignore_error(e): 879 raise 880 # Path doesn't exist or is a broken symlink 881 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 882 return False 883 except ValueError: 884 # Non-encodable path 885 return False 886 887 def is_file(self): 888 """ 889 Whether this path is a regular file (also True for symlinks pointing 890 to regular files). 891 """ 892 try: 893 return S_ISREG(self.stat().st_mode) 894 except OSError as e: 895 if not _ignore_error(e): 896 raise 897 # Path doesn't exist or is a broken symlink 898 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 899 return False 900 except ValueError: 901 # Non-encodable path 902 return False 903 904 def is_mount(self): 905 """ 906 Check if this path is a mount point 907 """ 908 return self._flavour.ismount(self) 909 910 def is_symlink(self): 911 """ 912 Whether this path is a symbolic link. 913 """ 914 try: 915 return S_ISLNK(self.lstat().st_mode) 916 except OSError as e: 917 if not _ignore_error(e): 918 raise 919 # Path doesn't exist 920 return False 921 except ValueError: 922 # Non-encodable path 923 return False 924 925 def is_junction(self): 926 """ 927 Whether this path is a junction. 928 """ 929 return self._flavour.isjunction(self) 930 931 def is_block_device(self): 932 """ 933 Whether this path is a block device. 934 """ 935 try: 936 return S_ISBLK(self.stat().st_mode) 937 except OSError as e: 938 if not _ignore_error(e): 939 raise 940 # Path doesn't exist or is a broken symlink 941 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 942 return False 943 except ValueError: 944 # Non-encodable path 945 return False 946 947 def is_char_device(self): 948 """ 949 Whether this path is a character device. 950 """ 951 try: 952 return S_ISCHR(self.stat().st_mode) 953 except OSError as e: 954 if not _ignore_error(e): 955 raise 956 # Path doesn't exist or is a broken symlink 957 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 958 return False 959 except ValueError: 960 # Non-encodable path 961 return False 962 963 def is_fifo(self): 964 """ 965 Whether this path is a FIFO. 966 """ 967 try: 968 return S_ISFIFO(self.stat().st_mode) 969 except OSError as e: 970 if not _ignore_error(e): 971 raise 972 # Path doesn't exist or is a broken symlink 973 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 974 return False 975 except ValueError: 976 # Non-encodable path 977 return False 978 979 def is_socket(self): 980 """ 981 Whether this path is a socket. 982 """ 983 try: 984 return S_ISSOCK(self.stat().st_mode) 985 except OSError as e: 986 if not _ignore_error(e): 987 raise 988 # Path doesn't exist or is a broken symlink 989 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 990 return False 991 except ValueError: 992 # Non-encodable path 993 return False 994 995 def samefile(self, other_path): 996 """Return whether other_path is the same or not as this file 997 (as returned by os.path.samefile()). 998 """ 999 st = self.stat() 1000 try: 1001 other_st = other_path.stat() 1002 except AttributeError: 1003 other_st = self.with_segments(other_path).stat() 1004 return self._flavour.samestat(st, other_st) 1005 1006 def open(self, mode='r', buffering=-1, encoding=None, 1007 errors=None, newline=None): 1008 """ 1009 Open the file pointed by this path and return a file object, as 1010 the built-in open() function does. 1011 """ 1012 if "b" not in mode: 1013 encoding = io.text_encoding(encoding) 1014 return io.open(self, mode, buffering, encoding, errors, newline) 1015 1016 def read_bytes(self): 1017 """ 1018 Open the file in bytes mode, read it, and close the file. 1019 """ 1020 with self.open(mode='rb') as f: 1021 return f.read() 1022 1023 def read_text(self, encoding=None, errors=None): 1024 """ 1025 Open the file in text mode, read it, and close the file. 1026 """ 1027 encoding = io.text_encoding(encoding) 1028 with self.open(mode='r', encoding=encoding, errors=errors) as f: 1029 return f.read() 1030 1031 def write_bytes(self, data): 1032 """ 1033 Open the file in bytes mode, write to it, and close the file. 1034 """ 1035 # type-check for the buffer interface before truncating the file 1036 view = memoryview(data) 1037 with self.open(mode='wb') as f: 1038 return f.write(view) 1039 1040 def write_text(self, data, encoding=None, errors=None, newline=None): 1041 """ 1042 Open the file in text mode, write to it, and close the file. 1043 """ 1044 if not isinstance(data, str): 1045 raise TypeError('data must be str, not %s' % 1046 data.__class__.__name__) 1047 encoding = io.text_encoding(encoding) 1048 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: 1049 return f.write(data) 1050 1051 def iterdir(self): 1052 """Yield path objects of the directory contents. 1053 1054 The children are yielded in arbitrary order, and the 1055 special entries '.' and '..' are not included. 1056 """ 1057 for name in os.listdir(self): 1058 yield self._make_child_relpath(name) 1059 1060 def _scandir(self): 1061 # bpo-24132: a future version of pathlib will support subclassing of 1062 # pathlib.Path to customize how the filesystem is accessed. This 1063 # includes scandir(), which is used to implement glob(). 1064 return os.scandir(self) 1065 1066 def _make_child_relpath(self, name): 1067 path_str = str(self) 1068 tail = self._tail 1069 if tail: 1070 path_str = f'{path_str}{self._flavour.sep}{name}' 1071 elif path_str != '.': 1072 path_str = f'{path_str}{name}' 1073 else: 1074 path_str = name 1075 path = self.with_segments(path_str) 1076 path._str = path_str 1077 path._drv = self.drive 1078 path._root = self.root 1079 path._tail_cached = tail + [name] 1080 return path 1081 1082 def glob(self, pattern, *, case_sensitive=None): 1083 """Iterate over this subtree and yield all existing files (of any 1084 kind, including directories) matching the given relative pattern. 1085 """ 1086 sys.audit("pathlib.Path.glob", self, pattern) 1087 if not pattern: 1088 raise ValueError("Unacceptable pattern: {!r}".format(pattern)) 1089 drv, root, pattern_parts = self._parse_path(pattern) 1090 if drv or root: 1091 raise NotImplementedError("Non-relative patterns are unsupported") 1092 if pattern[-1] in (self._flavour.sep, self._flavour.altsep): 1093 pattern_parts.append('') 1094 selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive) 1095 for p in selector.select_from(self): 1096 yield p 1097 1098 def rglob(self, pattern, *, case_sensitive=None): 1099 """Recursively yield all existing files (of any kind, including 1100 directories) matching the given relative pattern, anywhere in 1101 this subtree. 1102 """ 1103 sys.audit("pathlib.Path.rglob", self, pattern) 1104 drv, root, pattern_parts = self._parse_path(pattern) 1105 if drv or root: 1106 raise NotImplementedError("Non-relative patterns are unsupported") 1107 if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep): 1108 pattern_parts.append('') 1109 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive) 1110 for p in selector.select_from(self): 1111 yield p 1112 1113 def walk(self, top_down=True, on_error=None, follow_symlinks=False): 1114 """Walk the directory tree from this directory, similar to os.walk().""" 1115 sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) 1116 paths = [self] 1117 1118 while paths: 1119 path = paths.pop() 1120 if isinstance(path, tuple): 1121 yield path 1122 continue 1123 1124 # We may not have read permission for self, in which case we can't 1125 # get a list of the files the directory contains. os.walk() 1126 # always suppressed the exception in that instance, rather than 1127 # blow up for a minor reason when (say) a thousand readable 1128 # directories are still left to visit. That logic is copied here. 1129 try: 1130 scandir_it = path._scandir() 1131 except OSError as error: 1132 if on_error is not None: 1133 on_error(error) 1134 continue 1135 1136 with scandir_it: 1137 dirnames = [] 1138 filenames = [] 1139 for entry in scandir_it: 1140 try: 1141 is_dir = entry.is_dir(follow_symlinks=follow_symlinks) 1142 except OSError: 1143 # Carried over from os.path.isdir(). 1144 is_dir = False 1145 1146 if is_dir: 1147 dirnames.append(entry.name) 1148 else: 1149 filenames.append(entry.name) 1150 1151 if top_down: 1152 yield path, dirnames, filenames 1153 else: 1154 paths.append((path, dirnames, filenames)) 1155 1156 paths += [path._make_child_relpath(d) for d in reversed(dirnames)] 1157 1158 def __init__(self, *args, **kwargs): 1159 if kwargs: 1160 msg = ("support for supplying keyword arguments to pathlib.PurePath " 1161 "is deprecated and scheduled for removal in Python {remove}") 1162 warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14)) 1163 super().__init__(*args) 1164 1165 def __new__(cls, *args, **kwargs): 1166 if cls is Path: 1167 cls = WindowsPath if os.name == 'nt' else PosixPath 1168 return object.__new__(cls) 1169 1170 def __enter__(self): 1171 # In previous versions of pathlib, __exit__() marked this path as 1172 # closed; subsequent attempts to perform I/O would raise an IOError. 1173 # This functionality was never documented, and had the effect of 1174 # making Path objects mutable, contrary to PEP 428. 1175 # In Python 3.9 __exit__() was made a no-op. 1176 # In Python 3.11 __enter__() began emitting DeprecationWarning. 1177 # In Python 3.13 __enter__() and __exit__() should be removed. 1178 warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " 1179 "for removal in Python 3.13; Path objects as a context " 1180 "manager is a no-op", 1181 DeprecationWarning, stacklevel=2) 1182 return self 1183 1184 def __exit__(self, t, v, tb): 1185 pass 1186 1187 # Public API 1188 1189 @classmethod 1190 def cwd(cls): 1191 """Return a new path pointing to the current working directory.""" 1192 # We call 'absolute()' rather than using 'os.getcwd()' directly to 1193 # enable users to replace the implementation of 'absolute()' in a 1194 # subclass and benefit from the new behaviour here. This works because 1195 # os.path.abspath('.') == os.getcwd(). 1196 return cls().absolute() 1197 1198 @classmethod 1199 def home(cls): 1200 """Return a new path pointing to the user's home directory (as 1201 returned by os.path.expanduser('~')). 1202 """ 1203 return cls("~").expanduser() 1204 1205 def absolute(self): 1206 """Return an absolute version of this path by prepending the current 1207 working directory. No normalization or symlink resolution is performed. 1208 1209 Use resolve() to get the canonical path to a file. 1210 """ 1211 if self.is_absolute(): 1212 return self 1213 elif self.drive: 1214 # There is a CWD on each drive-letter drive. 1215 cwd = self._flavour.abspath(self.drive) 1216 else: 1217 cwd = os.getcwd() 1218 # Fast path for "empty" paths, e.g. Path("."), Path("") or Path(). 1219 # We pass only one argument to with_segments() to avoid the cost 1220 # of joining, and we exploit the fact that getcwd() returns a 1221 # fully-normalized string by storing it in _str. This is used to 1222 # implement Path.cwd(). 1223 if not self.root and not self._tail: 1224 result = self.with_segments(cwd) 1225 result._str = cwd 1226 return result 1227 return self.with_segments(cwd, self) 1228 1229 def resolve(self, strict=False): 1230 """ 1231 Make the path absolute, resolving all symlinks on the way and also 1232 normalizing it. 1233 """ 1234 1235 def check_eloop(e): 1236 winerror = getattr(e, 'winerror', 0) 1237 if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME: 1238 raise RuntimeError("Symlink loop from %r" % e.filename) 1239 1240 try: 1241 s = self._flavour.realpath(self, strict=strict) 1242 except OSError as e: 1243 check_eloop(e) 1244 raise 1245 p = self.with_segments(s) 1246 1247 # In non-strict mode, realpath() doesn't raise on symlink loops. 1248 # Ensure we get an exception by calling stat() 1249 if not strict: 1250 try: 1251 p.stat() 1252 except OSError as e: 1253 check_eloop(e) 1254 return p 1255 1256 def owner(self): 1257 """ 1258 Return the login name of the file owner. 1259 """ 1260 try: 1261 import pwd 1262 return pwd.getpwuid(self.stat().st_uid).pw_name 1263 except ImportError: 1264 raise NotImplementedError("Path.owner() is unsupported on this system") 1265 1266 def group(self): 1267 """ 1268 Return the group name of the file gid. 1269 """ 1270 1271 try: 1272 import grp 1273 return grp.getgrgid(self.stat().st_gid).gr_name 1274 except ImportError: 1275 raise NotImplementedError("Path.group() is unsupported on this system") 1276 1277 def readlink(self): 1278 """ 1279 Return the path to which the symbolic link points. 1280 """ 1281 if not hasattr(os, "readlink"): 1282 raise NotImplementedError("os.readlink() not available on this system") 1283 return self.with_segments(os.readlink(self)) 1284 1285 def touch(self, mode=0o666, exist_ok=True): 1286 """ 1287 Create this file with the given access mode, if it doesn't exist. 1288 """ 1289 1290 if exist_ok: 1291 # First try to bump modification time 1292 # Implementation note: GNU touch uses the UTIME_NOW option of 1293 # the utimensat() / futimens() functions. 1294 try: 1295 os.utime(self, None) 1296 except OSError: 1297 # Avoid exception chaining 1298 pass 1299 else: 1300 return 1301 flags = os.O_CREAT | os.O_WRONLY 1302 if not exist_ok: 1303 flags |= os.O_EXCL 1304 fd = os.open(self, flags, mode) 1305 os.close(fd) 1306 1307 def mkdir(self, mode=0o777, parents=False, exist_ok=False): 1308 """ 1309 Create a new directory at this given path. 1310 """ 1311 try: 1312 os.mkdir(self, mode) 1313 except FileNotFoundError: 1314 if not parents or self.parent == self: 1315 raise 1316 self.parent.mkdir(parents=True, exist_ok=True) 1317 self.mkdir(mode, parents=False, exist_ok=exist_ok) 1318 except OSError: 1319 # Cannot rely on checking for EEXIST, since the operating system 1320 # could give priority to other errors like EACCES or EROFS 1321 if not exist_ok or not self.is_dir(): 1322 raise 1323 1324 def chmod(self, mode, *, follow_symlinks=True): 1325 """ 1326 Change the permissions of the path, like os.chmod(). 1327 """ 1328 os.chmod(self, mode, follow_symlinks=follow_symlinks) 1329 1330 def lchmod(self, mode): 1331 """ 1332 Like chmod(), except if the path points to a symlink, the symlink's 1333 permissions are changed, rather than its target's. 1334 """ 1335 self.chmod(mode, follow_symlinks=False) 1336 1337 def unlink(self, missing_ok=False): 1338 """ 1339 Remove this file or link. 1340 If the path is a directory, use rmdir() instead. 1341 """ 1342 try: 1343 os.unlink(self) 1344 except FileNotFoundError: 1345 if not missing_ok: 1346 raise 1347 1348 def rmdir(self): 1349 """ 1350 Remove this directory. The directory must be empty. 1351 """ 1352 os.rmdir(self) 1353 1354 def rename(self, target): 1355 """ 1356 Rename this path to the target path. 1357 1358 The target path may be absolute or relative. Relative paths are 1359 interpreted relative to the current working directory, *not* the 1360 directory of the Path object. 1361 1362 Returns the new Path instance pointing to the target path. 1363 """ 1364 os.rename(self, target) 1365 return self.with_segments(target) 1366 1367 def replace(self, target): 1368 """ 1369 Rename this path to the target path, overwriting if that path exists. 1370 1371 The target path may be absolute or relative. Relative paths are 1372 interpreted relative to the current working directory, *not* the 1373 directory of the Path object. 1374 1375 Returns the new Path instance pointing to the target path. 1376 """ 1377 os.replace(self, target) 1378 return self.with_segments(target) 1379 1380 def symlink_to(self, target, target_is_directory=False): 1381 """ 1382 Make this path a symlink pointing to the target path. 1383 Note the order of arguments (link, target) is the reverse of os.symlink. 1384 """ 1385 if not hasattr(os, "symlink"): 1386 raise NotImplementedError("os.symlink() not available on this system") 1387 os.symlink(target, self, target_is_directory) 1388 1389 def hardlink_to(self, target): 1390 """ 1391 Make this path a hard link pointing to the same file as *target*. 1392 1393 Note the order of arguments (self, target) is the reverse of os.link's. 1394 """ 1395 if not hasattr(os, "link"): 1396 raise NotImplementedError("os.link() not available on this system") 1397 os.link(target, self) 1398 1399 def expanduser(self): 1400 """ Return a new path with expanded ~ and ~user constructs 1401 (as returned by os.path.expanduser) 1402 """ 1403 if (not (self.drive or self.root) and 1404 self._tail and self._tail[0][:1] == '~'): 1405 homedir = self._flavour.expanduser(self._tail[0]) 1406 if homedir[:1] == "~": 1407 raise RuntimeError("Could not determine home directory.") 1408 drv, root, tail = self._parse_path(homedir) 1409 return self._from_parsed_parts(drv, root, tail + self._tail[1:]) 1410 1411 return self 1412 1413 1414class PosixPath(Path, PurePosixPath): 1415 """Path subclass for non-Windows systems. 1416 1417 On a POSIX system, instantiating a Path should return this object. 1418 """ 1419 __slots__ = () 1420 1421 if os.name == 'nt': 1422 def __new__(cls, *args, **kwargs): 1423 raise NotImplementedError( 1424 f"cannot instantiate {cls.__name__!r} on your system") 1425 1426class WindowsPath(Path, PureWindowsPath): 1427 """Path subclass for Windows systems. 1428 1429 On a Windows system, instantiating a Path should return this object. 1430 """ 1431 __slots__ = () 1432 1433 if os.name != 'nt': 1434 def __new__(cls, *args, **kwargs): 1435 raise NotImplementedError( 1436 f"cannot instantiate {cls.__name__!r} on your system")
293class PurePath(object): 294 """Base class for manipulating paths without I/O. 295 296 PurePath represents a filesystem path and offers operations which 297 don't imply any actual filesystem I/O. Depending on your system, 298 instantiating a PurePath will return either a PurePosixPath or a 299 PureWindowsPath object. You can also instantiate either of these classes 300 directly, regardless of your system. 301 """ 302 303 __slots__ = ( 304 # The `_raw_paths` slot stores unnormalized string paths. This is set 305 # in the `__init__()` method. 306 '_raw_paths', 307 308 # The `_drv`, `_root` and `_tail_cached` slots store parsed and 309 # normalized parts of the path. They are set when any of the `drive`, 310 # `root` or `_tail` properties are accessed for the first time. The 311 # three-part division corresponds to the result of 312 # `os.path.splitroot()`, except that the tail is further split on path 313 # separators (i.e. it is a list of strings), and that the root and 314 # tail are normalized. 315 '_drv', '_root', '_tail_cached', 316 317 # The `_str` slot stores the string representation of the path, 318 # computed from the drive, root and tail when `__str__()` is called 319 # for the first time. It's used to implement `_str_normcase` 320 '_str', 321 322 # The `_str_normcase_cached` slot stores the string path with 323 # normalized case. It is set when the `_str_normcase` property is 324 # accessed for the first time. It's used to implement `__eq__()` 325 # `__hash__()`, and `_parts_normcase` 326 '_str_normcase_cached', 327 328 # The `_parts_normcase_cached` slot stores the case-normalized 329 # string path after splitting on path separators. It's set when the 330 # `_parts_normcase` property is accessed for the first time. It's used 331 # to implement comparison methods like `__lt__()`. 332 '_parts_normcase_cached', 333 334 # The `_lines_cached` slot stores the string path with path separators 335 # and newlines swapped. This is used to implement `match()`. 336 '_lines_cached', 337 338 # The `_hash` slot stores the hash of the case-normalized string 339 # path. It's set when `__hash__()` is called for the first time. 340 '_hash', 341 ) 342 _flavour = os.path 343 344 def __new__(cls, *args, **kwargs): 345 """Construct a PurePath from one or several strings and or existing 346 PurePath objects. The strings and path objects are combined so as 347 to yield a canonicalized path, which is incorporated into the 348 new PurePath object. 349 """ 350 if cls is PurePath: 351 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath 352 return object.__new__(cls) 353 354 def __reduce__(self): 355 # Using the parts tuple helps share interned path parts 356 # when pickling related paths. 357 return (self.__class__, self.parts) 358 359 def __init__(self, *args): 360 paths = [] 361 for arg in args: 362 if isinstance(arg, PurePath): 363 if arg._flavour is ntpath and self._flavour is posixpath: 364 # GH-103631: Convert separators for backwards compatibility. 365 paths.extend(path.replace('\\', '/') for path in arg._raw_paths) 366 else: 367 paths.extend(arg._raw_paths) 368 else: 369 try: 370 path = os.fspath(arg) 371 except TypeError: 372 path = arg 373 if not isinstance(path, str): 374 raise TypeError( 375 "argument should be a str or an os.PathLike " 376 "object where __fspath__ returns a str, " 377 f"not {type(path).__name__!r}") 378 paths.append(path) 379 self._raw_paths = paths 380 381 def with_segments(self, *pathsegments): 382 """Construct a new path object from any number of path-like objects. 383 Subclasses may override this method to customize how new path objects 384 are created from methods like `iterdir()`. 385 """ 386 return type(self)(*pathsegments) 387 388 @classmethod 389 def _parse_path(cls, path): 390 if not path: 391 return '', '', [] 392 sep = cls._flavour.sep 393 altsep = cls._flavour.altsep 394 if altsep: 395 path = path.replace(altsep, sep) 396 drv, root, rel = cls._flavour.splitroot(path) 397 if not root and drv.startswith(sep) and not drv.endswith(sep): 398 drv_parts = drv.split(sep) 399 if len(drv_parts) == 4 and drv_parts[2] not in '?.': 400 # e.g. //server/share 401 root = sep 402 elif len(drv_parts) == 6: 403 # e.g. //?/unc/server/share 404 root = sep 405 parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.'] 406 return drv, root, parsed 407 408 def _load_parts(self): 409 paths = self._raw_paths 410 if len(paths) == 0: 411 path = '' 412 elif len(paths) == 1: 413 path = paths[0] 414 else: 415 path = self._flavour.join(*paths) 416 drv, root, tail = self._parse_path(path) 417 self._drv = drv 418 self._root = root 419 self._tail_cached = tail 420 421 def _from_parsed_parts(self, drv, root, tail): 422 path_str = self._format_parsed_parts(drv, root, tail) 423 path = self.with_segments(path_str) 424 path._str = path_str or '.' 425 path._drv = drv 426 path._root = root 427 path._tail_cached = tail 428 return path 429 430 @classmethod 431 def _format_parsed_parts(cls, drv, root, tail): 432 if drv or root: 433 return drv + root + cls._flavour.sep.join(tail) 434 elif tail and cls._flavour.splitdrive(tail[0])[0]: 435 tail = ['.'] + tail 436 return cls._flavour.sep.join(tail) 437 438 def __str__(self): 439 """Return the string representation of the path, suitable for 440 passing to system calls.""" 441 try: 442 return self._str 443 except AttributeError: 444 self._str = self._format_parsed_parts(self.drive, self.root, 445 self._tail) or '.' 446 return self._str 447 448 def __fspath__(self): 449 return str(self) 450 451 def as_posix(self): 452 """Return the string representation of the path with forward (/) 453 slashes.""" 454 f = self._flavour 455 return str(self).replace(f.sep, '/') 456 457 def __bytes__(self): 458 """Return the bytes representation of the path. This is only 459 recommended to use under Unix.""" 460 return os.fsencode(self) 461 462 def __repr__(self): 463 return "{}({!r})".format(self.__class__.__name__, self.as_posix()) 464 465 def as_uri(self): 466 """Return the path as a 'file' URI.""" 467 if not self.is_absolute(): 468 raise ValueError("relative path can't be expressed as a file URI") 469 470 drive = self.drive 471 if len(drive) == 2 and drive[1] == ':': 472 # It's a path on a local drive => 'file:///c:/a/b' 473 prefix = 'file:///' + drive 474 path = self.as_posix()[2:] 475 elif drive: 476 # It's a path on a network drive => 'file://host/share/a/b' 477 prefix = 'file:' 478 path = self.as_posix() 479 else: 480 # It's a posix path => 'file:///etc/hosts' 481 prefix = 'file://' 482 path = str(self) 483 return prefix + urlquote_from_bytes(os.fsencode(path)) 484 485 @property 486 def _str_normcase(self): 487 # String with normalized case, for hashing and equality checks 488 try: 489 return self._str_normcase_cached 490 except AttributeError: 491 if _is_case_sensitive(self._flavour): 492 self._str_normcase_cached = str(self) 493 else: 494 self._str_normcase_cached = str(self).lower() 495 return self._str_normcase_cached 496 497 @property 498 def _parts_normcase(self): 499 # Cached parts with normalized case, for comparisons. 500 try: 501 return self._parts_normcase_cached 502 except AttributeError: 503 self._parts_normcase_cached = self._str_normcase.split(self._flavour.sep) 504 return self._parts_normcase_cached 505 506 @property 507 def _lines(self): 508 # Path with separators and newlines swapped, for pattern matching. 509 try: 510 return self._lines_cached 511 except AttributeError: 512 path_str = str(self) 513 if path_str == '.': 514 self._lines_cached = '' 515 else: 516 trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] 517 self._lines_cached = path_str.translate(trans) 518 return self._lines_cached 519 520 def __eq__(self, other): 521 if not isinstance(other, PurePath): 522 return NotImplemented 523 return self._str_normcase == other._str_normcase and self._flavour is other._flavour 524 525 def __hash__(self): 526 try: 527 return self._hash 528 except AttributeError: 529 self._hash = hash(self._str_normcase) 530 return self._hash 531 532 def __lt__(self, other): 533 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 534 return NotImplemented 535 return self._parts_normcase < other._parts_normcase 536 537 def __le__(self, other): 538 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 539 return NotImplemented 540 return self._parts_normcase <= other._parts_normcase 541 542 def __gt__(self, other): 543 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 544 return NotImplemented 545 return self._parts_normcase > other._parts_normcase 546 547 def __ge__(self, other): 548 if not isinstance(other, PurePath) or self._flavour is not other._flavour: 549 return NotImplemented 550 return self._parts_normcase >= other._parts_normcase 551 552 @property 553 def drive(self): 554 """The drive prefix (letter or UNC path), if any.""" 555 try: 556 return self._drv 557 except AttributeError: 558 self._load_parts() 559 return self._drv 560 561 @property 562 def root(self): 563 """The root of the path, if any.""" 564 try: 565 return self._root 566 except AttributeError: 567 self._load_parts() 568 return self._root 569 570 @property 571 def _tail(self): 572 try: 573 return self._tail_cached 574 except AttributeError: 575 self._load_parts() 576 return self._tail_cached 577 578 @property 579 def anchor(self): 580 """The concatenation of the drive and root, or ''.""" 581 anchor = self.drive + self.root 582 return anchor 583 584 @property 585 def name(self): 586 """The final path component, if any.""" 587 tail = self._tail 588 if not tail: 589 return '' 590 return tail[-1] 591 592 @property 593 def suffix(self): 594 """ 595 The final component's last suffix, if any. 596 597 This includes the leading period. For example: '.txt' 598 """ 599 name = self.name 600 i = name.rfind('.') 601 if 0 < i < len(name) - 1: 602 return name[i:] 603 else: 604 return '' 605 606 @property 607 def suffixes(self): 608 """ 609 A list of the final component's suffixes, if any. 610 611 These include the leading periods. For example: ['.tar', '.gz'] 612 """ 613 name = self.name 614 if name.endswith('.'): 615 return [] 616 name = name.lstrip('.') 617 return ['.' + suffix for suffix in name.split('.')[1:]] 618 619 @property 620 def stem(self): 621 """The final path component, minus its last suffix.""" 622 name = self.name 623 i = name.rfind('.') 624 if 0 < i < len(name) - 1: 625 return name[:i] 626 else: 627 return name 628 629 def with_name(self, name): 630 """Return a new path with the file name changed.""" 631 if not self.name: 632 raise ValueError("%r has an empty name" % (self,)) 633 f = self._flavour 634 drv, root, tail = f.splitroot(name) 635 if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail): 636 raise ValueError("Invalid name %r" % (name)) 637 return self._from_parsed_parts(self.drive, self.root, 638 self._tail[:-1] + [name]) 639 640 def with_stem(self, stem): 641 """Return a new path with the stem changed.""" 642 return self.with_name(stem + self.suffix) 643 644 def with_suffix(self, suffix): 645 """Return a new path with the file suffix changed. If the path 646 has no suffix, add given suffix. If the given suffix is an empty 647 string, remove the suffix from the path. 648 """ 649 f = self._flavour 650 if f.sep in suffix or f.altsep and f.altsep in suffix: 651 raise ValueError("Invalid suffix %r" % (suffix,)) 652 if suffix and not suffix.startswith('.') or suffix == '.': 653 raise ValueError("Invalid suffix %r" % (suffix)) 654 name = self.name 655 if not name: 656 raise ValueError("%r has an empty name" % (self,)) 657 old_suffix = self.suffix 658 if not old_suffix: 659 name = name + suffix 660 else: 661 name = name[:-len(old_suffix)] + suffix 662 return self._from_parsed_parts(self.drive, self.root, 663 self._tail[:-1] + [name]) 664 665 def relative_to(self, other, /, *_deprecated, walk_up=False): 666 """Return the relative path to another path identified by the passed 667 arguments. If the operation is not possible (because this is not 668 related to the other path), raise ValueError. 669 670 The *walk_up* parameter controls whether `..` may be used to resolve 671 the path. 672 """ 673 if _deprecated: 674 msg = ("support for supplying more than one positional argument " 675 "to pathlib.PurePath.relative_to() is deprecated and " 676 "scheduled for removal in Python {remove}") 677 warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg, 678 remove=(3, 14)) 679 other = self.with_segments(other, *_deprecated) 680 for step, path in enumerate([other] + list(other.parents)): 681 if self.is_relative_to(path): 682 break 683 elif not walk_up: 684 raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") 685 elif path.name == '..': 686 raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") 687 else: 688 raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") 689 parts = ['..'] * step + self._tail[len(path._tail):] 690 return self.with_segments(*parts) 691 692 def is_relative_to(self, other, /, *_deprecated): 693 """Return True if the path is relative to another path or False. 694 """ 695 if _deprecated: 696 msg = ("support for supplying more than one argument to " 697 "pathlib.PurePath.is_relative_to() is deprecated and " 698 "scheduled for removal in Python {remove}") 699 warnings._deprecated("pathlib.PurePath.is_relative_to(*args)", 700 msg, remove=(3, 14)) 701 other = self.with_segments(other, *_deprecated) 702 return other == self or other in self.parents 703 704 @property 705 def parts(self): 706 """An object providing sequence-like access to the 707 components in the filesystem path.""" 708 if self.drive or self.root: 709 return (self.drive + self.root,) + tuple(self._tail) 710 else: 711 return tuple(self._tail) 712 713 def joinpath(self, *pathsegments): 714 """Combine this path with one or several arguments, and return a 715 new path representing either a subpath (if all arguments are relative 716 paths) or a totally different path (if one of the arguments is 717 anchored). 718 """ 719 return self.with_segments(self, *pathsegments) 720 721 def __truediv__(self, key): 722 try: 723 return self.joinpath(key) 724 except TypeError: 725 return NotImplemented 726 727 def __rtruediv__(self, key): 728 try: 729 return self.with_segments(key, self) 730 except TypeError: 731 return NotImplemented 732 733 @property 734 def parent(self): 735 """The logical parent of the path.""" 736 drv = self.drive 737 root = self.root 738 tail = self._tail 739 if not tail: 740 return self 741 return self._from_parsed_parts(drv, root, tail[:-1]) 742 743 @property 744 def parents(self): 745 """A sequence of this path's logical parents.""" 746 # The value of this property should not be cached on the path object, 747 # as doing so would introduce a reference cycle. 748 return _PathParents(self) 749 750 def is_absolute(self): 751 """True if the path is absolute (has both a root and, if applicable, 752 a drive).""" 753 if self._flavour is ntpath: 754 # ntpath.isabs() is defective - see GH-44626. 755 return bool(self.drive and self.root) 756 elif self._flavour is posixpath: 757 # Optimization: work with raw paths on POSIX. 758 for path in self._raw_paths: 759 if path.startswith('/'): 760 return True 761 return False 762 else: 763 return self._flavour.isabs(str(self)) 764 765 def is_reserved(self): 766 """Return True if the path contains one of the special names reserved 767 by the system, if any.""" 768 if self._flavour is posixpath or not self._tail: 769 return False 770 771 # NOTE: the rules for reserved names seem somewhat complicated 772 # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not 773 # exist). We err on the side of caution and return True for paths 774 # which are not considered reserved by Windows. 775 if self.drive.startswith('\\\\'): 776 # UNC paths are never reserved. 777 return False 778 name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ') 779 return name.upper() in _WIN_RESERVED_NAMES 780 781 def match(self, path_pattern, *, case_sensitive=None): 782 """ 783 Return True if this path matches the given pattern. 784 """ 785 if not isinstance(path_pattern, PurePath): 786 path_pattern = self.with_segments(path_pattern) 787 if case_sensitive is None: 788 case_sensitive = _is_case_sensitive(self._flavour) 789 pattern = _compile_pattern_lines(path_pattern._lines, case_sensitive) 790 if path_pattern.drive or path_pattern.root: 791 return pattern.match(self._lines) is not None 792 elif path_pattern._tail: 793 return pattern.search(self._lines) is not None 794 else: 795 raise ValueError("empty pattern")
Base class for manipulating paths without I/O.
PurePath represents a filesystem path and offers operations which don't imply any actual filesystem I/O. Depending on your system, instantiating a PurePath will return either a PurePosixPath or a PureWindowsPath object. You can also instantiate either of these classes directly, regardless of your system.
344 def __new__(cls, *args, **kwargs): 345 """Construct a PurePath from one or several strings and or existing 346 PurePath objects. The strings and path objects are combined so as 347 to yield a canonicalized path, which is incorporated into the 348 new PurePath object. 349 """ 350 if cls is PurePath: 351 cls = PureWindowsPath if os.name == 'nt' else PurePosixPath 352 return object.__new__(cls)
Construct a PurePath from one or several strings and or existing PurePath objects. The strings and path objects are combined so as to yield a canonicalized path, which is incorporated into the new PurePath object.
381 def with_segments(self, *pathsegments): 382 """Construct a new path object from any number of path-like objects. 383 Subclasses may override this method to customize how new path objects 384 are created from methods like `iterdir()`. 385 """ 386 return type(self)(*pathsegments)
Construct a new path object from any number of path-like objects.
Subclasses may override this method to customize how new path objects
are created from methods like iterdir()
.
451 def as_posix(self): 452 """Return the string representation of the path with forward (/) 453 slashes.""" 454 f = self._flavour 455 return str(self).replace(f.sep, '/')
Return the string representation of the path with forward (/) slashes.
465 def as_uri(self): 466 """Return the path as a 'file' URI.""" 467 if not self.is_absolute(): 468 raise ValueError("relative path can't be expressed as a file URI") 469 470 drive = self.drive 471 if len(drive) == 2 and drive[1] == ':': 472 # It's a path on a local drive => 'file:///c:/a/b' 473 prefix = 'file:///' + drive 474 path = self.as_posix()[2:] 475 elif drive: 476 # It's a path on a network drive => 'file://host/share/a/b' 477 prefix = 'file:' 478 path = self.as_posix() 479 else: 480 # It's a posix path => 'file:///etc/hosts' 481 prefix = 'file://' 482 path = str(self) 483 return prefix + urlquote_from_bytes(os.fsencode(path))
Return the path as a 'file' URI.
552 @property 553 def drive(self): 554 """The drive prefix (letter or UNC path), if any.""" 555 try: 556 return self._drv 557 except AttributeError: 558 self._load_parts() 559 return self._drv
The drive prefix (letter or UNC path), if any.
561 @property 562 def root(self): 563 """The root of the path, if any.""" 564 try: 565 return self._root 566 except AttributeError: 567 self._load_parts() 568 return self._root
The root of the path, if any.
578 @property 579 def anchor(self): 580 """The concatenation of the drive and root, or ''.""" 581 anchor = self.drive + self.root 582 return anchor
The concatenation of the drive and root, or ''.
584 @property 585 def name(self): 586 """The final path component, if any.""" 587 tail = self._tail 588 if not tail: 589 return '' 590 return tail[-1]
The final path component, if any.
592 @property 593 def suffix(self): 594 """ 595 The final component's last suffix, if any. 596 597 This includes the leading period. For example: '.txt' 598 """ 599 name = self.name 600 i = name.rfind('.') 601 if 0 < i < len(name) - 1: 602 return name[i:] 603 else: 604 return ''
The final component's last suffix, if any.
This includes the leading period. For example: '.txt'
606 @property 607 def suffixes(self): 608 """ 609 A list of the final component's suffixes, if any. 610 611 These include the leading periods. For example: ['.tar', '.gz'] 612 """ 613 name = self.name 614 if name.endswith('.'): 615 return [] 616 name = name.lstrip('.') 617 return ['.' + suffix for suffix in name.split('.')[1:]]
A list of the final component's suffixes, if any.
These include the leading periods. For example: ['.tar', '.gz']
619 @property 620 def stem(self): 621 """The final path component, minus its last suffix.""" 622 name = self.name 623 i = name.rfind('.') 624 if 0 < i < len(name) - 1: 625 return name[:i] 626 else: 627 return name
The final path component, minus its last suffix.
629 def with_name(self, name): 630 """Return a new path with the file name changed.""" 631 if not self.name: 632 raise ValueError("%r has an empty name" % (self,)) 633 f = self._flavour 634 drv, root, tail = f.splitroot(name) 635 if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail): 636 raise ValueError("Invalid name %r" % (name)) 637 return self._from_parsed_parts(self.drive, self.root, 638 self._tail[:-1] + [name])
Return a new path with the file name changed.
640 def with_stem(self, stem): 641 """Return a new path with the stem changed.""" 642 return self.with_name(stem + self.suffix)
Return a new path with the stem changed.
644 def with_suffix(self, suffix): 645 """Return a new path with the file suffix changed. If the path 646 has no suffix, add given suffix. If the given suffix is an empty 647 string, remove the suffix from the path. 648 """ 649 f = self._flavour 650 if f.sep in suffix or f.altsep and f.altsep in suffix: 651 raise ValueError("Invalid suffix %r" % (suffix,)) 652 if suffix and not suffix.startswith('.') or suffix == '.': 653 raise ValueError("Invalid suffix %r" % (suffix)) 654 name = self.name 655 if not name: 656 raise ValueError("%r has an empty name" % (self,)) 657 old_suffix = self.suffix 658 if not old_suffix: 659 name = name + suffix 660 else: 661 name = name[:-len(old_suffix)] + suffix 662 return self._from_parsed_parts(self.drive, self.root, 663 self._tail[:-1] + [name])
Return a new path with the file suffix changed. If the path has no suffix, add given suffix. If the given suffix is an empty string, remove the suffix from the path.
665 def relative_to(self, other, /, *_deprecated, walk_up=False): 666 """Return the relative path to another path identified by the passed 667 arguments. If the operation is not possible (because this is not 668 related to the other path), raise ValueError. 669 670 The *walk_up* parameter controls whether `..` may be used to resolve 671 the path. 672 """ 673 if _deprecated: 674 msg = ("support for supplying more than one positional argument " 675 "to pathlib.PurePath.relative_to() is deprecated and " 676 "scheduled for removal in Python {remove}") 677 warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg, 678 remove=(3, 14)) 679 other = self.with_segments(other, *_deprecated) 680 for step, path in enumerate([other] + list(other.parents)): 681 if self.is_relative_to(path): 682 break 683 elif not walk_up: 684 raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") 685 elif path.name == '..': 686 raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") 687 else: 688 raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") 689 parts = ['..'] * step + self._tail[len(path._tail):] 690 return self.with_segments(*parts)
Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError.
The walk_up parameter controls whether ..
may be used to resolve
the path.
692 def is_relative_to(self, other, /, *_deprecated): 693 """Return True if the path is relative to another path or False. 694 """ 695 if _deprecated: 696 msg = ("support for supplying more than one argument to " 697 "pathlib.PurePath.is_relative_to() is deprecated and " 698 "scheduled for removal in Python {remove}") 699 warnings._deprecated("pathlib.PurePath.is_relative_to(*args)", 700 msg, remove=(3, 14)) 701 other = self.with_segments(other, *_deprecated) 702 return other == self or other in self.parents
Return True if the path is relative to another path or False.
704 @property 705 def parts(self): 706 """An object providing sequence-like access to the 707 components in the filesystem path.""" 708 if self.drive or self.root: 709 return (self.drive + self.root,) + tuple(self._tail) 710 else: 711 return tuple(self._tail)
An object providing sequence-like access to the components in the filesystem path.
713 def joinpath(self, *pathsegments): 714 """Combine this path with one or several arguments, and return a 715 new path representing either a subpath (if all arguments are relative 716 paths) or a totally different path (if one of the arguments is 717 anchored). 718 """ 719 return self.with_segments(self, *pathsegments)
Combine this path with one or several arguments, and return a new path representing either a subpath (if all arguments are relative paths) or a totally different path (if one of the arguments is anchored).
733 @property 734 def parent(self): 735 """The logical parent of the path.""" 736 drv = self.drive 737 root = self.root 738 tail = self._tail 739 if not tail: 740 return self 741 return self._from_parsed_parts(drv, root, tail[:-1])
The logical parent of the path.
743 @property 744 def parents(self): 745 """A sequence of this path's logical parents.""" 746 # The value of this property should not be cached on the path object, 747 # as doing so would introduce a reference cycle. 748 return _PathParents(self)
A sequence of this path's logical parents.
750 def is_absolute(self): 751 """True if the path is absolute (has both a root and, if applicable, 752 a drive).""" 753 if self._flavour is ntpath: 754 # ntpath.isabs() is defective - see GH-44626. 755 return bool(self.drive and self.root) 756 elif self._flavour is posixpath: 757 # Optimization: work with raw paths on POSIX. 758 for path in self._raw_paths: 759 if path.startswith('/'): 760 return True 761 return False 762 else: 763 return self._flavour.isabs(str(self))
True if the path is absolute (has both a root and, if applicable, a drive).
765 def is_reserved(self): 766 """Return True if the path contains one of the special names reserved 767 by the system, if any.""" 768 if self._flavour is posixpath or not self._tail: 769 return False 770 771 # NOTE: the rules for reserved names seem somewhat complicated 772 # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not 773 # exist). We err on the side of caution and return True for paths 774 # which are not considered reserved by Windows. 775 if self.drive.startswith('\\\\'): 776 # UNC paths are never reserved. 777 return False 778 name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ') 779 return name.upper() in _WIN_RESERVED_NAMES
Return True if the path contains one of the special names reserved by the system, if any.
781 def match(self, path_pattern, *, case_sensitive=None): 782 """ 783 Return True if this path matches the given pattern. 784 """ 785 if not isinstance(path_pattern, PurePath): 786 path_pattern = self.with_segments(path_pattern) 787 if case_sensitive is None: 788 case_sensitive = _is_case_sensitive(self._flavour) 789 pattern = _compile_pattern_lines(path_pattern._lines, case_sensitive) 790 if path_pattern.drive or path_pattern.root: 791 return pattern.match(self._lines) is not None 792 elif path_pattern._tail: 793 return pattern.search(self._lines) is not None 794 else: 795 raise ValueError("empty pattern")
Return True if this path matches the given pattern.
803class PurePosixPath(PurePath): 804 """PurePath subclass for non-Windows systems. 805 806 On a POSIX system, instantiating a PurePath should return this object. 807 However, you can also instantiate it directly on any system. 808 """ 809 _flavour = posixpath 810 __slots__ = ()
PurePath subclass for non-Windows systems.
On a POSIX system, instantiating a PurePath should return this object. However, you can also instantiate it directly on any system.
813class PureWindowsPath(PurePath): 814 """PurePath subclass for Windows systems. 815 816 On a Windows system, instantiating a PurePath should return this object. 817 However, you can also instantiate it directly on any system. 818 """ 819 _flavour = ntpath 820 __slots__ = ()
PurePath subclass for Windows systems.
On a Windows system, instantiating a PurePath should return this object. However, you can also instantiate it directly on any system.
826class Path(PurePath): 827 """PurePath subclass that can make system calls. 828 829 Path represents a filesystem path but unlike PurePath, also offers 830 methods to do system calls on path objects. Depending on your system, 831 instantiating a Path will return either a PosixPath or a WindowsPath 832 object. You can also instantiate a PosixPath or WindowsPath directly, 833 but cannot instantiate a WindowsPath on a POSIX system or vice versa. 834 """ 835 __slots__ = () 836 837 def stat(self, *, follow_symlinks=True): 838 """ 839 Return the result of the stat() system call on this path, like 840 os.stat() does. 841 """ 842 return os.stat(self, follow_symlinks=follow_symlinks) 843 844 def lstat(self): 845 """ 846 Like stat(), except if the path points to a symlink, the symlink's 847 status information is returned, rather than its target's. 848 """ 849 return self.stat(follow_symlinks=False) 850 851 852 # Convenience functions for querying the stat results 853 854 def exists(self, *, follow_symlinks=True): 855 """ 856 Whether this path exists. 857 858 This method normally follows symlinks; to check whether a symlink exists, 859 add the argument follow_symlinks=False. 860 """ 861 try: 862 self.stat(follow_symlinks=follow_symlinks) 863 except OSError as e: 864 if not _ignore_error(e): 865 raise 866 return False 867 except ValueError: 868 # Non-encodable path 869 return False 870 return True 871 872 def is_dir(self): 873 """ 874 Whether this path is a directory. 875 """ 876 try: 877 return S_ISDIR(self.stat().st_mode) 878 except OSError as e: 879 if not _ignore_error(e): 880 raise 881 # Path doesn't exist or is a broken symlink 882 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 883 return False 884 except ValueError: 885 # Non-encodable path 886 return False 887 888 def is_file(self): 889 """ 890 Whether this path is a regular file (also True for symlinks pointing 891 to regular files). 892 """ 893 try: 894 return S_ISREG(self.stat().st_mode) 895 except OSError as e: 896 if not _ignore_error(e): 897 raise 898 # Path doesn't exist or is a broken symlink 899 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 900 return False 901 except ValueError: 902 # Non-encodable path 903 return False 904 905 def is_mount(self): 906 """ 907 Check if this path is a mount point 908 """ 909 return self._flavour.ismount(self) 910 911 def is_symlink(self): 912 """ 913 Whether this path is a symbolic link. 914 """ 915 try: 916 return S_ISLNK(self.lstat().st_mode) 917 except OSError as e: 918 if not _ignore_error(e): 919 raise 920 # Path doesn't exist 921 return False 922 except ValueError: 923 # Non-encodable path 924 return False 925 926 def is_junction(self): 927 """ 928 Whether this path is a junction. 929 """ 930 return self._flavour.isjunction(self) 931 932 def is_block_device(self): 933 """ 934 Whether this path is a block device. 935 """ 936 try: 937 return S_ISBLK(self.stat().st_mode) 938 except OSError as e: 939 if not _ignore_error(e): 940 raise 941 # Path doesn't exist or is a broken symlink 942 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 943 return False 944 except ValueError: 945 # Non-encodable path 946 return False 947 948 def is_char_device(self): 949 """ 950 Whether this path is a character device. 951 """ 952 try: 953 return S_ISCHR(self.stat().st_mode) 954 except OSError as e: 955 if not _ignore_error(e): 956 raise 957 # Path doesn't exist or is a broken symlink 958 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 959 return False 960 except ValueError: 961 # Non-encodable path 962 return False 963 964 def is_fifo(self): 965 """ 966 Whether this path is a FIFO. 967 """ 968 try: 969 return S_ISFIFO(self.stat().st_mode) 970 except OSError as e: 971 if not _ignore_error(e): 972 raise 973 # Path doesn't exist or is a broken symlink 974 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 975 return False 976 except ValueError: 977 # Non-encodable path 978 return False 979 980 def is_socket(self): 981 """ 982 Whether this path is a socket. 983 """ 984 try: 985 return S_ISSOCK(self.stat().st_mode) 986 except OSError as e: 987 if not _ignore_error(e): 988 raise 989 # Path doesn't exist or is a broken symlink 990 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 991 return False 992 except ValueError: 993 # Non-encodable path 994 return False 995 996 def samefile(self, other_path): 997 """Return whether other_path is the same or not as this file 998 (as returned by os.path.samefile()). 999 """ 1000 st = self.stat() 1001 try: 1002 other_st = other_path.stat() 1003 except AttributeError: 1004 other_st = self.with_segments(other_path).stat() 1005 return self._flavour.samestat(st, other_st) 1006 1007 def open(self, mode='r', buffering=-1, encoding=None, 1008 errors=None, newline=None): 1009 """ 1010 Open the file pointed by this path and return a file object, as 1011 the built-in open() function does. 1012 """ 1013 if "b" not in mode: 1014 encoding = io.text_encoding(encoding) 1015 return io.open(self, mode, buffering, encoding, errors, newline) 1016 1017 def read_bytes(self): 1018 """ 1019 Open the file in bytes mode, read it, and close the file. 1020 """ 1021 with self.open(mode='rb') as f: 1022 return f.read() 1023 1024 def read_text(self, encoding=None, errors=None): 1025 """ 1026 Open the file in text mode, read it, and close the file. 1027 """ 1028 encoding = io.text_encoding(encoding) 1029 with self.open(mode='r', encoding=encoding, errors=errors) as f: 1030 return f.read() 1031 1032 def write_bytes(self, data): 1033 """ 1034 Open the file in bytes mode, write to it, and close the file. 1035 """ 1036 # type-check for the buffer interface before truncating the file 1037 view = memoryview(data) 1038 with self.open(mode='wb') as f: 1039 return f.write(view) 1040 1041 def write_text(self, data, encoding=None, errors=None, newline=None): 1042 """ 1043 Open the file in text mode, write to it, and close the file. 1044 """ 1045 if not isinstance(data, str): 1046 raise TypeError('data must be str, not %s' % 1047 data.__class__.__name__) 1048 encoding = io.text_encoding(encoding) 1049 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: 1050 return f.write(data) 1051 1052 def iterdir(self): 1053 """Yield path objects of the directory contents. 1054 1055 The children are yielded in arbitrary order, and the 1056 special entries '.' and '..' are not included. 1057 """ 1058 for name in os.listdir(self): 1059 yield self._make_child_relpath(name) 1060 1061 def _scandir(self): 1062 # bpo-24132: a future version of pathlib will support subclassing of 1063 # pathlib.Path to customize how the filesystem is accessed. This 1064 # includes scandir(), which is used to implement glob(). 1065 return os.scandir(self) 1066 1067 def _make_child_relpath(self, name): 1068 path_str = str(self) 1069 tail = self._tail 1070 if tail: 1071 path_str = f'{path_str}{self._flavour.sep}{name}' 1072 elif path_str != '.': 1073 path_str = f'{path_str}{name}' 1074 else: 1075 path_str = name 1076 path = self.with_segments(path_str) 1077 path._str = path_str 1078 path._drv = self.drive 1079 path._root = self.root 1080 path._tail_cached = tail + [name] 1081 return path 1082 1083 def glob(self, pattern, *, case_sensitive=None): 1084 """Iterate over this subtree and yield all existing files (of any 1085 kind, including directories) matching the given relative pattern. 1086 """ 1087 sys.audit("pathlib.Path.glob", self, pattern) 1088 if not pattern: 1089 raise ValueError("Unacceptable pattern: {!r}".format(pattern)) 1090 drv, root, pattern_parts = self._parse_path(pattern) 1091 if drv or root: 1092 raise NotImplementedError("Non-relative patterns are unsupported") 1093 if pattern[-1] in (self._flavour.sep, self._flavour.altsep): 1094 pattern_parts.append('') 1095 selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive) 1096 for p in selector.select_from(self): 1097 yield p 1098 1099 def rglob(self, pattern, *, case_sensitive=None): 1100 """Recursively yield all existing files (of any kind, including 1101 directories) matching the given relative pattern, anywhere in 1102 this subtree. 1103 """ 1104 sys.audit("pathlib.Path.rglob", self, pattern) 1105 drv, root, pattern_parts = self._parse_path(pattern) 1106 if drv or root: 1107 raise NotImplementedError("Non-relative patterns are unsupported") 1108 if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep): 1109 pattern_parts.append('') 1110 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive) 1111 for p in selector.select_from(self): 1112 yield p 1113 1114 def walk(self, top_down=True, on_error=None, follow_symlinks=False): 1115 """Walk the directory tree from this directory, similar to os.walk().""" 1116 sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) 1117 paths = [self] 1118 1119 while paths: 1120 path = paths.pop() 1121 if isinstance(path, tuple): 1122 yield path 1123 continue 1124 1125 # We may not have read permission for self, in which case we can't 1126 # get a list of the files the directory contains. os.walk() 1127 # always suppressed the exception in that instance, rather than 1128 # blow up for a minor reason when (say) a thousand readable 1129 # directories are still left to visit. That logic is copied here. 1130 try: 1131 scandir_it = path._scandir() 1132 except OSError as error: 1133 if on_error is not None: 1134 on_error(error) 1135 continue 1136 1137 with scandir_it: 1138 dirnames = [] 1139 filenames = [] 1140 for entry in scandir_it: 1141 try: 1142 is_dir = entry.is_dir(follow_symlinks=follow_symlinks) 1143 except OSError: 1144 # Carried over from os.path.isdir(). 1145 is_dir = False 1146 1147 if is_dir: 1148 dirnames.append(entry.name) 1149 else: 1150 filenames.append(entry.name) 1151 1152 if top_down: 1153 yield path, dirnames, filenames 1154 else: 1155 paths.append((path, dirnames, filenames)) 1156 1157 paths += [path._make_child_relpath(d) for d in reversed(dirnames)] 1158 1159 def __init__(self, *args, **kwargs): 1160 if kwargs: 1161 msg = ("support for supplying keyword arguments to pathlib.PurePath " 1162 "is deprecated and scheduled for removal in Python {remove}") 1163 warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14)) 1164 super().__init__(*args) 1165 1166 def __new__(cls, *args, **kwargs): 1167 if cls is Path: 1168 cls = WindowsPath if os.name == 'nt' else PosixPath 1169 return object.__new__(cls) 1170 1171 def __enter__(self): 1172 # In previous versions of pathlib, __exit__() marked this path as 1173 # closed; subsequent attempts to perform I/O would raise an IOError. 1174 # This functionality was never documented, and had the effect of 1175 # making Path objects mutable, contrary to PEP 428. 1176 # In Python 3.9 __exit__() was made a no-op. 1177 # In Python 3.11 __enter__() began emitting DeprecationWarning. 1178 # In Python 3.13 __enter__() and __exit__() should be removed. 1179 warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " 1180 "for removal in Python 3.13; Path objects as a context " 1181 "manager is a no-op", 1182 DeprecationWarning, stacklevel=2) 1183 return self 1184 1185 def __exit__(self, t, v, tb): 1186 pass 1187 1188 # Public API 1189 1190 @classmethod 1191 def cwd(cls): 1192 """Return a new path pointing to the current working directory.""" 1193 # We call 'absolute()' rather than using 'os.getcwd()' directly to 1194 # enable users to replace the implementation of 'absolute()' in a 1195 # subclass and benefit from the new behaviour here. This works because 1196 # os.path.abspath('.') == os.getcwd(). 1197 return cls().absolute() 1198 1199 @classmethod 1200 def home(cls): 1201 """Return a new path pointing to the user's home directory (as 1202 returned by os.path.expanduser('~')). 1203 """ 1204 return cls("~").expanduser() 1205 1206 def absolute(self): 1207 """Return an absolute version of this path by prepending the current 1208 working directory. No normalization or symlink resolution is performed. 1209 1210 Use resolve() to get the canonical path to a file. 1211 """ 1212 if self.is_absolute(): 1213 return self 1214 elif self.drive: 1215 # There is a CWD on each drive-letter drive. 1216 cwd = self._flavour.abspath(self.drive) 1217 else: 1218 cwd = os.getcwd() 1219 # Fast path for "empty" paths, e.g. Path("."), Path("") or Path(). 1220 # We pass only one argument to with_segments() to avoid the cost 1221 # of joining, and we exploit the fact that getcwd() returns a 1222 # fully-normalized string by storing it in _str. This is used to 1223 # implement Path.cwd(). 1224 if not self.root and not self._tail: 1225 result = self.with_segments(cwd) 1226 result._str = cwd 1227 return result 1228 return self.with_segments(cwd, self) 1229 1230 def resolve(self, strict=False): 1231 """ 1232 Make the path absolute, resolving all symlinks on the way and also 1233 normalizing it. 1234 """ 1235 1236 def check_eloop(e): 1237 winerror = getattr(e, 'winerror', 0) 1238 if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME: 1239 raise RuntimeError("Symlink loop from %r" % e.filename) 1240 1241 try: 1242 s = self._flavour.realpath(self, strict=strict) 1243 except OSError as e: 1244 check_eloop(e) 1245 raise 1246 p = self.with_segments(s) 1247 1248 # In non-strict mode, realpath() doesn't raise on symlink loops. 1249 # Ensure we get an exception by calling stat() 1250 if not strict: 1251 try: 1252 p.stat() 1253 except OSError as e: 1254 check_eloop(e) 1255 return p 1256 1257 def owner(self): 1258 """ 1259 Return the login name of the file owner. 1260 """ 1261 try: 1262 import pwd 1263 return pwd.getpwuid(self.stat().st_uid).pw_name 1264 except ImportError: 1265 raise NotImplementedError("Path.owner() is unsupported on this system") 1266 1267 def group(self): 1268 """ 1269 Return the group name of the file gid. 1270 """ 1271 1272 try: 1273 import grp 1274 return grp.getgrgid(self.stat().st_gid).gr_name 1275 except ImportError: 1276 raise NotImplementedError("Path.group() is unsupported on this system") 1277 1278 def readlink(self): 1279 """ 1280 Return the path to which the symbolic link points. 1281 """ 1282 if not hasattr(os, "readlink"): 1283 raise NotImplementedError("os.readlink() not available on this system") 1284 return self.with_segments(os.readlink(self)) 1285 1286 def touch(self, mode=0o666, exist_ok=True): 1287 """ 1288 Create this file with the given access mode, if it doesn't exist. 1289 """ 1290 1291 if exist_ok: 1292 # First try to bump modification time 1293 # Implementation note: GNU touch uses the UTIME_NOW option of 1294 # the utimensat() / futimens() functions. 1295 try: 1296 os.utime(self, None) 1297 except OSError: 1298 # Avoid exception chaining 1299 pass 1300 else: 1301 return 1302 flags = os.O_CREAT | os.O_WRONLY 1303 if not exist_ok: 1304 flags |= os.O_EXCL 1305 fd = os.open(self, flags, mode) 1306 os.close(fd) 1307 1308 def mkdir(self, mode=0o777, parents=False, exist_ok=False): 1309 """ 1310 Create a new directory at this given path. 1311 """ 1312 try: 1313 os.mkdir(self, mode) 1314 except FileNotFoundError: 1315 if not parents or self.parent == self: 1316 raise 1317 self.parent.mkdir(parents=True, exist_ok=True) 1318 self.mkdir(mode, parents=False, exist_ok=exist_ok) 1319 except OSError: 1320 # Cannot rely on checking for EEXIST, since the operating system 1321 # could give priority to other errors like EACCES or EROFS 1322 if not exist_ok or not self.is_dir(): 1323 raise 1324 1325 def chmod(self, mode, *, follow_symlinks=True): 1326 """ 1327 Change the permissions of the path, like os.chmod(). 1328 """ 1329 os.chmod(self, mode, follow_symlinks=follow_symlinks) 1330 1331 def lchmod(self, mode): 1332 """ 1333 Like chmod(), except if the path points to a symlink, the symlink's 1334 permissions are changed, rather than its target's. 1335 """ 1336 self.chmod(mode, follow_symlinks=False) 1337 1338 def unlink(self, missing_ok=False): 1339 """ 1340 Remove this file or link. 1341 If the path is a directory, use rmdir() instead. 1342 """ 1343 try: 1344 os.unlink(self) 1345 except FileNotFoundError: 1346 if not missing_ok: 1347 raise 1348 1349 def rmdir(self): 1350 """ 1351 Remove this directory. The directory must be empty. 1352 """ 1353 os.rmdir(self) 1354 1355 def rename(self, target): 1356 """ 1357 Rename this path to the target path. 1358 1359 The target path may be absolute or relative. Relative paths are 1360 interpreted relative to the current working directory, *not* the 1361 directory of the Path object. 1362 1363 Returns the new Path instance pointing to the target path. 1364 """ 1365 os.rename(self, target) 1366 return self.with_segments(target) 1367 1368 def replace(self, target): 1369 """ 1370 Rename this path to the target path, overwriting if that path exists. 1371 1372 The target path may be absolute or relative. Relative paths are 1373 interpreted relative to the current working directory, *not* the 1374 directory of the Path object. 1375 1376 Returns the new Path instance pointing to the target path. 1377 """ 1378 os.replace(self, target) 1379 return self.with_segments(target) 1380 1381 def symlink_to(self, target, target_is_directory=False): 1382 """ 1383 Make this path a symlink pointing to the target path. 1384 Note the order of arguments (link, target) is the reverse of os.symlink. 1385 """ 1386 if not hasattr(os, "symlink"): 1387 raise NotImplementedError("os.symlink() not available on this system") 1388 os.symlink(target, self, target_is_directory) 1389 1390 def hardlink_to(self, target): 1391 """ 1392 Make this path a hard link pointing to the same file as *target*. 1393 1394 Note the order of arguments (self, target) is the reverse of os.link's. 1395 """ 1396 if not hasattr(os, "link"): 1397 raise NotImplementedError("os.link() not available on this system") 1398 os.link(target, self) 1399 1400 def expanduser(self): 1401 """ Return a new path with expanded ~ and ~user constructs 1402 (as returned by os.path.expanduser) 1403 """ 1404 if (not (self.drive or self.root) and 1405 self._tail and self._tail[0][:1] == '~'): 1406 homedir = self._flavour.expanduser(self._tail[0]) 1407 if homedir[:1] == "~": 1408 raise RuntimeError("Could not determine home directory.") 1409 drv, root, tail = self._parse_path(homedir) 1410 return self._from_parsed_parts(drv, root, tail + self._tail[1:]) 1411 1412 return self
PurePath subclass that can make system calls.
Path represents a filesystem path but unlike PurePath, also offers methods to do system calls on path objects. Depending on your system, instantiating a Path will return either a PosixPath or a WindowsPath object. You can also instantiate a PosixPath or WindowsPath directly, but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1159 def __init__(self, *args, **kwargs): 1160 if kwargs: 1161 msg = ("support for supplying keyword arguments to pathlib.PurePath " 1162 "is deprecated and scheduled for removal in Python {remove}") 1163 warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14)) 1164 super().__init__(*args)
837 def stat(self, *, follow_symlinks=True): 838 """ 839 Return the result of the stat() system call on this path, like 840 os.stat() does. 841 """ 842 return os.stat(self, follow_symlinks=follow_symlinks)
Return the result of the stat() system call on this path, like os.stat() does.
844 def lstat(self): 845 """ 846 Like stat(), except if the path points to a symlink, the symlink's 847 status information is returned, rather than its target's. 848 """ 849 return self.stat(follow_symlinks=False)
Like stat(), except if the path points to a symlink, the symlink's status information is returned, rather than its target's.
854 def exists(self, *, follow_symlinks=True): 855 """ 856 Whether this path exists. 857 858 This method normally follows symlinks; to check whether a symlink exists, 859 add the argument follow_symlinks=False. 860 """ 861 try: 862 self.stat(follow_symlinks=follow_symlinks) 863 except OSError as e: 864 if not _ignore_error(e): 865 raise 866 return False 867 except ValueError: 868 # Non-encodable path 869 return False 870 return True
Whether this path exists.
This method normally follows symlinks; to check whether a symlink exists, add the argument follow_symlinks=False.
872 def is_dir(self): 873 """ 874 Whether this path is a directory. 875 """ 876 try: 877 return S_ISDIR(self.stat().st_mode) 878 except OSError as e: 879 if not _ignore_error(e): 880 raise 881 # Path doesn't exist or is a broken symlink 882 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 883 return False 884 except ValueError: 885 # Non-encodable path 886 return False
Whether this path is a directory.
888 def is_file(self): 889 """ 890 Whether this path is a regular file (also True for symlinks pointing 891 to regular files). 892 """ 893 try: 894 return S_ISREG(self.stat().st_mode) 895 except OSError as e: 896 if not _ignore_error(e): 897 raise 898 # Path doesn't exist or is a broken symlink 899 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 900 return False 901 except ValueError: 902 # Non-encodable path 903 return False
Whether this path is a regular file (also True for symlinks pointing to regular files).
905 def is_mount(self): 906 """ 907 Check if this path is a mount point 908 """ 909 return self._flavour.ismount(self)
Check if this path is a mount point
911 def is_symlink(self): 912 """ 913 Whether this path is a symbolic link. 914 """ 915 try: 916 return S_ISLNK(self.lstat().st_mode) 917 except OSError as e: 918 if not _ignore_error(e): 919 raise 920 # Path doesn't exist 921 return False 922 except ValueError: 923 # Non-encodable path 924 return False
Whether this path is a symbolic link.
926 def is_junction(self): 927 """ 928 Whether this path is a junction. 929 """ 930 return self._flavour.isjunction(self)
Whether this path is a junction.
932 def is_block_device(self): 933 """ 934 Whether this path is a block device. 935 """ 936 try: 937 return S_ISBLK(self.stat().st_mode) 938 except OSError as e: 939 if not _ignore_error(e): 940 raise 941 # Path doesn't exist or is a broken symlink 942 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 943 return False 944 except ValueError: 945 # Non-encodable path 946 return False
Whether this path is a block device.
948 def is_char_device(self): 949 """ 950 Whether this path is a character device. 951 """ 952 try: 953 return S_ISCHR(self.stat().st_mode) 954 except OSError as e: 955 if not _ignore_error(e): 956 raise 957 # Path doesn't exist or is a broken symlink 958 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 959 return False 960 except ValueError: 961 # Non-encodable path 962 return False
Whether this path is a character device.
964 def is_fifo(self): 965 """ 966 Whether this path is a FIFO. 967 """ 968 try: 969 return S_ISFIFO(self.stat().st_mode) 970 except OSError as e: 971 if not _ignore_error(e): 972 raise 973 # Path doesn't exist or is a broken symlink 974 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 975 return False 976 except ValueError: 977 # Non-encodable path 978 return False
Whether this path is a FIFO.
980 def is_socket(self): 981 """ 982 Whether this path is a socket. 983 """ 984 try: 985 return S_ISSOCK(self.stat().st_mode) 986 except OSError as e: 987 if not _ignore_error(e): 988 raise 989 # Path doesn't exist or is a broken symlink 990 # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) 991 return False 992 except ValueError: 993 # Non-encodable path 994 return False
Whether this path is a socket.
996 def samefile(self, other_path): 997 """Return whether other_path is the same or not as this file 998 (as returned by os.path.samefile()). 999 """ 1000 st = self.stat() 1001 try: 1002 other_st = other_path.stat() 1003 except AttributeError: 1004 other_st = self.with_segments(other_path).stat() 1005 return self._flavour.samestat(st, other_st)
Return whether other_path is the same or not as this file (as returned by os.path.samefile()).
1007 def open(self, mode='r', buffering=-1, encoding=None, 1008 errors=None, newline=None): 1009 """ 1010 Open the file pointed by this path and return a file object, as 1011 the built-in open() function does. 1012 """ 1013 if "b" not in mode: 1014 encoding = io.text_encoding(encoding) 1015 return io.open(self, mode, buffering, encoding, errors, newline)
Open the file pointed by this path and return a file object, as the built-in open() function does.
1017 def read_bytes(self): 1018 """ 1019 Open the file in bytes mode, read it, and close the file. 1020 """ 1021 with self.open(mode='rb') as f: 1022 return f.read()
Open the file in bytes mode, read it, and close the file.
1024 def read_text(self, encoding=None, errors=None): 1025 """ 1026 Open the file in text mode, read it, and close the file. 1027 """ 1028 encoding = io.text_encoding(encoding) 1029 with self.open(mode='r', encoding=encoding, errors=errors) as f: 1030 return f.read()
Open the file in text mode, read it, and close the file.
1032 def write_bytes(self, data): 1033 """ 1034 Open the file in bytes mode, write to it, and close the file. 1035 """ 1036 # type-check for the buffer interface before truncating the file 1037 view = memoryview(data) 1038 with self.open(mode='wb') as f: 1039 return f.write(view)
Open the file in bytes mode, write to it, and close the file.
1041 def write_text(self, data, encoding=None, errors=None, newline=None): 1042 """ 1043 Open the file in text mode, write to it, and close the file. 1044 """ 1045 if not isinstance(data, str): 1046 raise TypeError('data must be str, not %s' % 1047 data.__class__.__name__) 1048 encoding = io.text_encoding(encoding) 1049 with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: 1050 return f.write(data)
Open the file in text mode, write to it, and close the file.
1052 def iterdir(self): 1053 """Yield path objects of the directory contents. 1054 1055 The children are yielded in arbitrary order, and the 1056 special entries '.' and '..' are not included. 1057 """ 1058 for name in os.listdir(self): 1059 yield self._make_child_relpath(name)
Yield path objects of the directory contents.
The children are yielded in arbitrary order, and the special entries '.' and '..' are not included.
1083 def glob(self, pattern, *, case_sensitive=None): 1084 """Iterate over this subtree and yield all existing files (of any 1085 kind, including directories) matching the given relative pattern. 1086 """ 1087 sys.audit("pathlib.Path.glob", self, pattern) 1088 if not pattern: 1089 raise ValueError("Unacceptable pattern: {!r}".format(pattern)) 1090 drv, root, pattern_parts = self._parse_path(pattern) 1091 if drv or root: 1092 raise NotImplementedError("Non-relative patterns are unsupported") 1093 if pattern[-1] in (self._flavour.sep, self._flavour.altsep): 1094 pattern_parts.append('') 1095 selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive) 1096 for p in selector.select_from(self): 1097 yield p
Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.
1099 def rglob(self, pattern, *, case_sensitive=None): 1100 """Recursively yield all existing files (of any kind, including 1101 directories) matching the given relative pattern, anywhere in 1102 this subtree. 1103 """ 1104 sys.audit("pathlib.Path.rglob", self, pattern) 1105 drv, root, pattern_parts = self._parse_path(pattern) 1106 if drv or root: 1107 raise NotImplementedError("Non-relative patterns are unsupported") 1108 if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep): 1109 pattern_parts.append('') 1110 selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive) 1111 for p in selector.select_from(self): 1112 yield p
Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.
1114 def walk(self, top_down=True, on_error=None, follow_symlinks=False): 1115 """Walk the directory tree from this directory, similar to os.walk().""" 1116 sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) 1117 paths = [self] 1118 1119 while paths: 1120 path = paths.pop() 1121 if isinstance(path, tuple): 1122 yield path 1123 continue 1124 1125 # We may not have read permission for self, in which case we can't 1126 # get a list of the files the directory contains. os.walk() 1127 # always suppressed the exception in that instance, rather than 1128 # blow up for a minor reason when (say) a thousand readable 1129 # directories are still left to visit. That logic is copied here. 1130 try: 1131 scandir_it = path._scandir() 1132 except OSError as error: 1133 if on_error is not None: 1134 on_error(error) 1135 continue 1136 1137 with scandir_it: 1138 dirnames = [] 1139 filenames = [] 1140 for entry in scandir_it: 1141 try: 1142 is_dir = entry.is_dir(follow_symlinks=follow_symlinks) 1143 except OSError: 1144 # Carried over from os.path.isdir(). 1145 is_dir = False 1146 1147 if is_dir: 1148 dirnames.append(entry.name) 1149 else: 1150 filenames.append(entry.name) 1151 1152 if top_down: 1153 yield path, dirnames, filenames 1154 else: 1155 paths.append((path, dirnames, filenames)) 1156 1157 paths += [path._make_child_relpath(d) for d in reversed(dirnames)]
Walk the directory tree from this directory, similar to os.walk().
1190 @classmethod 1191 def cwd(cls): 1192 """Return a new path pointing to the current working directory.""" 1193 # We call 'absolute()' rather than using 'os.getcwd()' directly to 1194 # enable users to replace the implementation of 'absolute()' in a 1195 # subclass and benefit from the new behaviour here. This works because 1196 # os.path.abspath('.') == os.getcwd(). 1197 return cls().absolute()
Return a new path pointing to the current working directory.
1199 @classmethod 1200 def home(cls): 1201 """Return a new path pointing to the user's home directory (as 1202 returned by os.path.expanduser('~')). 1203 """ 1204 return cls("~").expanduser()
Return a new path pointing to the user's home directory (as returned by os.path.expanduser('~')).
1206 def absolute(self): 1207 """Return an absolute version of this path by prepending the current 1208 working directory. No normalization or symlink resolution is performed. 1209 1210 Use resolve() to get the canonical path to a file. 1211 """ 1212 if self.is_absolute(): 1213 return self 1214 elif self.drive: 1215 # There is a CWD on each drive-letter drive. 1216 cwd = self._flavour.abspath(self.drive) 1217 else: 1218 cwd = os.getcwd() 1219 # Fast path for "empty" paths, e.g. Path("."), Path("") or Path(). 1220 # We pass only one argument to with_segments() to avoid the cost 1221 # of joining, and we exploit the fact that getcwd() returns a 1222 # fully-normalized string by storing it in _str. This is used to 1223 # implement Path.cwd(). 1224 if not self.root and not self._tail: 1225 result = self.with_segments(cwd) 1226 result._str = cwd 1227 return result 1228 return self.with_segments(cwd, self)
Return an absolute version of this path by prepending the current working directory. No normalization or symlink resolution is performed.
Use resolve() to get the canonical path to a file.
1230 def resolve(self, strict=False): 1231 """ 1232 Make the path absolute, resolving all symlinks on the way and also 1233 normalizing it. 1234 """ 1235 1236 def check_eloop(e): 1237 winerror = getattr(e, 'winerror', 0) 1238 if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME: 1239 raise RuntimeError("Symlink loop from %r" % e.filename) 1240 1241 try: 1242 s = self._flavour.realpath(self, strict=strict) 1243 except OSError as e: 1244 check_eloop(e) 1245 raise 1246 p = self.with_segments(s) 1247 1248 # In non-strict mode, realpath() doesn't raise on symlink loops. 1249 # Ensure we get an exception by calling stat() 1250 if not strict: 1251 try: 1252 p.stat() 1253 except OSError as e: 1254 check_eloop(e) 1255 return p
Make the path absolute, resolving all symlinks on the way and also normalizing it.
1257 def owner(self): 1258 """ 1259 Return the login name of the file owner. 1260 """ 1261 try: 1262 import pwd 1263 return pwd.getpwuid(self.stat().st_uid).pw_name 1264 except ImportError: 1265 raise NotImplementedError("Path.owner() is unsupported on this system")
Return the login name of the file owner.
1267 def group(self): 1268 """ 1269 Return the group name of the file gid. 1270 """ 1271 1272 try: 1273 import grp 1274 return grp.getgrgid(self.stat().st_gid).gr_name 1275 except ImportError: 1276 raise NotImplementedError("Path.group() is unsupported on this system")
Return the group name of the file gid.
1278 def readlink(self): 1279 """ 1280 Return the path to which the symbolic link points. 1281 """ 1282 if not hasattr(os, "readlink"): 1283 raise NotImplementedError("os.readlink() not available on this system") 1284 return self.with_segments(os.readlink(self))
Return the path to which the symbolic link points.
1286 def touch(self, mode=0o666, exist_ok=True): 1287 """ 1288 Create this file with the given access mode, if it doesn't exist. 1289 """ 1290 1291 if exist_ok: 1292 # First try to bump modification time 1293 # Implementation note: GNU touch uses the UTIME_NOW option of 1294 # the utimensat() / futimens() functions. 1295 try: 1296 os.utime(self, None) 1297 except OSError: 1298 # Avoid exception chaining 1299 pass 1300 else: 1301 return 1302 flags = os.O_CREAT | os.O_WRONLY 1303 if not exist_ok: 1304 flags |= os.O_EXCL 1305 fd = os.open(self, flags, mode) 1306 os.close(fd)
Create this file with the given access mode, if it doesn't exist.
1308 def mkdir(self, mode=0o777, parents=False, exist_ok=False): 1309 """ 1310 Create a new directory at this given path. 1311 """ 1312 try: 1313 os.mkdir(self, mode) 1314 except FileNotFoundError: 1315 if not parents or self.parent == self: 1316 raise 1317 self.parent.mkdir(parents=True, exist_ok=True) 1318 self.mkdir(mode, parents=False, exist_ok=exist_ok) 1319 except OSError: 1320 # Cannot rely on checking for EEXIST, since the operating system 1321 # could give priority to other errors like EACCES or EROFS 1322 if not exist_ok or not self.is_dir(): 1323 raise
Create a new directory at this given path.
1325 def chmod(self, mode, *, follow_symlinks=True): 1326 """ 1327 Change the permissions of the path, like os.chmod(). 1328 """ 1329 os.chmod(self, mode, follow_symlinks=follow_symlinks)
Change the permissions of the path, like os.chmod().
1331 def lchmod(self, mode): 1332 """ 1333 Like chmod(), except if the path points to a symlink, the symlink's 1334 permissions are changed, rather than its target's. 1335 """ 1336 self.chmod(mode, follow_symlinks=False)
Like chmod(), except if the path points to a symlink, the symlink's permissions are changed, rather than its target's.
1338 def unlink(self, missing_ok=False): 1339 """ 1340 Remove this file or link. 1341 If the path is a directory, use rmdir() instead. 1342 """ 1343 try: 1344 os.unlink(self) 1345 except FileNotFoundError: 1346 if not missing_ok: 1347 raise
Remove this file or link. If the path is a directory, use rmdir() instead.
1349 def rmdir(self): 1350 """ 1351 Remove this directory. The directory must be empty. 1352 """ 1353 os.rmdir(self)
Remove this directory. The directory must be empty.
1355 def rename(self, target): 1356 """ 1357 Rename this path to the target path. 1358 1359 The target path may be absolute or relative. Relative paths are 1360 interpreted relative to the current working directory, *not* the 1361 directory of the Path object. 1362 1363 Returns the new Path instance pointing to the target path. 1364 """ 1365 os.rename(self, target) 1366 return self.with_segments(target)
Rename this path to the target path.
The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.
Returns the new Path instance pointing to the target path.
1368 def replace(self, target): 1369 """ 1370 Rename this path to the target path, overwriting if that path exists. 1371 1372 The target path may be absolute or relative. Relative paths are 1373 interpreted relative to the current working directory, *not* the 1374 directory of the Path object. 1375 1376 Returns the new Path instance pointing to the target path. 1377 """ 1378 os.replace(self, target) 1379 return self.with_segments(target)
Rename this path to the target path, overwriting if that path exists.
The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.
Returns the new Path instance pointing to the target path.
1381 def symlink_to(self, target, target_is_directory=False): 1382 """ 1383 Make this path a symlink pointing to the target path. 1384 Note the order of arguments (link, target) is the reverse of os.symlink. 1385 """ 1386 if not hasattr(os, "symlink"): 1387 raise NotImplementedError("os.symlink() not available on this system") 1388 os.symlink(target, self, target_is_directory)
Make this path a symlink pointing to the target path. Note the order of arguments (link, target) is the reverse of os.symlink.
1390 def hardlink_to(self, target): 1391 """ 1392 Make this path a hard link pointing to the same file as *target*. 1393 1394 Note the order of arguments (self, target) is the reverse of os.link's. 1395 """ 1396 if not hasattr(os, "link"): 1397 raise NotImplementedError("os.link() not available on this system") 1398 os.link(target, self)
Make this path a hard link pointing to the same file as target.
Note the order of arguments (self, target) is the reverse of os.link's.
1400 def expanduser(self): 1401 """ Return a new path with expanded ~ and ~user constructs 1402 (as returned by os.path.expanduser) 1403 """ 1404 if (not (self.drive or self.root) and 1405 self._tail and self._tail[0][:1] == '~'): 1406 homedir = self._flavour.expanduser(self._tail[0]) 1407 if homedir[:1] == "~": 1408 raise RuntimeError("Could not determine home directory.") 1409 drv, root, tail = self._parse_path(homedir) 1410 return self._from_parsed_parts(drv, root, tail + self._tail[1:]) 1411 1412 return self
Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser)
1415class PosixPath(Path, PurePosixPath): 1416 """Path subclass for non-Windows systems. 1417 1418 On a POSIX system, instantiating a Path should return this object. 1419 """ 1420 __slots__ = () 1421 1422 if os.name == 'nt': 1423 def __new__(cls, *args, **kwargs): 1424 raise NotImplementedError( 1425 f"cannot instantiate {cls.__name__!r} on your system")
Path subclass for non-Windows systems.
On a POSIX system, instantiating a Path should return this object.
Inherited Members
- Path
- Path
- stat
- lstat
- exists
- is_dir
- is_file
- is_mount
- is_symlink
- is_junction
- is_block_device
- is_char_device
- is_fifo
- is_socket
- samefile
- open
- read_bytes
- read_text
- write_bytes
- write_text
- iterdir
- glob
- rglob
- walk
- cwd
- home
- absolute
- resolve
- owner
- group
- readlink
- touch
- mkdir
- chmod
- lchmod
- unlink
- rmdir
- rename
- replace
- symlink_to
- hardlink_to
- expanduser
1427class WindowsPath(Path, PureWindowsPath): 1428 """Path subclass for Windows systems. 1429 1430 On a Windows system, instantiating a Path should return this object. 1431 """ 1432 __slots__ = () 1433 1434 if os.name != 'nt': 1435 def __new__(cls, *args, **kwargs): 1436 raise NotImplementedError( 1437 f"cannot instantiate {cls.__name__!r} on your system")
Path subclass for Windows systems.
On a Windows system, instantiating a Path should return this object.
Inherited Members
- Path
- Path
- stat
- lstat
- exists
- is_dir
- is_file
- is_mount
- is_symlink
- is_junction
- is_block_device
- is_char_device
- is_fifo
- is_socket
- samefile
- open
- read_bytes
- read_text
- write_bytes
- write_text
- iterdir
- glob
- rglob
- walk
- cwd
- home
- absolute
- resolve
- owner
- group
- readlink
- touch
- mkdir
- chmod
- lchmod
- unlink
- rmdir
- rename
- replace
- symlink_to
- hardlink_to
- expanduser