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