pathlib

Object-oriented filesystem paths.

This module provides classes to represent abstract paths and concrete paths with operations that have semantics appropriate for different operating systems.

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

Base class for manipulating paths without I/O.

PurePath represents a filesystem path and offers operations which don't imply any actual filesystem I/O. Depending on your system, instantiating a PurePath will return either a PurePosixPath or a PureWindowsPath object. You can also instantiate either of these classes directly, regardless of your system.

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

Return a new path with the file name changed.

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

Return a new path with the stem changed.

def with_suffix(self, suffix):
644    def with_suffix(self, suffix):
645        """Return a new path with the file suffix changed.  If the path
646        has no suffix, add given suffix.  If the given suffix is an empty
647        string, remove the suffix from the path.
648        """
649        f = self._flavour
650        if f.sep in suffix or f.altsep and f.altsep in suffix:
651            raise ValueError("Invalid suffix %r" % (suffix,))
652        if suffix and not suffix.startswith('.') or suffix == '.':
653            raise ValueError("Invalid suffix %r" % (suffix))
654        name = self.name
655        if not name:
656            raise ValueError("%r has an empty name" % (self,))
657        old_suffix = self.suffix
658        if not old_suffix:
659            name = name + suffix
660        else:
661            name = name[:-len(old_suffix)] + suffix
662        return self._from_parsed_parts(self.drive, self.root,
663                                       self._tail[:-1] + [name])

Return a new path with the file suffix changed. If the path has no suffix, add given suffix. If the given suffix is an empty string, remove the suffix from the path.

def relative_to(self, other, /, *_deprecated, walk_up=False):
665    def relative_to(self, other, /, *_deprecated, walk_up=False):
666        """Return the relative path to another path identified by the passed
667        arguments.  If the operation is not possible (because this is not
668        related to the other path), raise ValueError.
669
670        The *walk_up* parameter controls whether `..` may be used to resolve
671        the path.
672        """
673        if _deprecated:
674            msg = ("support for supplying more than one positional argument "
675                   "to pathlib.PurePath.relative_to() is deprecated and "
676                   "scheduled for removal in Python {remove}")
677            warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg,
678                                 remove=(3, 14))
679        other = self.with_segments(other, *_deprecated)
680        for step, path in enumerate([other] + list(other.parents)):
681            if self.is_relative_to(path):
682                break
683            elif not walk_up:
684                raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
685            elif path.name == '..':
686                raise ValueError(f"'..' segment in {str(other)!r} cannot be walked")
687        else:
688            raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors")
689        parts = ['..'] * step + self._tail[len(path._tail):]
690        return self.with_segments(*parts)

Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError.

The walk_up parameter controls whether .. may be used to resolve the path.

def is_relative_to(self, other, /, *_deprecated):
692    def is_relative_to(self, other, /, *_deprecated):
693        """Return True if the path is relative to another path or False.
694        """
695        if _deprecated:
696            msg = ("support for supplying more than one argument to "
697                   "pathlib.PurePath.is_relative_to() is deprecated and "
698                   "scheduled for removal in Python {remove}")
699            warnings._deprecated("pathlib.PurePath.is_relative_to(*args)",
700                                 msg, remove=(3, 14))
701        other = self.with_segments(other, *_deprecated)
702        return other == self or other in self.parents

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

parts
704    @property
705    def parts(self):
706        """An object providing sequence-like access to the
707        components in the filesystem path."""
708        if self.drive or self.root:
709            return (self.drive + self.root,) + tuple(self._tail)
710        else:
711            return tuple(self._tail)

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

def joinpath(self, *pathsegments):
713    def joinpath(self, *pathsegments):
714        """Combine this path with one or several arguments, and return a
715        new path representing either a subpath (if all arguments are relative
716        paths) or a totally different path (if one of the arguments is
717        anchored).
718        """
719        return self.with_segments(self, *pathsegments)

Combine this path with one or several arguments, and return a new path representing either a subpath (if all arguments are relative paths) or a totally different path (if one of the arguments is anchored).

parent
733    @property
734    def parent(self):
735        """The logical parent of the path."""
736        drv = self.drive
737        root = self.root
738        tail = self._tail
739        if not tail:
740            return self
741        return self._from_parsed_parts(drv, root, tail[:-1])

The logical parent of the path.

parents
743    @property
744    def parents(self):
745        """A sequence of this path's logical parents."""
746        # The value of this property should not be cached on the path object,
747        # as doing so would introduce a reference cycle.
748        return _PathParents(self)

A sequence of this path's logical parents.

def is_absolute(self):
750    def is_absolute(self):
751        """True if the path is absolute (has both a root and, if applicable,
752        a drive)."""
753        if self._flavour is ntpath:
754            # ntpath.isabs() is defective - see GH-44626.
755            return bool(self.drive and self.root)
756        elif self._flavour is posixpath:
757            # Optimization: work with raw paths on POSIX.
758            for path in self._raw_paths:
759                if path.startswith('/'):
760                    return True
761            return False
762        else:
763            return self._flavour.isabs(str(self))

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

def is_reserved(self):
765    def is_reserved(self):
766        """Return True if the path contains one of the special names reserved
767        by the system, if any."""
768        if self._flavour is posixpath or not self._tail:
769            return False
770
771        # NOTE: the rules for reserved names seem somewhat complicated
772        # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
773        # exist). We err on the side of caution and return True for paths
774        # which are not considered reserved by Windows.
775        if self.drive.startswith('\\\\'):
776            # UNC paths are never reserved.
777            return False
778        name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ')
779        return name.upper() in _WIN_RESERVED_NAMES

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

def match(self, path_pattern, *, case_sensitive=None):
781    def match(self, path_pattern, *, case_sensitive=None):
782        """
783        Return True if this path matches the given pattern.
784        """
785        if not isinstance(path_pattern, PurePath):
786            path_pattern = self.with_segments(path_pattern)
787        if case_sensitive is None:
788            case_sensitive = _is_case_sensitive(self._flavour)
789        pattern = _compile_pattern_lines(path_pattern._lines, case_sensitive)
790        if path_pattern.drive or path_pattern.root:
791            return pattern.match(self._lines) is not None
792        elif path_pattern._tail:
793            return pattern.search(self._lines) is not None
794        else:
795            raise ValueError("empty pattern")

Return True if this path matches the given pattern.

class PurePosixPath(PurePath):
803class PurePosixPath(PurePath):
804    """PurePath subclass for non-Windows systems.
805
806    On a POSIX system, instantiating a PurePath should return this object.
807    However, you can also instantiate it directly on any system.
808    """
809    _flavour = posixpath
810    __slots__ = ()

PurePath subclass for non-Windows systems.

On a POSIX system, instantiating a PurePath should return this object. However, you can also instantiate it directly on any system.

class PureWindowsPath(PurePath):
813class PureWindowsPath(PurePath):
814    """PurePath subclass for Windows systems.
815
816    On a Windows system, instantiating a PurePath should return this object.
817    However, you can also instantiate it directly on any system.
818    """
819    _flavour = ntpath
820    __slots__ = ()

PurePath subclass for Windows systems.

On a Windows system, instantiating a PurePath should return this object. However, you can also instantiate it directly on any system.

class Path(PurePath):
 826class Path(PurePath):
 827    """PurePath subclass that can make system calls.
 828
 829    Path represents a filesystem path but unlike PurePath, also offers
 830    methods to do system calls on path objects. Depending on your system,
 831    instantiating a Path will return either a PosixPath or a WindowsPath
 832    object. You can also instantiate a PosixPath or WindowsPath directly,
 833    but cannot instantiate a WindowsPath on a POSIX system or vice versa.
 834    """
 835    __slots__ = ()
 836
 837    def stat(self, *, follow_symlinks=True):
 838        """
 839        Return the result of the stat() system call on this path, like
 840        os.stat() does.
 841        """
 842        return os.stat(self, follow_symlinks=follow_symlinks)
 843
 844    def lstat(self):
 845        """
 846        Like stat(), except if the path points to a symlink, the symlink's
 847        status information is returned, rather than its target's.
 848        """
 849        return self.stat(follow_symlinks=False)
 850
 851
 852    # Convenience functions for querying the stat results
 853
 854    def exists(self, *, follow_symlinks=True):
 855        """
 856        Whether this path exists.
 857
 858        This method normally follows symlinks; to check whether a symlink exists,
 859        add the argument follow_symlinks=False.
 860        """
 861        try:
 862            self.stat(follow_symlinks=follow_symlinks)
 863        except OSError as e:
 864            if not _ignore_error(e):
 865                raise
 866            return False
 867        except ValueError:
 868            # Non-encodable path
 869            return False
 870        return True
 871
 872    def is_dir(self):
 873        """
 874        Whether this path is a directory.
 875        """
 876        try:
 877            return S_ISDIR(self.stat().st_mode)
 878        except OSError as e:
 879            if not _ignore_error(e):
 880                raise
 881            # Path doesn't exist or is a broken symlink
 882            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 883            return False
 884        except ValueError:
 885            # Non-encodable path
 886            return False
 887
 888    def is_file(self):
 889        """
 890        Whether this path is a regular file (also True for symlinks pointing
 891        to regular files).
 892        """
 893        try:
 894            return S_ISREG(self.stat().st_mode)
 895        except OSError as e:
 896            if not _ignore_error(e):
 897                raise
 898            # Path doesn't exist or is a broken symlink
 899            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 900            return False
 901        except ValueError:
 902            # Non-encodable path
 903            return False
 904
 905    def is_mount(self):
 906        """
 907        Check if this path is a mount point
 908        """
 909        return self._flavour.ismount(self)
 910
 911    def is_symlink(self):
 912        """
 913        Whether this path is a symbolic link.
 914        """
 915        try:
 916            return S_ISLNK(self.lstat().st_mode)
 917        except OSError as e:
 918            if not _ignore_error(e):
 919                raise
 920            # Path doesn't exist
 921            return False
 922        except ValueError:
 923            # Non-encodable path
 924            return False
 925
 926    def is_junction(self):
 927        """
 928        Whether this path is a junction.
 929        """
 930        return self._flavour.isjunction(self)
 931
 932    def is_block_device(self):
 933        """
 934        Whether this path is a block device.
 935        """
 936        try:
 937            return S_ISBLK(self.stat().st_mode)
 938        except OSError as e:
 939            if not _ignore_error(e):
 940                raise
 941            # Path doesn't exist or is a broken symlink
 942            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 943            return False
 944        except ValueError:
 945            # Non-encodable path
 946            return False
 947
 948    def is_char_device(self):
 949        """
 950        Whether this path is a character device.
 951        """
 952        try:
 953            return S_ISCHR(self.stat().st_mode)
 954        except OSError as e:
 955            if not _ignore_error(e):
 956                raise
 957            # Path doesn't exist or is a broken symlink
 958            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 959            return False
 960        except ValueError:
 961            # Non-encodable path
 962            return False
 963
 964    def is_fifo(self):
 965        """
 966        Whether this path is a FIFO.
 967        """
 968        try:
 969            return S_ISFIFO(self.stat().st_mode)
 970        except OSError as e:
 971            if not _ignore_error(e):
 972                raise
 973            # Path doesn't exist or is a broken symlink
 974            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 975            return False
 976        except ValueError:
 977            # Non-encodable path
 978            return False
 979
 980    def is_socket(self):
 981        """
 982        Whether this path is a socket.
 983        """
 984        try:
 985            return S_ISSOCK(self.stat().st_mode)
 986        except OSError as e:
 987            if not _ignore_error(e):
 988                raise
 989            # Path doesn't exist or is a broken symlink
 990            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
 991            return False
 992        except ValueError:
 993            # Non-encodable path
 994            return False
 995
 996    def samefile(self, other_path):
 997        """Return whether other_path is the same or not as this file
 998        (as returned by os.path.samefile()).
 999        """
1000        st = self.stat()
1001        try:
1002            other_st = other_path.stat()
1003        except AttributeError:
1004            other_st = self.with_segments(other_path).stat()
1005        return self._flavour.samestat(st, other_st)
1006
1007    def open(self, mode='r', buffering=-1, encoding=None,
1008             errors=None, newline=None):
1009        """
1010        Open the file pointed by this path and return a file object, as
1011        the built-in open() function does.
1012        """
1013        if "b" not in mode:
1014            encoding = io.text_encoding(encoding)
1015        return io.open(self, mode, buffering, encoding, errors, newline)
1016
1017    def read_bytes(self):
1018        """
1019        Open the file in bytes mode, read it, and close the file.
1020        """
1021        with self.open(mode='rb') as f:
1022            return f.read()
1023
1024    def read_text(self, encoding=None, errors=None):
1025        """
1026        Open the file in text mode, read it, and close the file.
1027        """
1028        encoding = io.text_encoding(encoding)
1029        with self.open(mode='r', encoding=encoding, errors=errors) as f:
1030            return f.read()
1031
1032    def write_bytes(self, data):
1033        """
1034        Open the file in bytes mode, write to it, and close the file.
1035        """
1036        # type-check for the buffer interface before truncating the file
1037        view = memoryview(data)
1038        with self.open(mode='wb') as f:
1039            return f.write(view)
1040
1041    def write_text(self, data, encoding=None, errors=None, newline=None):
1042        """
1043        Open the file in text mode, write to it, and close the file.
1044        """
1045        if not isinstance(data, str):
1046            raise TypeError('data must be str, not %s' %
1047                            data.__class__.__name__)
1048        encoding = io.text_encoding(encoding)
1049        with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
1050            return f.write(data)
1051
1052    def iterdir(self):
1053        """Yield path objects of the directory contents.
1054
1055        The children are yielded in arbitrary order, and the
1056        special entries '.' and '..' are not included.
1057        """
1058        for name in os.listdir(self):
1059            yield self._make_child_relpath(name)
1060
1061    def _scandir(self):
1062        # bpo-24132: a future version of pathlib will support subclassing of
1063        # pathlib.Path to customize how the filesystem is accessed. This
1064        # includes scandir(), which is used to implement glob().
1065        return os.scandir(self)
1066
1067    def _make_child_relpath(self, name):
1068        path_str = str(self)
1069        tail = self._tail
1070        if tail:
1071            path_str = f'{path_str}{self._flavour.sep}{name}'
1072        elif path_str != '.':
1073            path_str = f'{path_str}{name}'
1074        else:
1075            path_str = name
1076        path = self.with_segments(path_str)
1077        path._str = path_str
1078        path._drv = self.drive
1079        path._root = self.root
1080        path._tail_cached = tail + [name]
1081        return path
1082
1083    def glob(self, pattern, *, case_sensitive=None):
1084        """Iterate over this subtree and yield all existing files (of any
1085        kind, including directories) matching the given relative pattern.
1086        """
1087        sys.audit("pathlib.Path.glob", self, pattern)
1088        if not pattern:
1089            raise ValueError("Unacceptable pattern: {!r}".format(pattern))
1090        drv, root, pattern_parts = self._parse_path(pattern)
1091        if drv or root:
1092            raise NotImplementedError("Non-relative patterns are unsupported")
1093        if pattern[-1] in (self._flavour.sep, self._flavour.altsep):
1094            pattern_parts.append('')
1095        selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive)
1096        for p in selector.select_from(self):
1097            yield p
1098
1099    def rglob(self, pattern, *, case_sensitive=None):
1100        """Recursively yield all existing files (of any kind, including
1101        directories) matching the given relative pattern, anywhere in
1102        this subtree.
1103        """
1104        sys.audit("pathlib.Path.rglob", self, pattern)
1105        drv, root, pattern_parts = self._parse_path(pattern)
1106        if drv or root:
1107            raise NotImplementedError("Non-relative patterns are unsupported")
1108        if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep):
1109            pattern_parts.append('')
1110        selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive)
1111        for p in selector.select_from(self):
1112            yield p
1113
1114    def walk(self, top_down=True, on_error=None, follow_symlinks=False):
1115        """Walk the directory tree from this directory, similar to os.walk()."""
1116        sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
1117        paths = [self]
1118
1119        while paths:
1120            path = paths.pop()
1121            if isinstance(path, tuple):
1122                yield path
1123                continue
1124
1125            # We may not have read permission for self, in which case we can't
1126            # get a list of the files the directory contains. os.walk()
1127            # always suppressed the exception in that instance, rather than
1128            # blow up for a minor reason when (say) a thousand readable
1129            # directories are still left to visit. That logic is copied here.
1130            try:
1131                scandir_it = path._scandir()
1132            except OSError as error:
1133                if on_error is not None:
1134                    on_error(error)
1135                continue
1136
1137            with scandir_it:
1138                dirnames = []
1139                filenames = []
1140                for entry in scandir_it:
1141                    try:
1142                        is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
1143                    except OSError:
1144                        # Carried over from os.path.isdir().
1145                        is_dir = False
1146
1147                    if is_dir:
1148                        dirnames.append(entry.name)
1149                    else:
1150                        filenames.append(entry.name)
1151
1152            if top_down:
1153                yield path, dirnames, filenames
1154            else:
1155                paths.append((path, dirnames, filenames))
1156
1157            paths += [path._make_child_relpath(d) for d in reversed(dirnames)]
1158
1159    def __init__(self, *args, **kwargs):
1160        if kwargs:
1161            msg = ("support for supplying keyword arguments to pathlib.PurePath "
1162                   "is deprecated and scheduled for removal in Python {remove}")
1163            warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
1164        super().__init__(*args)
1165
1166    def __new__(cls, *args, **kwargs):
1167        if cls is Path:
1168            cls = WindowsPath if os.name == 'nt' else PosixPath
1169        return object.__new__(cls)
1170
1171    def __enter__(self):
1172        # In previous versions of pathlib, __exit__() marked this path as
1173        # closed; subsequent attempts to perform I/O would raise an IOError.
1174        # This functionality was never documented, and had the effect of
1175        # making Path objects mutable, contrary to PEP 428.
1176        # In Python 3.9 __exit__() was made a no-op.
1177        # In Python 3.11 __enter__() began emitting DeprecationWarning.
1178        # In Python 3.13 __enter__() and __exit__() should be removed.
1179        warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled "
1180                      "for removal in Python 3.13; Path objects as a context "
1181                      "manager is a no-op",
1182                      DeprecationWarning, stacklevel=2)
1183        return self
1184
1185    def __exit__(self, t, v, tb):
1186        pass
1187
1188    # Public API
1189
1190    @classmethod
1191    def cwd(cls):
1192        """Return a new path pointing to the current working directory."""
1193        # We call 'absolute()' rather than using 'os.getcwd()' directly to
1194        # enable users to replace the implementation of 'absolute()' in a
1195        # subclass and benefit from the new behaviour here. This works because
1196        # os.path.abspath('.') == os.getcwd().
1197        return cls().absolute()
1198
1199    @classmethod
1200    def home(cls):
1201        """Return a new path pointing to the user's home directory (as
1202        returned by os.path.expanduser('~')).
1203        """
1204        return cls("~").expanduser()
1205
1206    def absolute(self):
1207        """Return an absolute version of this path by prepending the current
1208        working directory. No normalization or symlink resolution is performed.
1209
1210        Use resolve() to get the canonical path to a file.
1211        """
1212        if self.is_absolute():
1213            return self
1214        elif self.drive:
1215            # There is a CWD on each drive-letter drive.
1216            cwd = self._flavour.abspath(self.drive)
1217        else:
1218            cwd = os.getcwd()
1219            # Fast path for "empty" paths, e.g. Path("."), Path("") or Path().
1220            # We pass only one argument to with_segments() to avoid the cost
1221            # of joining, and we exploit the fact that getcwd() returns a
1222            # fully-normalized string by storing it in _str. This is used to
1223            # implement Path.cwd().
1224            if not self.root and not self._tail:
1225                result = self.with_segments(cwd)
1226                result._str = cwd
1227                return result
1228        return self.with_segments(cwd, self)
1229
1230    def resolve(self, strict=False):
1231        """
1232        Make the path absolute, resolving all symlinks on the way and also
1233        normalizing it.
1234        """
1235
1236        def check_eloop(e):
1237            winerror = getattr(e, 'winerror', 0)
1238            if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME:
1239                raise RuntimeError("Symlink loop from %r" % e.filename)
1240
1241        try:
1242            s = self._flavour.realpath(self, strict=strict)
1243        except OSError as e:
1244            check_eloop(e)
1245            raise
1246        p = self.with_segments(s)
1247
1248        # In non-strict mode, realpath() doesn't raise on symlink loops.
1249        # Ensure we get an exception by calling stat()
1250        if not strict:
1251            try:
1252                p.stat()
1253            except OSError as e:
1254                check_eloop(e)
1255        return p
1256
1257    def owner(self):
1258        """
1259        Return the login name of the file owner.
1260        """
1261        try:
1262            import pwd
1263            return pwd.getpwuid(self.stat().st_uid).pw_name
1264        except ImportError:
1265            raise NotImplementedError("Path.owner() is unsupported on this system")
1266
1267    def group(self):
1268        """
1269        Return the group name of the file gid.
1270        """
1271
1272        try:
1273            import grp
1274            return grp.getgrgid(self.stat().st_gid).gr_name
1275        except ImportError:
1276            raise NotImplementedError("Path.group() is unsupported on this system")
1277
1278    def readlink(self):
1279        """
1280        Return the path to which the symbolic link points.
1281        """
1282        if not hasattr(os, "readlink"):
1283            raise NotImplementedError("os.readlink() not available on this system")
1284        return self.with_segments(os.readlink(self))
1285
1286    def touch(self, mode=0o666, exist_ok=True):
1287        """
1288        Create this file with the given access mode, if it doesn't exist.
1289        """
1290
1291        if exist_ok:
1292            # First try to bump modification time
1293            # Implementation note: GNU touch uses the UTIME_NOW option of
1294            # the utimensat() / futimens() functions.
1295            try:
1296                os.utime(self, None)
1297            except OSError:
1298                # Avoid exception chaining
1299                pass
1300            else:
1301                return
1302        flags = os.O_CREAT | os.O_WRONLY
1303        if not exist_ok:
1304            flags |= os.O_EXCL
1305        fd = os.open(self, flags, mode)
1306        os.close(fd)
1307
1308    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
1309        """
1310        Create a new directory at this given path.
1311        """
1312        try:
1313            os.mkdir(self, mode)
1314        except FileNotFoundError:
1315            if not parents or self.parent == self:
1316                raise
1317            self.parent.mkdir(parents=True, exist_ok=True)
1318            self.mkdir(mode, parents=False, exist_ok=exist_ok)
1319        except OSError:
1320            # Cannot rely on checking for EEXIST, since the operating system
1321            # could give priority to other errors like EACCES or EROFS
1322            if not exist_ok or not self.is_dir():
1323                raise
1324
1325    def chmod(self, mode, *, follow_symlinks=True):
1326        """
1327        Change the permissions of the path, like os.chmod().
1328        """
1329        os.chmod(self, mode, follow_symlinks=follow_symlinks)
1330
1331    def lchmod(self, mode):
1332        """
1333        Like chmod(), except if the path points to a symlink, the symlink's
1334        permissions are changed, rather than its target's.
1335        """
1336        self.chmod(mode, follow_symlinks=False)
1337
1338    def unlink(self, missing_ok=False):
1339        """
1340        Remove this file or link.
1341        If the path is a directory, use rmdir() instead.
1342        """
1343        try:
1344            os.unlink(self)
1345        except FileNotFoundError:
1346            if not missing_ok:
1347                raise
1348
1349    def rmdir(self):
1350        """
1351        Remove this directory.  The directory must be empty.
1352        """
1353        os.rmdir(self)
1354
1355    def rename(self, target):
1356        """
1357        Rename this path to the target path.
1358
1359        The target path may be absolute or relative. Relative paths are
1360        interpreted relative to the current working directory, *not* the
1361        directory of the Path object.
1362
1363        Returns the new Path instance pointing to the target path.
1364        """
1365        os.rename(self, target)
1366        return self.with_segments(target)
1367
1368    def replace(self, target):
1369        """
1370        Rename this path to the target path, overwriting if that path exists.
1371
1372        The target path may be absolute or relative. Relative paths are
1373        interpreted relative to the current working directory, *not* the
1374        directory of the Path object.
1375
1376        Returns the new Path instance pointing to the target path.
1377        """
1378        os.replace(self, target)
1379        return self.with_segments(target)
1380
1381    def symlink_to(self, target, target_is_directory=False):
1382        """
1383        Make this path a symlink pointing to the target path.
1384        Note the order of arguments (link, target) is the reverse of os.symlink.
1385        """
1386        if not hasattr(os, "symlink"):
1387            raise NotImplementedError("os.symlink() not available on this system")
1388        os.symlink(target, self, target_is_directory)
1389
1390    def hardlink_to(self, target):
1391        """
1392        Make this path a hard link pointing to the same file as *target*.
1393
1394        Note the order of arguments (self, target) is the reverse of os.link's.
1395        """
1396        if not hasattr(os, "link"):
1397            raise NotImplementedError("os.link() not available on this system")
1398        os.link(target, self)
1399
1400    def expanduser(self):
1401        """ Return a new path with expanded ~ and ~user constructs
1402        (as returned by os.path.expanduser)
1403        """
1404        if (not (self.drive or self.root) and
1405            self._tail and self._tail[0][:1] == '~'):
1406            homedir = self._flavour.expanduser(self._tail[0])
1407            if homedir[:1] == "~":
1408                raise RuntimeError("Could not determine home directory.")
1409            drv, root, tail = self._parse_path(homedir)
1410            return self._from_parsed_parts(drv, root, tail + self._tail[1:])
1411
1412        return self

PurePath subclass that can make system calls.

Path represents a filesystem path but unlike PurePath, also offers methods to do system calls on path objects. Depending on your system, instantiating a Path will return either a PosixPath or a WindowsPath object. You can also instantiate a PosixPath or WindowsPath directly, but cannot instantiate a WindowsPath on a POSIX system or vice versa.

Path(*args, **kwargs)
1159    def __init__(self, *args, **kwargs):
1160        if kwargs:
1161            msg = ("support for supplying keyword arguments to pathlib.PurePath "
1162                   "is deprecated and scheduled for removal in Python {remove}")
1163            warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
1164        super().__init__(*args)
def stat(self, *, follow_symlinks=True):
837    def stat(self, *, follow_symlinks=True):
838        """
839        Return the result of the stat() system call on this path, like
840        os.stat() does.
841        """
842        return os.stat(self, follow_symlinks=follow_symlinks)

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

def lstat(self):
844    def lstat(self):
845        """
846        Like stat(), except if the path points to a symlink, the symlink's
847        status information is returned, rather than its target's.
848        """
849        return self.stat(follow_symlinks=False)

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

def exists(self, *, follow_symlinks=True):
854    def exists(self, *, follow_symlinks=True):
855        """
856        Whether this path exists.
857
858        This method normally follows symlinks; to check whether a symlink exists,
859        add the argument follow_symlinks=False.
860        """
861        try:
862            self.stat(follow_symlinks=follow_symlinks)
863        except OSError as e:
864            if not _ignore_error(e):
865                raise
866            return False
867        except ValueError:
868            # Non-encodable path
869            return False
870        return True

Whether this path exists.

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

def is_dir(self):
872    def is_dir(self):
873        """
874        Whether this path is a directory.
875        """
876        try:
877            return S_ISDIR(self.stat().st_mode)
878        except OSError as e:
879            if not _ignore_error(e):
880                raise
881            # Path doesn't exist or is a broken symlink
882            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
883            return False
884        except ValueError:
885            # Non-encodable path
886            return False

Whether this path is a directory.

def is_file(self):
888    def is_file(self):
889        """
890        Whether this path is a regular file (also True for symlinks pointing
891        to regular files).
892        """
893        try:
894            return S_ISREG(self.stat().st_mode)
895        except OSError as e:
896            if not _ignore_error(e):
897                raise
898            # Path doesn't exist or is a broken symlink
899            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
900            return False
901        except ValueError:
902            # Non-encodable path
903            return False

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

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

Check if this path is a mount point

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

Whether this path is a junction.

def is_block_device(self):
932    def is_block_device(self):
933        """
934        Whether this path is a block device.
935        """
936        try:
937            return S_ISBLK(self.stat().st_mode)
938        except OSError as e:
939            if not _ignore_error(e):
940                raise
941            # Path doesn't exist or is a broken symlink
942            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
943            return False
944        except ValueError:
945            # Non-encodable path
946            return False

Whether this path is a block device.

def is_char_device(self):
948    def is_char_device(self):
949        """
950        Whether this path is a character device.
951        """
952        try:
953            return S_ISCHR(self.stat().st_mode)
954        except OSError as e:
955            if not _ignore_error(e):
956                raise
957            # Path doesn't exist or is a broken symlink
958            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
959            return False
960        except ValueError:
961            # Non-encodable path
962            return False

Whether this path is a character device.

def is_fifo(self):
964    def is_fifo(self):
965        """
966        Whether this path is a FIFO.
967        """
968        try:
969            return S_ISFIFO(self.stat().st_mode)
970        except OSError as e:
971            if not _ignore_error(e):
972                raise
973            # Path doesn't exist or is a broken symlink
974            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
975            return False
976        except ValueError:
977            # Non-encodable path
978            return False

Whether this path is a FIFO.

def is_socket(self):
980    def is_socket(self):
981        """
982        Whether this path is a socket.
983        """
984        try:
985            return S_ISSOCK(self.stat().st_mode)
986        except OSError as e:
987            if not _ignore_error(e):
988                raise
989            # Path doesn't exist or is a broken symlink
990            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
991            return False
992        except ValueError:
993            # Non-encodable path
994            return False

Whether this path is a socket.

def samefile(self, other_path):
 996    def samefile(self, other_path):
 997        """Return whether other_path is the same or not as this file
 998        (as returned by os.path.samefile()).
 999        """
1000        st = self.stat()
1001        try:
1002            other_st = other_path.stat()
1003        except AttributeError:
1004            other_st = self.with_segments(other_path).stat()
1005        return self._flavour.samestat(st, other_st)

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

def open( self, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
1007    def open(self, mode='r', buffering=-1, encoding=None,
1008             errors=None, newline=None):
1009        """
1010        Open the file pointed by this path and return a file object, as
1011        the built-in open() function does.
1012        """
1013        if "b" not in mode:
1014            encoding = io.text_encoding(encoding)
1015        return io.open(self, mode, buffering, encoding, errors, newline)

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

def read_bytes(self):
1017    def read_bytes(self):
1018        """
1019        Open the file in bytes mode, read it, and close the file.
1020        """
1021        with self.open(mode='rb') as f:
1022            return f.read()

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

def read_text(self, encoding=None, errors=None):
1024    def read_text(self, encoding=None, errors=None):
1025        """
1026        Open the file in text mode, read it, and close the file.
1027        """
1028        encoding = io.text_encoding(encoding)
1029        with self.open(mode='r', encoding=encoding, errors=errors) as f:
1030            return f.read()

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

def write_bytes(self, data):
1032    def write_bytes(self, data):
1033        """
1034        Open the file in bytes mode, write to it, and close the file.
1035        """
1036        # type-check for the buffer interface before truncating the file
1037        view = memoryview(data)
1038        with self.open(mode='wb') as f:
1039            return f.write(view)

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

def write_text(self, data, encoding=None, errors=None, newline=None):
1041    def write_text(self, data, encoding=None, errors=None, newline=None):
1042        """
1043        Open the file in text mode, write to it, and close the file.
1044        """
1045        if not isinstance(data, str):
1046            raise TypeError('data must be str, not %s' %
1047                            data.__class__.__name__)
1048        encoding = io.text_encoding(encoding)
1049        with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
1050            return f.write(data)

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

def iterdir(self):
1052    def iterdir(self):
1053        """Yield path objects of the directory contents.
1054
1055        The children are yielded in arbitrary order, and the
1056        special entries '.' and '..' are not included.
1057        """
1058        for name in os.listdir(self):
1059            yield self._make_child_relpath(name)

Yield path objects of the directory contents.

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

def glob(self, pattern, *, case_sensitive=None):
1083    def glob(self, pattern, *, case_sensitive=None):
1084        """Iterate over this subtree and yield all existing files (of any
1085        kind, including directories) matching the given relative pattern.
1086        """
1087        sys.audit("pathlib.Path.glob", self, pattern)
1088        if not pattern:
1089            raise ValueError("Unacceptable pattern: {!r}".format(pattern))
1090        drv, root, pattern_parts = self._parse_path(pattern)
1091        if drv or root:
1092            raise NotImplementedError("Non-relative patterns are unsupported")
1093        if pattern[-1] in (self._flavour.sep, self._flavour.altsep):
1094            pattern_parts.append('')
1095        selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive)
1096        for p in selector.select_from(self):
1097            yield p

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

def rglob(self, pattern, *, case_sensitive=None):
1099    def rglob(self, pattern, *, case_sensitive=None):
1100        """Recursively yield all existing files (of any kind, including
1101        directories) matching the given relative pattern, anywhere in
1102        this subtree.
1103        """
1104        sys.audit("pathlib.Path.rglob", self, pattern)
1105        drv, root, pattern_parts = self._parse_path(pattern)
1106        if drv or root:
1107            raise NotImplementedError("Non-relative patterns are unsupported")
1108        if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep):
1109            pattern_parts.append('')
1110        selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive)
1111        for p in selector.select_from(self):
1112            yield p

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

def walk(self, top_down=True, on_error=None, follow_symlinks=False):
1114    def walk(self, top_down=True, on_error=None, follow_symlinks=False):
1115        """Walk the directory tree from this directory, similar to os.walk()."""
1116        sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
1117        paths = [self]
1118
1119        while paths:
1120            path = paths.pop()
1121            if isinstance(path, tuple):
1122                yield path
1123                continue
1124
1125            # We may not have read permission for self, in which case we can't
1126            # get a list of the files the directory contains. os.walk()
1127            # always suppressed the exception in that instance, rather than
1128            # blow up for a minor reason when (say) a thousand readable
1129            # directories are still left to visit. That logic is copied here.
1130            try:
1131                scandir_it = path._scandir()
1132            except OSError as error:
1133                if on_error is not None:
1134                    on_error(error)
1135                continue
1136
1137            with scandir_it:
1138                dirnames = []
1139                filenames = []
1140                for entry in scandir_it:
1141                    try:
1142                        is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
1143                    except OSError:
1144                        # Carried over from os.path.isdir().
1145                        is_dir = False
1146
1147                    if is_dir:
1148                        dirnames.append(entry.name)
1149                    else:
1150                        filenames.append(entry.name)
1151
1152            if top_down:
1153                yield path, dirnames, filenames
1154            else:
1155                paths.append((path, dirnames, filenames))
1156
1157            paths += [path._make_child_relpath(d) for d in reversed(dirnames)]

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

@classmethod
def cwd(cls):
1190    @classmethod
1191    def cwd(cls):
1192        """Return a new path pointing to the current working directory."""
1193        # We call 'absolute()' rather than using 'os.getcwd()' directly to
1194        # enable users to replace the implementation of 'absolute()' in a
1195        # subclass and benefit from the new behaviour here. This works because
1196        # os.path.abspath('.') == os.getcwd().
1197        return cls().absolute()

Return a new path pointing to the current working directory.

@classmethod
def home(cls):
1199    @classmethod
1200    def home(cls):
1201        """Return a new path pointing to the user's home directory (as
1202        returned by os.path.expanduser('~')).
1203        """
1204        return cls("~").expanduser()

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

def absolute(self):
1206    def absolute(self):
1207        """Return an absolute version of this path by prepending the current
1208        working directory. No normalization or symlink resolution is performed.
1209
1210        Use resolve() to get the canonical path to a file.
1211        """
1212        if self.is_absolute():
1213            return self
1214        elif self.drive:
1215            # There is a CWD on each drive-letter drive.
1216            cwd = self._flavour.abspath(self.drive)
1217        else:
1218            cwd = os.getcwd()
1219            # Fast path for "empty" paths, e.g. Path("."), Path("") or Path().
1220            # We pass only one argument to with_segments() to avoid the cost
1221            # of joining, and we exploit the fact that getcwd() returns a
1222            # fully-normalized string by storing it in _str. This is used to
1223            # implement Path.cwd().
1224            if not self.root and not self._tail:
1225                result = self.with_segments(cwd)
1226                result._str = cwd
1227                return result
1228        return self.with_segments(cwd, self)

Return an absolute version of this path by prepending the current working directory. No normalization or symlink resolution is performed.

Use resolve() to get the canonical path to a file.

def resolve(self, strict=False):
1230    def resolve(self, strict=False):
1231        """
1232        Make the path absolute, resolving all symlinks on the way and also
1233        normalizing it.
1234        """
1235
1236        def check_eloop(e):
1237            winerror = getattr(e, 'winerror', 0)
1238            if e.errno == ELOOP or winerror == _WINERROR_CANT_RESOLVE_FILENAME:
1239                raise RuntimeError("Symlink loop from %r" % e.filename)
1240
1241        try:
1242            s = self._flavour.realpath(self, strict=strict)
1243        except OSError as e:
1244            check_eloop(e)
1245            raise
1246        p = self.with_segments(s)
1247
1248        # In non-strict mode, realpath() doesn't raise on symlink loops.
1249        # Ensure we get an exception by calling stat()
1250        if not strict:
1251            try:
1252                p.stat()
1253            except OSError as e:
1254                check_eloop(e)
1255        return p

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

def owner(self):
1257    def owner(self):
1258        """
1259        Return the login name of the file owner.
1260        """
1261        try:
1262            import pwd
1263            return pwd.getpwuid(self.stat().st_uid).pw_name
1264        except ImportError:
1265            raise NotImplementedError("Path.owner() is unsupported on this system")

Return the login name of the file owner.

def group(self):
1267    def group(self):
1268        """
1269        Return the group name of the file gid.
1270        """
1271
1272        try:
1273            import grp
1274            return grp.getgrgid(self.stat().st_gid).gr_name
1275        except ImportError:
1276            raise NotImplementedError("Path.group() is unsupported on this system")

Return the group name of the file gid.

def touch(self, mode=438, exist_ok=True):
1286    def touch(self, mode=0o666, exist_ok=True):
1287        """
1288        Create this file with the given access mode, if it doesn't exist.
1289        """
1290
1291        if exist_ok:
1292            # First try to bump modification time
1293            # Implementation note: GNU touch uses the UTIME_NOW option of
1294            # the utimensat() / futimens() functions.
1295            try:
1296                os.utime(self, None)
1297            except OSError:
1298                # Avoid exception chaining
1299                pass
1300            else:
1301                return
1302        flags = os.O_CREAT | os.O_WRONLY
1303        if not exist_ok:
1304            flags |= os.O_EXCL
1305        fd = os.open(self, flags, mode)
1306        os.close(fd)

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

def mkdir(self, mode=511, parents=False, exist_ok=False):
1308    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
1309        """
1310        Create a new directory at this given path.
1311        """
1312        try:
1313            os.mkdir(self, mode)
1314        except FileNotFoundError:
1315            if not parents or self.parent == self:
1316                raise
1317            self.parent.mkdir(parents=True, exist_ok=True)
1318            self.mkdir(mode, parents=False, exist_ok=exist_ok)
1319        except OSError:
1320            # Cannot rely on checking for EEXIST, since the operating system
1321            # could give priority to other errors like EACCES or EROFS
1322            if not exist_ok or not self.is_dir():
1323                raise

Create a new directory at this given path.

def chmod(self, mode, *, follow_symlinks=True):
1325    def chmod(self, mode, *, follow_symlinks=True):
1326        """
1327        Change the permissions of the path, like os.chmod().
1328        """
1329        os.chmod(self, mode, follow_symlinks=follow_symlinks)

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

def lchmod(self, mode):
1331    def lchmod(self, mode):
1332        """
1333        Like chmod(), except if the path points to a symlink, the symlink's
1334        permissions are changed, rather than its target's.
1335        """
1336        self.chmod(mode, follow_symlinks=False)

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

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

Remove this directory. The directory must be empty.

def rename(self, target):
1355    def rename(self, target):
1356        """
1357        Rename this path to the target path.
1358
1359        The target path may be absolute or relative. Relative paths are
1360        interpreted relative to the current working directory, *not* the
1361        directory of the Path object.
1362
1363        Returns the new Path instance pointing to the target path.
1364        """
1365        os.rename(self, target)
1366        return self.with_segments(target)

Rename this path to the target path.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

def replace(self, target):
1368    def replace(self, target):
1369        """
1370        Rename this path to the target path, overwriting if that path exists.
1371
1372        The target path may be absolute or relative. Relative paths are
1373        interpreted relative to the current working directory, *not* the
1374        directory of the Path object.
1375
1376        Returns the new Path instance pointing to the target path.
1377        """
1378        os.replace(self, target)
1379        return self.with_segments(target)

Rename this path to the target path, overwriting if that path exists.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

def expanduser(self):
1400    def expanduser(self):
1401        """ Return a new path with expanded ~ and ~user constructs
1402        (as returned by os.path.expanduser)
1403        """
1404        if (not (self.drive or self.root) and
1405            self._tail and self._tail[0][:1] == '~'):
1406            homedir = self._flavour.expanduser(self._tail[0])
1407            if homedir[:1] == "~":
1408                raise RuntimeError("Could not determine home directory.")
1409            drv, root, tail = self._parse_path(homedir)
1410            return self._from_parsed_parts(drv, root, tail + self._tail[1:])
1411
1412        return self

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

class PosixPath(Path, PurePosixPath):
1415class PosixPath(Path, PurePosixPath):
1416    """Path subclass for non-Windows systems.
1417
1418    On a POSIX system, instantiating a Path should return this object.
1419    """
1420    __slots__ = ()
1421
1422    if os.name == 'nt':
1423        def __new__(cls, *args, **kwargs):
1424            raise NotImplementedError(
1425                f"cannot instantiate {cls.__name__!r} on your system")

Path subclass for non-Windows systems.

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

class WindowsPath(Path, PureWindowsPath):
1427class WindowsPath(Path, PureWindowsPath):
1428    """Path subclass for Windows systems.
1429
1430    On a Windows system, instantiating a Path should return this object.
1431    """
1432    __slots__ = ()
1433
1434    if os.name != 'nt':
1435        def __new__(cls, *args, **kwargs):
1436            raise NotImplementedError(
1437                f"cannot instantiate {cls.__name__!r} on your system")

Path subclass for Windows systems.

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