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 not self._flavour:
 363                    # GH-103631: Convert separators for backwards compatibility.
 364                    paths.append(arg.as_posix())
 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        if not name or f.sep in name or (f.altsep and f.altsep in name) or name == '.':
 634            raise ValueError("Invalid name %r" % (name))
 635        return self._from_parsed_parts(self.drive, self.root,
 636                                       self._tail[:-1] + [name])
 637
 638    def with_stem(self, stem):
 639        """Return a new path with the stem changed."""
 640        return self.with_name(stem + self.suffix)
 641
 642    def with_suffix(self, suffix):
 643        """Return a new path with the file suffix changed.  If the path
 644        has no suffix, add given suffix.  If the given suffix is an empty
 645        string, remove the suffix from the path.
 646        """
 647        f = self._flavour
 648        if f.sep in suffix or f.altsep and f.altsep in suffix:
 649            raise ValueError("Invalid suffix %r" % (suffix,))
 650        if suffix and not suffix.startswith('.') or suffix == '.':
 651            raise ValueError("Invalid suffix %r" % (suffix))
 652        name = self.name
 653        if not name:
 654            raise ValueError("%r has an empty name" % (self,))
 655        old_suffix = self.suffix
 656        if not old_suffix:
 657            name = name + suffix
 658        else:
 659            name = name[:-len(old_suffix)] + suffix
 660        return self._from_parsed_parts(self.drive, self.root,
 661                                       self._tail[:-1] + [name])
 662
 663    def relative_to(self, other, /, *_deprecated, walk_up=False):
 664        """Return the relative path to another path identified by the passed
 665        arguments.  If the operation is not possible (because this is not
 666        related to the other path), raise ValueError.
 667
 668        The *walk_up* parameter controls whether `..` may be used to resolve
 669        the path.
 670        """
 671        if _deprecated:
 672            msg = ("support for supplying more than one positional argument "
 673                   "to pathlib.PurePath.relative_to() is deprecated and "
 674                   "scheduled for removal in Python {remove}")
 675            warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg,
 676                                 remove=(3, 14))
 677        other = self.with_segments(other, *_deprecated)
 678        for step, path in enumerate([other] + list(other.parents)):
 679            if self.is_relative_to(path):
 680                break
 681            elif not walk_up:
 682                raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
 683            elif path.name == '..':
 684                raise ValueError(f"'..' segment in {str(other)!r} cannot be walked")
 685        else:
 686            raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors")
 687        parts = ['..'] * step + self._tail[len(path._tail):]
 688        return self.with_segments(*parts)
 689
 690    def is_relative_to(self, other, /, *_deprecated):
 691        """Return True if the path is relative to another path or False.
 692        """
 693        if _deprecated:
 694            msg = ("support for supplying more than one argument to "
 695                   "pathlib.PurePath.is_relative_to() is deprecated and "
 696                   "scheduled for removal in Python {remove}")
 697            warnings._deprecated("pathlib.PurePath.is_relative_to(*args)",
 698                                 msg, remove=(3, 14))
 699        other = self.with_segments(other, *_deprecated)
 700        return other == self or other in self.parents
 701
 702    @property
 703    def parts(self):
 704        """An object providing sequence-like access to the
 705        components in the filesystem path."""
 706        if self.drive or self.root:
 707            return (self.drive + self.root,) + tuple(self._tail)
 708        else:
 709            return tuple(self._tail)
 710
 711    def joinpath(self, *pathsegments):
 712        """Combine this path with one or several arguments, and return a
 713        new path representing either a subpath (if all arguments are relative
 714        paths) or a totally different path (if one of the arguments is
 715        anchored).
 716        """
 717        return self.with_segments(self, *pathsegments)
 718
 719    def __truediv__(self, key):
 720        try:
 721            return self.joinpath(key)
 722        except TypeError:
 723            return NotImplemented
 724
 725    def __rtruediv__(self, key):
 726        try:
 727            return self.with_segments(key, self)
 728        except TypeError:
 729            return NotImplemented
 730
 731    @property
 732    def parent(self):
 733        """The logical parent of the path."""
 734        drv = self.drive
 735        root = self.root
 736        tail = self._tail
 737        if not tail:
 738            return self
 739        return self._from_parsed_parts(drv, root, tail[:-1])
 740
 741    @property
 742    def parents(self):
 743        """A sequence of this path's logical parents."""
 744        # The value of this property should not be cached on the path object,
 745        # as doing so would introduce a reference cycle.
 746        return _PathParents(self)
 747
 748    def is_absolute(self):
 749        """True if the path is absolute (has both a root and, if applicable,
 750        a drive)."""
 751        if self._flavour is ntpath:
 752            # ntpath.isabs() is defective - see GH-44626.
 753            return bool(self.drive and self.root)
 754        elif self._flavour is posixpath:
 755            # Optimization: work with raw paths on POSIX.
 756            for path in self._raw_paths:
 757                if path.startswith('/'):
 758                    return True
 759            return False
 760        else:
 761            return self._flavour.isabs(str(self))
 762
 763    def is_reserved(self):
 764        """Return True if the path contains one of the special names reserved
 765        by the system, if any."""
 766        if self._flavour is posixpath or not self._tail:
 767            return False
 768
 769        # NOTE: the rules for reserved names seem somewhat complicated
 770        # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
 771        # exist). We err on the side of caution and return True for paths
 772        # which are not considered reserved by Windows.
 773        if self.drive.startswith('\\\\'):
 774            # UNC paths are never reserved.
 775            return False
 776        name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ')
 777        return name.upper() in _WIN_RESERVED_NAMES
 778
 779    def match(self, path_pattern, *, case_sensitive=None):
 780        """
 781        Return True if this path matches the given pattern.
 782        """
 783        if not isinstance(path_pattern, PurePath):
 784            path_pattern = self.with_segments(path_pattern)
 785        if case_sensitive is None:
 786            case_sensitive = _is_case_sensitive(self._flavour)
 787        pattern = _compile_pattern_lines(path_pattern._lines, case_sensitive)
 788        if path_pattern.drive or path_pattern.root:
 789            return pattern.match(self._lines) is not None
 790        elif path_pattern._tail:
 791            return pattern.search(self._lines) is not None
 792        else:
 793            raise ValueError("empty pattern")
 794
 795
 796# Can't subclass os.PathLike from PurePath and keep the constructor
 797# optimizations in PurePath.__slots__.
 798os.PathLike.register(PurePath)
 799
 800
 801class PurePosixPath(PurePath):
 802    """PurePath subclass for non-Windows systems.
 803
 804    On a POSIX system, instantiating a PurePath should return this object.
 805    However, you can also instantiate it directly on any system.
 806    """
 807    _flavour = posixpath
 808    __slots__ = ()
 809
 810
 811class PureWindowsPath(PurePath):
 812    """PurePath subclass for Windows systems.
 813
 814    On a Windows system, instantiating a PurePath should return this object.
 815    However, you can also instantiate it directly on any system.
 816    """
 817    _flavour = ntpath
 818    __slots__ = ()
 819
 820
 821# Filesystem-accessing classes
 822
 823
 824class Path(PurePath):
 825    """PurePath subclass that can make system calls.
 826
 827    Path represents a filesystem path but unlike PurePath, also offers
 828    methods to do system calls on path objects. Depending on your system,
 829    instantiating a Path will return either a PosixPath or a WindowsPath
 830    object. You can also instantiate a PosixPath or WindowsPath directly,
 831    but cannot instantiate a WindowsPath on a POSIX system or vice versa.
 832    """
 833    __slots__ = ()
 834
 835    def stat(self, *, follow_symlinks=True):
 836        """
 837        Return the result of the stat() system call on this path, like
 838        os.stat() does.
 839        """
 840        return os.stat(self, follow_symlinks=follow_symlinks)
 841
 842    def lstat(self):
 843        """
 844        Like stat(), except if the path points to a symlink, the symlink's
 845        status information is returned, rather than its target's.
 846        """
 847        return self.stat(follow_symlinks=False)
 848
 849
 850    # Convenience functions for querying the stat results
 851
 852    def exists(self, *, follow_symlinks=True):
 853        """
 854        Whether this path exists.
 855
 856        This method normally follows symlinks; to check whether a symlink exists,
 857        add the argument follow_symlinks=False.
 858        """
 859        try:
 860            self.stat(follow_symlinks=follow_symlinks)
 861        except OSError as e:
 862            if not _ignore_error(e):
 863                raise
 864            return False
 865        except ValueError:
 866            # Non-encodable path
 867            return False
 868        return True
 869
 870    def is_dir(self):
 871        """
 872        Whether this path is a directory.
 873        """
 874        try:
 875            return S_ISDIR(self.stat().st_mode)
 876        except OSError as e:
 877            if not _ignore_error(e):
 878                raise
 879            # Path doesn't exist or is a broken symlink
 880            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 881            return False
 882        except ValueError:
 883            # Non-encodable path
 884            return False
 885
 886    def is_file(self):
 887        """
 888        Whether this path is a regular file (also True for symlinks pointing
 889        to regular files).
 890        """
 891        try:
 892            return S_ISREG(self.stat().st_mode)
 893        except OSError as e:
 894            if not _ignore_error(e):
 895                raise
 896            # Path doesn't exist or is a broken symlink
 897            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 898            return False
 899        except ValueError:
 900            # Non-encodable path
 901            return False
 902
 903    def is_mount(self):
 904        """
 905        Check if this path is a mount point
 906        """
 907        return self._flavour.ismount(self)
 908
 909    def is_symlink(self):
 910        """
 911        Whether this path is a symbolic link.
 912        """
 913        try:
 914            return S_ISLNK(self.lstat().st_mode)
 915        except OSError as e:
 916            if not _ignore_error(e):
 917                raise
 918            # Path doesn't exist
 919            return False
 920        except ValueError:
 921            # Non-encodable path
 922            return False
 923
 924    def is_junction(self):
 925        """
 926        Whether this path is a junction.
 927        """
 928        return self._flavour.isjunction(self)
 929
 930    def is_block_device(self):
 931        """
 932        Whether this path is a block device.
 933        """
 934        try:
 935            return S_ISBLK(self.stat().st_mode)
 936        except OSError as e:
 937            if not _ignore_error(e):
 938                raise
 939            # Path doesn't exist or is a broken symlink
 940            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 941            return False
 942        except ValueError:
 943            # Non-encodable path
 944            return False
 945
 946    def is_char_device(self):
 947        """
 948        Whether this path is a character device.
 949        """
 950        try:
 951            return S_ISCHR(self.stat().st_mode)
 952        except OSError as e:
 953            if not _ignore_error(e):
 954                raise
 955            # Path doesn't exist or is a broken symlink
 956            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 957            return False
 958        except ValueError:
 959            # Non-encodable path
 960            return False
 961
 962    def is_fifo(self):
 963        """
 964        Whether this path is a FIFO.
 965        """
 966        try:
 967            return S_ISFIFO(self.stat().st_mode)
 968        except OSError as e:
 969            if not _ignore_error(e):
 970                raise
 971            # Path doesn't exist or is a broken symlink
 972            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 973            return False
 974        except ValueError:
 975            # Non-encodable path
 976            return False
 977
 978    def is_socket(self):
 979        """
 980        Whether this path is a socket.
 981        """
 982        try:
 983            return S_ISSOCK(self.stat().st_mode)
 984        except OSError as e:
 985            if not _ignore_error(e):
 986                raise
 987            # Path doesn't exist or is a broken symlink
 988            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 989            return False
 990        except ValueError:
 991            # Non-encodable path
 992            return False
 993
 994    def samefile(self, other_path):
 995        """Return whether other_path is the same or not as this file
 996        (as returned by os.path.samefile()).
 997        """
 998        st = self.stat()
 999        try:
1000            other_st = other_path.stat()
1001        except AttributeError:
1002            other_st = self.with_segments(other_path).stat()
1003        return self._flavour.samestat(st, other_st)
1004
1005    def open(self, mode='r', buffering=-1, encoding=None,
1006             errors=None, newline=None):
1007        """
1008        Open the file pointed to by this path and return a file object, as
1009        the built-in open() function does.
1010        """
1011        if "b" not in mode:
1012            encoding = io.text_encoding(encoding)
1013        return io.open(self, mode, buffering, encoding, errors, newline)
1014
1015    def read_bytes(self):
1016        """
1017        Open the file in bytes mode, read it, and close the file.
1018        """
1019        with self.open(mode='rb') as f:
1020            return f.read()
1021
1022    def read_text(self, encoding=None, errors=None):
1023        """
1024        Open the file in text mode, read it, and close the file.
1025        """
1026        encoding = io.text_encoding(encoding)
1027        with self.open(mode='r', encoding=encoding, errors=errors) as f:
1028            return f.read()
1029
1030    def write_bytes(self, data):
1031        """
1032        Open the file in bytes mode, write to it, and close the file.
1033        """
1034        # type-check for the buffer interface before truncating the file
1035        view = memoryview(data)
1036        with self.open(mode='wb') as f:
1037            return f.write(view)
1038
1039    def write_text(self, data, encoding=None, errors=None, newline=None):
1040        """
1041        Open the file in text mode, write to it, and close the file.
1042        """
1043        if not isinstance(data, str):
1044            raise TypeError('data must be str, not %s' %
1045                            data.__class__.__name__)
1046        encoding = io.text_encoding(encoding)
1047        with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
1048            return f.write(data)
1049
1050    def iterdir(self):
1051        """Yield path objects of the directory contents.
1052
1053        The children are yielded in arbitrary order, and the
1054        special entries '.' and '..' are not included.
1055        """
1056        for name in os.listdir(self):
1057            yield self._make_child_relpath(name)
1058
1059    def _scandir(self):
1060        # bpo-24132: a future version of pathlib will support subclassing of
1061        # pathlib.Path to customize how the filesystem is accessed. This
1062        # includes scandir(), which is used to implement glob().
1063        return os.scandir(self)
1064
1065    def _make_child_relpath(self, name):
1066        path_str = str(self)
1067        tail = self._tail
1068        if tail:
1069            path_str = f'{path_str}{self._flavour.sep}{name}'
1070        elif path_str != '.':
1071            path_str = f'{path_str}{name}'
1072        else:
1073            path_str = name
1074        path = self.with_segments(path_str)
1075        path._str = path_str
1076        path._drv = self.drive
1077        path._root = self.root
1078        path._tail_cached = tail + [name]
1079        return path
1080
1081    def glob(self, pattern, *, case_sensitive=None):
1082        """Iterate over this subtree and yield all existing files (of any
1083        kind, including directories) matching the given relative pattern.
1084        """
1085        sys.audit("pathlib.Path.glob", self, pattern)
1086        if not pattern:
1087            raise ValueError("Unacceptable pattern: {!r}".format(pattern))
1088        drv, root, pattern_parts = self._parse_path(pattern)
1089        if drv or root:
1090            raise NotImplementedError("Non-relative patterns are unsupported")
1091        if pattern[-1] in (self._flavour.sep, self._flavour.altsep):
1092            pattern_parts.append('')
1093        selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive)
1094        for p in selector.select_from(self):
1095            yield p
1096
1097    def rglob(self, pattern, *, case_sensitive=None):
1098        """Recursively yield all existing files (of any kind, including
1099        directories) matching the given relative pattern, anywhere in
1100        this subtree.
1101        """
1102        sys.audit("pathlib.Path.rglob", self, pattern)
1103        drv, root, pattern_parts = self._parse_path(pattern)
1104        if drv or root:
1105            raise NotImplementedError("Non-relative patterns are unsupported")
1106        if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep):
1107            pattern_parts.append('')
1108        selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive)
1109        for p in selector.select_from(self):
1110            yield p
1111
1112    def walk(self, top_down=True, on_error=None, follow_symlinks=False):
1113        """Walk the directory tree from this directory, similar to os.walk()."""
1114        sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
1115        paths = [self]
1116
1117        while paths:
1118            path = paths.pop()
1119            if isinstance(path, tuple):
1120                yield path
1121                continue
1122
1123            # We may not have read permission for self, in which case we can't
1124            # get a list of the files the directory contains. os.walk()
1125            # always suppressed the exception in that instance, rather than
1126            # blow up for a minor reason when (say) a thousand readable
1127            # directories are still left to visit. That logic is copied here.
1128            try:
1129                scandir_it = path._scandir()
1130            except OSError as error:
1131                if on_error is not None:
1132                    on_error(error)
1133                continue
1134
1135            with scandir_it:
1136                dirnames = []
1137                filenames = []
1138                for entry in scandir_it:
1139                    try:
1140                        is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
1141                    except OSError:
1142                        # Carried over from os.path.isdir().
1143                        is_dir = False
1144
1145                    if is_dir:
1146                        dirnames.append(entry.name)
1147                    else:
1148                        filenames.append(entry.name)
1149
1150            if top_down:
1151                yield path, dirnames, filenames
1152            else:
1153                paths.append((path, dirnames, filenames))
1154
1155            paths += [path._make_child_relpath(d) for d in reversed(dirnames)]
1156
1157    def __init__(self, *args, **kwargs):
1158        if kwargs:
1159            msg = ("support for supplying keyword arguments to pathlib.PurePath "
1160                   "is deprecated and scheduled for removal in Python {remove}")
1161            warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
1162        super().__init__(*args)
1163
1164    def __new__(cls, *args, **kwargs):
1165        if cls is Path:
1166            cls = WindowsPath if os.name == 'nt' else PosixPath
1167        return object.__new__(cls)
1168
1169    def __enter__(self):
1170        # In previous versions of pathlib, __exit__() marked this path as
1171        # closed; subsequent attempts to perform I/O would raise an IOError.
1172        # This functionality was never documented, and had the effect of
1173        # making Path objects mutable, contrary to PEP 428.
1174        # In Python 3.9 __exit__() was made a no-op.
1175        # In Python 3.11 __enter__() began emitting DeprecationWarning.
1176        # In Python 3.13 __enter__() and __exit__() should be removed.
1177        warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled "
1178                      "for removal in Python 3.13; Path objects as a context "
1179                      "manager is a no-op",
1180                      DeprecationWarning, stacklevel=2)
1181        return self
1182
1183    def __exit__(self, t, v, tb):
1184        pass
1185
1186    # Public API
1187
1188    @classmethod
1189    def cwd(cls):
1190        """Return a new path pointing to the current working directory."""
1191        # We call 'absolute()' rather than using 'os.getcwd()' directly to
1192        # enable users to replace the implementation of 'absolute()' in a
1193        # subclass and benefit from the new behaviour here. This works because
1194        # os.path.abspath('.') == os.getcwd().
1195        return cls().absolute()
1196
1197    @classmethod
1198    def home(cls):
1199        """Return a new path pointing to the user's home directory (as
1200        returned by os.path.expanduser('~')).
1201        """
1202        return cls("~").expanduser()
1203
1204    def absolute(self):
1205        """Return an absolute version of this path by prepending the current
1206        working directory. No normalization or symlink resolution is performed.
1207
1208        Use resolve() to get the canonical path to a file.
1209        """
1210        if self.is_absolute():
1211            return self
1212        elif self.drive:
1213            # There is a CWD on each drive-letter drive.
1214            cwd = self._flavour.abspath(self.drive)
1215        else:
1216            cwd = os.getcwd()
1217            # Fast path for "empty" paths, e.g. Path("."), Path("") or Path().
1218            # We pass only one argument to with_segments() to avoid the cost
1219            # of joining, and we exploit the fact that getcwd() returns a
1220            # fully-normalized string by storing it in _str. This is used to
1221            # implement Path.cwd().
1222            if not self.root and not self._tail:
1223                result = self.with_segments(cwd)
1224                result._str = cwd
1225                return result
1226        return self.with_segments(cwd, self)
1227
1228    def resolve(self, strict=False):
1229        """
1230        Make the path absolute, resolving all symlinks on the way and also
1231        normalizing it.
1232        """
1233
1234        def check_eloop(e):
1235            winerror = getattr(e, 'winerror', 0)
1236            if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME:
1237                raise RuntimeError("Symlink loop from %r" % e.filename)
1238
1239        try:
1240            s = self._flavour.realpath(self, strict=strict)
1241        except OSError as e:
1242            check_eloop(e)
1243            raise
1244        p = self.with_segments(s)
1245
1246        # In non-strict mode, realpath() doesn't raise on symlink loops.
1247        # Ensure we get an exception by calling stat()
1248        if not strict:
1249            try:
1250                p.stat()
1251            except OSError as e:
1252                check_eloop(e)
1253        return p
1254
1255    def owner(self):
1256        """
1257        Return the login name of the file owner.
1258        """
1259        try:
1260            import pwd
1261            return pwd.getpwuid(self.stat().st_uid).pw_name
1262        except ImportError:
1263            raise NotImplementedError("Path.owner() is unsupported on this system")
1264
1265    def group(self):
1266        """
1267        Return the group name of the file gid.
1268        """
1269
1270        try:
1271            import grp
1272            return grp.getgrgid(self.stat().st_gid).gr_name
1273        except ImportError:
1274            raise NotImplementedError("Path.group() is unsupported on this system")
1275
1276    def readlink(self):
1277        """
1278        Return the path to which the symbolic link points.
1279        """
1280        if not hasattr(os, "readlink"):
1281            raise NotImplementedError("os.readlink() not available on this system")
1282        return self.with_segments(os.readlink(self))
1283
1284    def touch(self, mode=0o666, exist_ok=True):
1285        """
1286        Create this file with the given access mode, if it doesn't exist.
1287        """
1288
1289        if exist_ok:
1290            # First try to bump modification time
1291            # Implementation note: GNU touch uses the UTIME_NOW option of
1292            # the utimensat() / futimens() functions.
1293            try:
1294                os.utime(self, None)
1295            except OSError:
1296                # Avoid exception chaining
1297                pass
1298            else:
1299                return
1300        flags = os.O_CREAT | os.O_WRONLY
1301        if not exist_ok:
1302            flags |= os.O_EXCL
1303        fd = os.open(self, flags, mode)
1304        os.close(fd)
1305
1306    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
1307        """
1308        Create a new directory at this given path.
1309        """
1310        try:
1311            os.mkdir(self, mode)
1312        except FileNotFoundError:
1313            if not parents or self.parent == self:
1314                raise
1315            self.parent.mkdir(parents=True, exist_ok=True)
1316            self.mkdir(mode, parents=False, exist_ok=exist_ok)
1317        except OSError:
1318            # Cannot rely on checking for EEXIST, since the operating system
1319            # could give priority to other errors like EACCES or EROFS
1320            if not exist_ok or not self.is_dir():
1321                raise
1322
1323    def chmod(self, mode, *, follow_symlinks=True):
1324        """
1325        Change the permissions of the path, like os.chmod().
1326        """
1327        os.chmod(self, mode, follow_symlinks=follow_symlinks)
1328
1329    def lchmod(self, mode):
1330        """
1331        Like chmod(), except if the path points to a symlink, the symlink's
1332        permissions are changed, rather than its target's.
1333        """
1334        self.chmod(mode, follow_symlinks=False)
1335
1336    def unlink(self, missing_ok=False):
1337        """
1338        Remove this file or link.
1339        If the path is a directory, use rmdir() instead.
1340        """
1341        try:
1342            os.unlink(self)
1343        except FileNotFoundError:
1344            if not missing_ok:
1345                raise
1346
1347    def rmdir(self):
1348        """
1349        Remove this directory.  The directory must be empty.
1350        """
1351        os.rmdir(self)
1352
1353    def rename(self, target):
1354        """
1355        Rename this path to the target path.
1356
1357        The target path may be absolute or relative. Relative paths are
1358        interpreted relative to the current working directory, *not* the
1359        directory of the Path object.
1360
1361        Returns the new Path instance pointing to the target path.
1362        """
1363        os.rename(self, target)
1364        return self.with_segments(target)
1365
1366    def replace(self, target):
1367        """
1368        Rename this path to the target path, overwriting if that path exists.
1369
1370        The target path may be absolute or relative. Relative paths are
1371        interpreted relative to the current working directory, *not* the
1372        directory of the Path object.
1373
1374        Returns the new Path instance pointing to the target path.
1375        """
1376        os.replace(self, target)
1377        return self.with_segments(target)
1378
1379    def symlink_to(self, target, target_is_directory=False):
1380        """
1381        Make this path a symlink pointing to the target path.
1382        Note the order of arguments (link, target) is the reverse of os.symlink.
1383        """
1384        if not hasattr(os, "symlink"):
1385            raise NotImplementedError("os.symlink() not available on this system")
1386        os.symlink(target, self, target_is_directory)
1387
1388    def hardlink_to(self, target):
1389        """
1390        Make this path a hard link pointing to the same file as *target*.
1391
1392        Note the order of arguments (self, target) is the reverse of os.link's.
1393        """
1394        if not hasattr(os, "link"):
1395            raise NotImplementedError("os.link() not available on this system")
1396        os.link(target, self)
1397
1398    def expanduser(self):
1399        """ Return a new path with expanded ~ and ~user constructs
1400        (as returned by os.path.expanduser)
1401        """
1402        if (not (self.drive or self.root) and
1403            self._tail and self._tail[0][:1] == '~'):
1404            homedir = self._flavour.expanduser(self._tail[0])
1405            if homedir[:1] == "~":
1406                raise RuntimeError("Could not determine home directory.")
1407            drv, root, tail = self._parse_path(homedir)
1408            return self._from_parsed_parts(drv, root, tail + self._tail[1:])
1409
1410        return self
1411
1412
1413class PosixPath(Path, PurePosixPath):
1414    """Path subclass for non-Windows systems.
1415
1416    On a POSIX system, instantiating a Path should return this object.
1417    """
1418    __slots__ = ()
1419
1420    if os.name == 'nt':
1421        def __new__(cls, *args, **kwargs):
1422            raise NotImplementedError(
1423                f"cannot instantiate {cls.__name__!r} on your system")
1424
1425class WindowsPath(Path, PureWindowsPath):
1426    """Path subclass for Windows systems.
1427
1428    On a Windows system, instantiating a Path should return this object.
1429    """
1430    __slots__ = ()
1431
1432    if os.name != 'nt':
1433        def __new__(cls, *args, **kwargs):
1434            raise NotImplementedError(
1435                f"cannot instantiate {cls.__name__!r} on your system")
class PurePath:
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 not self._flavour:
364                    # GH-103631: Convert separators for backwards compatibility.
365                    paths.append(arg.as_posix())
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        if not name or f.sep in name or (f.altsep and f.altsep in name) or name == '.':
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")

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.

PurePath(*args, **kwargs)
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.

def with_segments(self, *pathsegments):
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().

def as_posix(self):
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.

def as_uri(self):
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.

drive
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.

root
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.

anchor
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 ''.

name
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.

suffix
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'

suffixes
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']

stem
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.

def with_name(self, name):
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        if not name or f.sep in name or (f.altsep and f.altsep in name) or name == '.':
635            raise ValueError("Invalid name %r" % (name))
636        return self._from_parsed_parts(self.drive, self.root,
637                                       self._tail[:-1] + [name])

Return a new path with the file name changed.

def with_stem(self, stem):
639    def with_stem(self, stem):
640        """Return a new path with the stem changed."""
641        return self.with_name(stem + self.suffix)

Return a new path with the stem changed.

def with_suffix(self, suffix):
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])

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.

def relative_to(self, other, /, *_deprecated, walk_up=False):
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)

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.

def is_relative_to(self, other, /, *_deprecated):
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

Return True if the path is relative to another path or False.

parts
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)

An object providing sequence-like access to the components in the filesystem path.

def joinpath(self, *pathsegments):
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)

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).

parent
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])

The logical parent of the path.

parents
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)

A sequence of this path's logical parents.

def is_absolute(self):
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))

True if the path is absolute (has both a root and, if applicable, a drive).

def is_reserved(self):
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

Return True if the path contains one of the special names reserved by the system, if any.

def match(self, path_pattern, *, case_sensitive=None):
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")

Return True if this path matches the given pattern.

class PurePosixPath(PurePath):
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__ = ()

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.

class PureWindowsPath(PurePath):
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__ = ()

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.

class Path(PurePath):
 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 to 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

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.

Path(*args, **kwargs)
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)
def stat(self, *, follow_symlinks=True):
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)

Return the result of the stat() system call on this path, like os.stat() does.

def lstat(self):
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)

Like stat(), except if the path points to a symlink, the symlink's status information is returned, rather than its target's.

def exists(self, *, follow_symlinks=True):
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

Whether this path exists.

This method normally follows symlinks; to check whether a symlink exists, add the argument follow_symlinks=False.

def is_dir(self):
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

Whether this path is a directory.

def is_file(self):
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

Whether this path is a regular file (also True for symlinks pointing to regular files).

def is_mount(self):
904    def is_mount(self):
905        """
906        Check if this path is a mount point
907        """
908        return self._flavour.ismount(self)

Check if this path is a mount point

def is_junction(self):
925    def is_junction(self):
926        """
927        Whether this path is a junction.
928        """
929        return self._flavour.isjunction(self)

Whether this path is a junction.

def is_block_device(self):
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

Whether this path is a block device.

def is_char_device(self):
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

Whether this path is a character device.

def is_fifo(self):
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

Whether this path is a FIFO.

def is_socket(self):
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

Whether this path is a socket.

def samefile(self, other_path):
 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)

Return whether other_path is the same or not as this file (as returned by os.path.samefile()).

def open( self, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
1006    def open(self, mode='r', buffering=-1, encoding=None,
1007             errors=None, newline=None):
1008        """
1009        Open the file pointed to 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)

Open the file pointed to by this path and return a file object, as the built-in open() function does.

def read_bytes(self):
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()

Open the file in bytes mode, read it, and close the file.

def read_text(self, encoding=None, errors=None):
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()

Open the file in text mode, read it, and close the file.

def write_bytes(self, data):
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)

Open the file in bytes mode, write to it, and close the file.

def write_text(self, data, encoding=None, errors=None, newline=None):
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)

Open the file in text mode, write to it, and close the file.

def iterdir(self):
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)

Yield path objects of the directory contents.

The children are yielded in arbitrary order, and the special entries '.' and '..' are not included.

def glob(self, pattern, *, case_sensitive=None):
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

Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.

def rglob(self, pattern, *, case_sensitive=None):
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

Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.

def walk(self, top_down=True, on_error=None, follow_symlinks=False):
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)]

Walk the directory tree from this directory, similar to os.walk().

@classmethod
def cwd(cls):
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()

Return a new path pointing to the current working directory.

@classmethod
def home(cls):
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()

Return a new path pointing to the user's home directory (as returned by os.path.expanduser('~')).

def absolute(self):
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)

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.

def resolve(self, strict=False):
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

Make the path absolute, resolving all symlinks on the way and also normalizing it.

def owner(self):
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")

Return the login name of the file owner.

def group(self):
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")

Return the group name of the file gid.

def touch(self, mode=438, exist_ok=True):
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)

Create this file with the given access mode, if it doesn't exist.

def mkdir(self, mode=511, parents=False, exist_ok=False):
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

Create a new directory at this given path.

def chmod(self, mode, *, follow_symlinks=True):
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)

Change the permissions of the path, like os.chmod().

def lchmod(self, mode):
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)

Like chmod(), except if the path points to a symlink, the symlink's permissions are changed, rather than its target's.

def rmdir(self):
1348    def rmdir(self):
1349        """
1350        Remove this directory.  The directory must be empty.
1351        """
1352        os.rmdir(self)

Remove this directory. The directory must be empty.

def rename(self, target):
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)

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.

def replace(self, target):
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)

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.

def expanduser(self):
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

Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser)

class PosixPath(Path, PurePosixPath):
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")

Path subclass for non-Windows systems.

On a POSIX system, instantiating a Path should return this object.

class WindowsPath(Path, PureWindowsPath):
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")

Path subclass for Windows systems.

On a Windows system, instantiating a Path should return this object.