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