objectoriented filesystem paths this module provides classes to represent abstract paths and concrete paths with operations that have semantics appropriate for different operating systems internals maximum number of symlinks to follow in pathbase resolve reference for windows paths can be found at https learn microsoft comengbwindowswin32fileionamingafile ebadf guard against macos stat throwing ebadf globbing helpers compile given glob pattern to a re pattern object observing case sensitivity global re glob if re is none import re glob flags re noflag if casesensitive else re ignorecase regex glob translatepat recursivetrue includehiddentrue sepssep the string representation of an empty path is a single dot empty paths shouldn t match wildcards so we consume it with an atomic group regex r z regex return re compileregex flagsflags match def selectchildrenparentpaths dironly followsymlinks match we must close the scandir object before proceeding to avoid exhausting file descriptors when globbing deep trees yield given paths and all their subdirectories recursively if followsymlinks is none followsymlinks false for parentpath in parentpaths paths parentpath while paths path paths pop yield path try we must close the scandir object before proceeding to avoid exhausting file descriptors when globbing deep trees with path scandir as scandirit entries listscandirit except oserror pass else for entry in entries try if entry isdirfollowsymlinksfollowsymlinks paths appendpath makechildrelpathentry name continue except oserror pass if not dironly yield path makechildrelpathentry name def selectuniquepaths public api an exception that is raised when an unsupported operation is called on a path object this object provides sequencelike access to the logical ancestors of a path don t try to construct it yourself slots path drv root tail def initself path self path path self drv path drive self root path root self tail path tail def lenself return lenself tail def getitemself idx if isinstanceidx slice return tupleselfi for i in rangeidx indiceslenself if idx lenself or idx lenself raise indexerroridx if idx 0 idx lenself return self path fromparsedpartsself drv self root self tail idx 1 def reprself return parents formattypeself path name class purepath slots the rawpaths slot stores unnormalized string paths this is set in the init method rawpaths the drv root and tailcached slots store parsed and normalized parts of the path they are set when any of the drive root or tail properties are accessed for the first time the threepart division corresponds to the result of os path splitroot except that the tail is further split on path separators i e it is a list of strings and that the root and tail are normalized drv root tailcached the str slot stores the string representation of the path computed from the drive root and tail when str is called for the first time it s used to implement strnormcase str the strnormcasecached slot stores the string path with normalized case it is set when the strnormcase property is accessed for the first time it s used to implement eq hash and partsnormcase strnormcasecached the partsnormcasecached slot stores the casenormalized string path after splitting on path separators it s set when the partsnormcase property is accessed for the first time it s used to implement comparison methods like lt partsnormcasecached the hash slot stores the hash of the casenormalized string path it s set when hash is called for the first time hash the resolving slot stores a boolean indicating whether the path is being processed by pathbase resolve this prevents duplicate work from occurring when resolve calls stat or readlink resolving pathmod os path def withsegmentsself pathsegments return typeselfpathsegments classmethod def parsepathcls path if not path return sep cls pathmod sep altsep cls pathmod altsep if altsep path path replacealtsep sep drv root rel cls pathmod splitrootpath if not root and drv startswithsep and not drv endswithsep drvparts drv splitsep if lendrvparts 4 and drvparts2 not in e g servershare root sep elif lendrvparts 6 e g uncservershare root sep parsed sys internstrx for x in rel splitsep if x and x return drv root parsed def loadpartsself paths self rawpaths if lenpaths 0 path elif lenpaths 1 path paths0 else path self pathmod joinpaths drv root tail self parsepathpath self drv drv self root root self tailcached tail def fromparsedpartsself drv root tail pathstr self formatparsedpartsdrv root tail path self withsegmentspathstr path str pathstr or path drv drv path root root path tailcached tail return path classmethod def formatparsedpartscls drv root tail if drv or root return drv root cls pathmod sep jointail elif tail and cls pathmod splitdrivetail00 tail tail return cls pathmod sep jointail def strself return the string representation of the path with forward slashes return strself replaceself pathmod sep def reprself return r formatself class name self asposix property def driveself the root of the path if any try return self root except attributeerror self loadparts return self root property def tailself try return self tailcached except attributeerror self loadparts return self tailcached property def anchorself the final path component if any tail self tail if not tail return return tail1 property def suffixself name self name i name rfind if 0 i lenname 1 return namei else return property def suffixesself name self name if name endswith return name name lstrip return suffix for suffix in name split 1 property def stemself return a new path with the file name changed m self pathmod if not name or m sep in name or m altsep and m altsep in name or name raise valueerrorfinvalid name name r tail self tail copy if not tail raise valueerrorfself r has an empty name tail1 name return self fromparsedpartsself drive self root tail def withstemself stem return a new path with the file suffix changed if the path has no suffix add given suffix if the given suffix is an empty string remove the suffix from the path return the relative path to another path identified by the passed arguments if the operation is not possible because this is not related to the other path raise valueerror the walkup parameter controls whether may be used to resolve the path return true if the path is relative to another path or false an object providing sequencelike access to the components in the filesystem path if self drive or self root return self drive self root tupleself tail else return tupleself tail def joinpathself pathsegments return self withsegmentsself pathsegments def truedivself key try return self joinpathkey except typeerror return notimplemented def rtruedivself key try return self withsegmentskey self except typeerror return notimplemented property def parentself a sequence of this path s logical parents the value of this property should not be cached on the path object as doing so would introduce a reference cycle return pathparentsself def isabsoluteself ntpath isabs is defective see gh44626 optimization work with raw paths on posix return true if the path contains one of the special names reserved by the system if any if self pathmod is posixpath or not self tail return false note the rules for reserved names seem somewhat complicated e g r nul is reserved but not rfoonul if foo does not exist we err on the side of caution and return true for paths which are not considered reserved by windows if self drive startswith unc paths are never reserved return false name self tail1 partition 0 partition 0 rstrip return name upper in winreservednames def matchself pathpattern casesensitivenone if not isinstancepathpattern purepath pathpattern self withsegmentspathpattern if casesensitive is none casesensitive iscasesensitiveself pathmod sep pathpattern pathmod sep patternstr strpathpattern if pathpattern drive or pathpattern root pass elif pathpattern tail patternstr f seppatternstr else raise valueerrorempty pattern match compilepatternpatternstr sep casesensitive return matchstrself is not none def newcls args kwargs if cls is purepath cls purewindowspath if os name nt else pureposixpath return object newcls def initself args paths for arg in args if isinstancearg purepath if arg pathmod is ntpath and self pathmod is posixpath gh103631 convert separators for backwards compatibility paths extendpath replace for path in arg rawpaths else paths extendarg rawpaths else try path os fspatharg except typeerror path arg if not isinstancepath str raise typeerror argument should be a str or an os pathlike object where fspath returns a str fnot typepath name r paths appendpath self rawpaths paths self resolving false def reduceself using the parts tuple helps share interned path parts when pickling related paths return self class self parts def fspathself return strself def bytesself string with normalized case for hashing and equality checks cached parts with normalized case for comparisons return the path as a uri if not self isabsolute raise valueerrorrelative path can t be expressed as a file uri drive self drive if lendrive 2 and drive1 it s a path on a local drive file c ab prefix file drive path self asposix2 elif drive it s a path on a network drive file hostshareab prefix file path self asposix else it s a posix path file etchosts prefix file path strself from urllib parse import quotefrombytes return prefix quotefrombytesos fsencodepath subclassing os pathlike makes isinstance checks slower which in turn makes path construction slower register instead os pathlike registerpurepath class pureposixpathpurepath pathmod posixpath slots class purewindowspathpurepath pathmod ntpath slots filesystemaccessing classes class pathbasepurepath slots bytes none fspath none virtual paths have no local file system representation classmethod def unsupportedcls methodname msg fcls name methodname is unsupported if issubclasscls path msg on this system raise unsupportedoperationmsg def statself followsymlinkstrue self unsupportedstat def lstatself return self statfollowsymlinksfalse convenience functions for querying the stat results def existsself followsymlinkstrue try self statfollowsymlinksfollowsymlinks except oserror as e if not ignoreerrore raise return false except valueerror nonencodable path return false return true def isdirself followsymlinkstrue try return sisdirself statfollowsymlinksfollowsymlinks stmode except oserror as e if not ignoreerrore raise path doesn t exist or is a broken symlink see http web archive orgweb20200623061726https bitbucket orgpitroupathlibissues12 return false except valueerror nonencodable path return false def isfileself followsymlinkstrue try return sisregself statfollowsymlinksfollowsymlinks stmode except oserror as e if not ignoreerrore raise path doesn t exist or is a broken symlink see http web archive orgweb20200623061726https bitbucket orgpitroupathlibissues12 return false except valueerror nonencodable path return false def ismountself need to exist and be a dir if not self exists or not self isdir return false try parentdev self parent stat stdev except oserror return false dev self stat stdev if dev parentdev return true ino self stat stino parentino self parent stat stino return ino parentino def issymlinkself try return sislnkself lstat stmode except oserror as e if not ignoreerrore raise path doesn t exist return false except valueerror nonencodable path return false def isjunctionself junctions are a windowsonly feature not present in posix nor the majority of virtual filesystems there is no crossplatform idiom to check for junctions using stat stmode return false def isblockdeviceself try return sisblkself stat stmode except oserror as e if not ignoreerrore raise path doesn t exist or is a broken symlink see http web archive orgweb20200623061726https bitbucket orgpitroupathlibissues12 return false except valueerror nonencodable path return false def ischardeviceself try return sischrself stat stmode except oserror as e if not ignoreerrore raise path doesn t exist or is a broken symlink see http web archive orgweb20200623061726https bitbucket orgpitroupathlibissues12 return false except valueerror nonencodable path return false def isfifoself try return sisfifoself stat stmode except oserror as e if not ignoreerrore raise path doesn t exist or is a broken symlink see http web archive orgweb20200623061726https bitbucket orgpitroupathlibissues12 return false except valueerror nonencodable path return false def issocketself try return sissockself stat stmode except oserror as e if not ignoreerrore raise path doesn t exist or is a broken symlink see http web archive orgweb20200623061726https bitbucket orgpitroupathlibissues12 return false except valueerror nonencodable path return false def samefileself otherpath st self stat try otherst otherpath stat except attributeerror otherst self withsegmentsotherpath stat return st stino otherst stino and st stdev otherst stdev def openself mode r buffering1 encodingnone errorsnone newlinenone self unsupportedopen def readbytesself with self openmode rb as f return f read def readtextself encodingnone errorsnone newlinenone encoding io textencodingencoding with self openmode r encodingencoding errorserrors newlinenewline as f return f read def writebytesself data typecheck for the buffer interface before truncating the file view memoryviewdata with self openmode wb as f return f writeview def writetextself data encodingnone errorsnone newlinenone if not isinstancedata str raise typeerror data must be str not s data class name encoding io textencodingencoding with self openmode w encodingencoding errorserrors newlinenewline as f return f writedata def iterdirself self unsupportediterdir def scandirself emulate os scandir which returns an object that can be used as a context manager this method is called by walk and glob from contextlib import nullcontext return nullcontextself iterdir def makechildrelpathself name pathstr strself tail self tail if tail pathstr f pathstrself pathmod sepname elif pathstr pathstr f pathstrname else pathstr name path self withsegmentspathstr path str pathstr path drv self drive path root self root path tailcached tail name return path def globself pattern casesensitivenone followsymlinksnone sys auditpathlib path glob self pattern return self globpattern casesensitive followsymlinks def rglobself pattern casesensitivenone followsymlinksnone sys auditpathlib path rglob self pattern return self globf pattern casesensitive followsymlinks def globself pattern casesensitive followsymlinks pathpattern self withsegmentspattern if pathpattern drive or pathpattern root raise notimplementederrornonrelative patterns are unsupported elif not pathpattern tail raise valueerrorunacceptable pattern r formatpattern patternparts pathpattern tail copy if pattern1 in self pathmod sep self pathmod altsep gh65238 pathlib doesn t preserve trailing slash add it back patternparts append if patternparts1 gh70303 only matches directories add trailing slash warnings warn pattern ending will match files and directories in a future python release add a trailing slash to match only directories and remove this warning futurewarning 3 patternparts append if casesensitive is none todo evaluate casesensitivity of each directory in selectchildren casesensitive iscasesensitiveself pathmod if symlinks are handled consistently and the pattern does not contain components then we can use a walkandmatch strategy when expanding wildcards when a wildcard is encountered all following pattern parts are immediately consumed and used to build a re pattern object this pattern is used to filter the recursive walk as a result pattern parts following a wildcard do not perform any filesystem access which can be much faster filterpaths followsymlinks is not none and not in patternparts deduplicatepaths false sep self pathmod sep paths iterself if self isdir else partidx 0 while partidx lenpatternparts part patternpartspartidx partidx 1 if part trailing slash pass elif part paths path makechildrelpath for path in paths elif part consume adjacent components while partidx lenpatternparts and patternpartspartidx partidx 1 if filterpaths and partidx lenpatternparts and patternpartspartidx dironly patternparts1 paths selectrecursivepaths dironly followsymlinks filter out paths that don t match pattern prefixlen lenstrself makechildrelpath 1 match compilepatternstrpathpattern sep casesensitive paths path for path in paths if matchstrpath prefixlen return paths dironly partidx lenpatternparts paths selectrecursivepaths dironly followsymlinks if deduplicatepaths deduplicate if we ve already seen a component paths selectuniquepaths deduplicatepaths true elif in part raise valueerrorinvalid pattern can only be an entire path component else dironly partidx lenpatternparts match compilepatternpart sep casesensitive paths selectchildrenpaths dironly followsymlinks match return paths def walkself topdowntrue onerrornone followsymlinksfalse we may not have read permission for self in which case we can t get a list of the files the directory contains os walk always suppressed the exception in that instance rather than blow up for a minor reason when say a thousand readable directories are still left to visit that logic is copied here carried over from os path isdir return an absolute version of this path no normalization or symlink resolution is performed use resolve to resolve symlinks and remove segments return a new path pointing to the current working directory we call absolute rather than using os getcwd directly to enable users to replace the implementation of absolute in a subclass and benefit from the new behaviour here this works because os path abspath os getcwd return cls absolute def expanduserself self unsupportedexpanduser classmethod def homecls return cls expanduser def readlinkself self unsupportedreadlink readlink supported false def splitstackself if not self tail return self return self fromparsedpartsself drive self root self tail 1 def resolveself strictfalse if self resolving return self path parts self splitstack try path path absolute except unsupportedoperation pass if the user has not overridden the readlink method then symlinks are unsupported and in nonstrict mode we can improve performance by not calling stat querying strict or getattrself readlink supported true linkcount 0 while parts part parts pop if part if not path tail if path root delete segment immediately following root continue elif path tail1 delete segment and its predecessor path path parent continue nextpath path makechildrelpathpart if querying and part nextpath resolving true try st nextpath statfollowsymlinksfalse if sislnkst stmode like linux and macos raise oserrorerrno eloop if too many symlinks are encountered during resolution linkcount 1 if linkcount maxsymlinks raise oserroreloop too many symbolic links in path strself target targetparts nextpath readlink splitstack if the symlink target is absolute like etchosts set the current path to its uppermost parent like if target root path target add the symlink target s reversed tail parts like hosts etc to the stack of unresolved path parts parts extendtargetparts continue elif parts and not sisdirst stmode raise notadirectoryerrorenotdir not a directory strself except oserror if strict raise else querying false nextpath resolving false path nextpath return path def symlinktoself target targetisdirectoryfalse self unsupportedsymlinkto def hardlinktoself target self unsupportedhardlinkto def touchself mode0o666 existoktrue self unsupportedtouch def mkdirself mode0o777 parentsfalse existokfalse self unsupportedmkdir def renameself target self unsupportedrename def replaceself target self unsupportedreplace def chmodself mode followsymlinkstrue self unsupportedchmod def lchmodself mode self chmodmode followsymlinksfalse def unlinkself missingokfalse self unsupportedunlink def rmdirself self unsupportedrmdir def ownerself self unsupportedowner def groupself self unsupportedgroup classmethod def fromuricls uri return the path as a uri self unsupportedasuri class pathpathbase slots bytes purepath bytes fspath purepath fspath asuri purepath asuri def initself args kwargs if kwargs msg support for supplying keyword arguments to pathlib purepath is deprecated and scheduled for removal in python remove warnings deprecatedpathlib purepathkwargs msg remove3 14 super initargs def newcls args kwargs if cls is path cls windowspath if os name nt else posixpath return object newcls def statself followsymlinkstrue return os statself followsymlinksfollowsymlinks def ismountself return os path ismountself def isjunctionself return os path isjunctionself def openself mode r buffering1 encodingnone errorsnone newlinenone if b not in mode encoding io textencodingencoding return io openself mode buffering encoding errors newline def iterdirself return self makechildrelpathname for name in os listdirself def scandirself return os scandirself def absoluteself if self isabsolute return self elif self drive there is a cwd on each driveletter drive cwd os path abspathself drive else cwd os getcwd fast path for empty paths e g path path or path we pass only one argument to withsegments to avoid the cost of joining and we exploit the fact that getcwd returns a fullynormalized string by storing it in str this is used to implement path cwd if not self root and not self tail result self withsegmentscwd result str cwd return result return self withsegmentscwd self def resolveself strictfalse return self withsegmentsos path realpathself strictstrict if pwd def ownerself return pwd getpwuidself stat stuid pwname if grp def groupself return grp getgrgidself stat stgid grname if hasattros readlink def readlinkself return self withsegmentsos readlinkself def touchself mode0o666 existoktrue if existok first try to bump modification time implementation note gnu touch uses the utimenow option of the utimensat futimens functions try os utimeself none except oserror avoid exception chaining pass else return flags os ocreat os owronly if not existok flags os oexcl fd os openself flags mode os closefd def mkdirself mode0o777 parentsfalse existokfalse try os mkdirself mode except filenotfounderror if not parents or self parent self raise self parent mkdirparentstrue existoktrue self mkdirmode parentsfalse existokexistok except oserror cannot rely on checking for eexist since the operating system could give priority to other errors like eacces or erofs if not existok or not self isdir raise def chmodself mode followsymlinkstrue os chmodself mode followsymlinksfollowsymlinks def unlinkself missingokfalse try os unlinkself except filenotfounderror if not missingok raise def rmdirself os rmdirself def renameself target os renameself target return self withsegmentstarget def replaceself target os replaceself target return self withsegmentstarget if hasattros symlink def symlinktoself target targetisdirectoryfalse os symlinktarget self targetisdirectory if hasattros link def hardlinktoself target os linktarget self def expanduserself if not self drive or self root and self tail and self tail0 1 homedir os path expanduserself tail0 if homedir 1 raise runtimeerrorcould not determine home directory drv root tail self parsepathhomedir return self fromparsedpartsdrv root tail self tail1 return self classmethod def fromuricls uri remove empty ity remove localhost ity remove slash before dos deviceunc path replace bar with colon in dos drive path subclass for nonwindows systems on a posix system instantiating a path should return this object path subclass for windows systems on a windows system instantiating a path should return this object internals maximum number of symlinks to follow in _pathbase resolve reference for windows paths can be found at https learn microsoft com en gb windows win32 fileio naming a file drive exists but is not accessible fix for bpo 35306 broken symlink pointing to itself ebadf guard against macos stat throwing ebadf globbing helpers compile given glob pattern to a re pattern object observing case sensitivity the string representation of an empty path is a single dot empty paths shouldn t match wildcards so we consume it with an atomic group yield direct children of given paths filtering by name and type we must close the scandir object before proceeding to avoid exhausting file descriptors when globbing deep trees yield given paths and all their subdirectories recursively we must close the scandir object before proceeding to avoid exhausting file descriptors when globbing deep trees yields the given paths filtering out duplicates public api an exception that is raised when an unsupported operation is called on a path object this object provides sequence like access to the logical ancestors of a path don t try to construct it yourself base class for manipulating paths without i o purepath represents a filesystem path and offers operations which don t imply any actual filesystem i o depending on your system instantiating a purepath will return either a pureposixpath or a purewindowspath object you can also instantiate either of these classes directly regardless of your system the _raw_paths slot stores unnormalized string paths this is set in the __init__ method the _drv _root and _tail_cached slots store parsed and normalized parts of the path they are set when any of the drive root or _tail properties are accessed for the first time the three part division corresponds to the result of os path splitroot except that the tail is further split on path separators i e it is a list of strings and that the root and tail are normalized the _str slot stores the string representation of the path computed from the drive root and tail when __str__ is called for the first time it s used to implement _str_normcase the _str_normcase_cached slot stores the string path with normalized case it is set when the _str_normcase property is accessed for the first time it s used to implement __eq__ __hash__ and _parts_normcase the _parts_normcase_cached slot stores the case normalized string path after splitting on path separators it s set when the _parts_normcase property is accessed for the first time it s used to implement comparison methods like __lt__ the _hash slot stores the hash of the case normalized string path it s set when __hash__ is called for the first time the _resolving slot stores a boolean indicating whether the path is being processed by _pathbase resolve this prevents duplicate work from occurring when resolve calls stat or readlink construct a new path object from any number of path like objects subclasses may override this method to customize how new path objects are created from methods like iterdir e g server share e g unc server share return the string representation of the path suitable for passing to system calls return the string representation of the path with forward slashes the drive prefix letter or unc path if any the root of the path if any the concatenation of the drive and root or the final path component if any the final component s last suffix if any this includes the leading period for example txt a list of the final component s suffixes if any these include the leading periods for example tar gz the final path component minus its last suffix return a new path with the file name changed return a new path with the stem changed return a new path with the file suffix changed if the path has no suffix add given suffix if the given suffix is an empty string remove the suffix from the path return the relative path to another path identified by the passed arguments if the operation is not possible because this is not related to the other path raise valueerror the walk_up parameter controls whether may be used to resolve the path return true if the path is relative to another path or false an object providing sequence like access to the components in the filesystem path combine this path with one or several arguments and return a new path representing either a subpath if all arguments are relative paths or a totally different path if one of the arguments is anchored the logical parent of the path a sequence of this path s logical parents the value of this property should not be cached on the path object as doing so would introduce a reference cycle true if the path is absolute has both a root and if applicable a drive ntpath isabs is defective see gh 44626 optimization work with raw paths on posix return true if the path contains one of the special names reserved by the system if any note the rules for reserved names seem somewhat complicated e g r nul is reserved but not r foo nul if foo does not exist we err on the side of caution and return true for paths which are not considered reserved by windows unc paths are never reserved return true if this path matches the given pattern construct a purepath from one or several strings and or existing purepath objects the strings and path objects are combined so as to yield a canonicalized path which is incorporated into the new purepath object gh 103631 convert separators for backwards compatibility using the parts tuple helps share interned path parts when pickling related paths return the bytes representation of the path this is only recommended to use under unix string with normalized case for hashing and equality checks cached parts with normalized case for comparisons return the path as a uri it s a path on a local drive file c a b it s a path on a network drive file host share a b it s a posix path file etc hosts subclassing os pathlike makes isinstance checks slower which in turn makes path construction slower register instead purepath subclass for non windows systems on a posix system instantiating a purepath should return this object however you can also instantiate it directly on any system purepath subclass for windows systems on a windows system instantiating a purepath should return this object however you can also instantiate it directly on any system filesystem accessing classes base class for concrete path objects this class provides dummy implementations for many methods that derived classes can override selectively the default implementations raise unsupportedoperation the most basic methods such as stat and open directly raise unsupportedoperation these basic methods are called by other methods such as is_dir and read_text the path class derives this class to implement local filesystem paths users may derive their own classes to implement virtual filesystem paths such as paths in archive files or on remote storage systems virtual paths have no local file system representation return the result of the stat system call on this path like os stat does like stat except if the path points to a symlink the symlink s status information is returned rather than its target s convenience functions for querying the stat results whether this path exists this method normally follows symlinks to check whether a symlink exists add the argument follow_symlinks false non encodable path whether this path is a directory path doesn t exist or is a broken symlink see http web archive org web 20200623061726 https bitbucket org pitrou pathlib issues 12 non encodable path whether this path is a regular file also true for symlinks pointing to regular files path doesn t exist or is a broken symlink see http web archive org web 20200623061726 https bitbucket org pitrou pathlib issues 12 non encodable path check if this path is a mount point need to exist and be a dir whether this path is a symbolic link path doesn t exist non encodable path whether this path is a junction junctions are a windows only feature not present in posix nor the majority of virtual filesystems there is no cross platform idiom to check for junctions using stat st_mode whether this path is a block device path doesn t exist or is a broken symlink see http web archive org web 20200623061726 https bitbucket org pitrou pathlib issues 12 non encodable path whether this path is a character device path doesn t exist or is a broken symlink see http web archive org web 20200623061726 https bitbucket org pitrou pathlib issues 12 non encodable path whether this path is a fifo path doesn t exist or is a broken symlink see http web archive org web 20200623061726 https bitbucket org pitrou pathlib issues 12 non encodable path whether this path is a socket path doesn t exist or is a broken symlink see http web archive org web 20200623061726 https bitbucket org pitrou pathlib issues 12 non encodable path return whether other_path is the same or not as this file as returned by os path samefile open the file pointed by this path and return a file object as the built in open function does open the file in bytes mode read it and close the file open the file in text mode read it and close the file open the file in bytes mode write to it and close the file type check for the buffer interface before truncating the file open the file in text mode write to it and close the file yield path objects of the directory contents the children are yielded in arbitrary order and the special entries and are not included emulate os scandir which returns an object that can be used as a context manager this method is called by walk and glob iterate over this subtree and yield all existing files of any kind including directories matching the given relative pattern recursively yield all existing files of any kind including directories matching the given relative pattern anywhere in this subtree gh 65238 pathlib doesn t preserve trailing slash add it back gh 70303 only matches directories add trailing slash todo evaluate case sensitivity of each directory in _select_children if symlinks are handled consistently and the pattern does not contain components then we can use a walk and match strategy when expanding wildcards when a wildcard is encountered all following pattern parts are immediately consumed and used to build a re pattern object this pattern is used to filter the recursive walk as a result pattern parts following a wildcard do not perform any filesystem access which can be much faster trailing slash consume adjacent components filter out paths that don t match pattern de duplicate if we ve already seen a component walk the directory tree from this directory similar to os walk we may not have read permission for self in which case we can t get a list of the files the directory contains os walk always suppressed the exception in that instance rather than blow up for a minor reason when say a thousand readable directories are still left to visit that logic is copied here carried over from os path isdir return an absolute version of this path no normalization or symlink resolution is performed use resolve to resolve symlinks and remove segments return a new path pointing to the current working directory we call absolute rather than using os getcwd directly to enable users to replace the implementation of absolute in a subclass and benefit from the new behaviour here this works because os path abspath os getcwd return a new path with expanded and user constructs as returned by os path expanduser return a new path pointing to expanduser return the path to which the symbolic link points split the path into a 2 tuple anchor parts where anchor is the uppermost parent of the path equivalent to path parents 1 and parts is a reversed list of parts following the anchor make the path absolute resolving all symlinks on the way and also normalizing it if the user has not overridden the readlink method then symlinks are unsupported and in non strict mode we can improve performance by not calling stat delete segment immediately following root delete segment and its predecessor like linux and macos raise oserror errno eloop if too many symlinks are encountered during resolution if the symlink target is absolute like etc hosts set the current path to its uppermost parent like add the symlink target s reversed tail parts like hosts etc to the stack of unresolved path parts make this path a symlink pointing to the target path note the order of arguments link target is the reverse of os symlink make this path a hard link pointing to the same file as target note the order of arguments self target is the reverse of os link s create this file with the given access mode if it doesn t exist create a new directory at this given path rename this path to the target path the target path may be absolute or relative relative paths are interpreted relative to the current working directory not the directory of the path object returns the new path instance pointing to the target path rename this path to the target path overwriting if that path exists the target path may be absolute or relative relative paths are interpreted relative to the current working directory not the directory of the path object returns the new path instance pointing to the target path change the permissions of the path like os chmod like chmod except if the path points to a symlink the symlink s permissions are changed rather than its target s remove this file or link if the path is a directory use rmdir instead remove this directory the directory must be empty return the login name of the file owner return the group name of the file gid return a new path from the given file uri return the path as a uri purepath subclass that can make system calls path represents a filesystem path but unlike purepath also offers methods to do system calls on path objects depending on your system instantiating a path will return either a posixpath or a windowspath object you can also instantiate a posixpath or windowspath directly but cannot instantiate a windowspath on a posix system or vice versa return the result of the stat system call on this path like os stat does check if this path is a mount point whether this path is a junction open the file pointed by this path and return a file object as the built in open function does yield path objects of the directory contents the children are yielded in arbitrary order and the special entries and are not included return an absolute version of this path no normalization or symlink resolution is performed use resolve to resolve symlinks and remove segments there is a cwd on each drive letter drive fast path for empty paths e g path path or path we pass only one argument to with_segments to avoid the cost of joining and we exploit the fact that getcwd returns a fully normalized string by storing it in _str this is used to implement path cwd make the path absolute resolving all symlinks on the way and also normalizing it return the login name of the file owner return the group name of the file gid return the path to which the symbolic link points create this file with the given access mode if it doesn t exist first try to bump modification time implementation note gnu touch uses the utime_now option of the utimensat futimens functions avoid exception chaining create a new directory at this given path cannot rely on checking for eexist since the operating system could give priority to other errors like eacces or erofs change the permissions of the path like os chmod remove this file or link if the path is a directory use rmdir instead remove this directory the directory must be empty rename this path to the target path the target path may be absolute or relative relative paths are interpreted relative to the current working directory not the directory of the path object returns the new path instance pointing to the target path rename this path to the target path overwriting if that path exists the target path may be absolute or relative relative paths are interpreted relative to the current working directory not the directory of the path object returns the new path instance pointing to the target path make this path a symlink pointing to the target path note the order of arguments link target is the reverse of os symlink make this path a hard link pointing to the same file as target note the order of arguments self target is the reverse of os link s return a new path with expanded and user constructs as returned by os path expanduser return a new path from the given file uri remove empty ity remove localhost ity remove slash before dos device unc path replace bar with colon in dos drive path subclass for non windows systems on a posix system instantiating a path should return this object path subclass for windows systems on a windows system instantiating a path should return this object
import functools
import io
import ntpath
import os
import posixpath
import sys
import warnings
from _collections_abc import Sequence
from errno import ENOENT, ENOTDIR, EBADF, ELOOP, EINVAL
from itertools import chain
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO

try:
    import pwd
except ImportError:
    pwd = None
try:
    import grp
except ImportError:
    grp = None


__all__ = [
    "UnsupportedOperation",
    "PurePath", "PurePosixPath", "PureWindowsPath",
    "Path", "PosixPath", "WindowsPath",
    ]






_MAX_SYMLINKS = 40



_WIN_RESERVED_NAMES = frozenset(
    {'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
    {f'COM{c}' for c in '123456789\xb9\xb2\xb3'} |
    {f'LPT{c}' for c in '123456789\xb9\xb2\xb3'}
)

_WINERROR_NOT_READY = 21  
_WINERROR_INVALID_NAME = 123  
_WINERROR_CANT_RESOLVE_FILENAME = 1921  


_IGNORED_ERRNOS = (ENOENT, ENOTDIR, EBADF, ELOOP)

_IGNORED_WINERRORS = (
    _WINERROR_NOT_READY,
    _WINERROR_INVALID_NAME,
    _WINERROR_CANT_RESOLVE_FILENAME)

def _ignore_error(exception):
    return (getattr(exception, 'errno', None) in _IGNORED_ERRNOS or
            getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)


@functools.cache
def _is_case_sensitive(pathmod):
    return pathmod.normcase('Aa') == 'Aa'





re = glob = None


@functools.lru_cache(maxsize=256)
def _compile_pattern(pat, sep, case_sensitive):
    
    global re, glob
    if re is None:
        import re, glob

    flags = re.NOFLAG if case_sensitive else re.IGNORECASE
    regex = glob.translate(pat, recursive=True, include_hidden=True, seps=sep)
    
    
    regex = r'(\.\Z)?+' + regex
    return re.compile(regex, flags=flags).match


def _select_children(parent_paths, dir_only, follow_symlinks, match):
    
    if follow_symlinks is None:
        follow_symlinks = True
    for parent_path in parent_paths:
        try:
            
            
            with parent_path._scandir() as scandir_it:
                entries = list(scandir_it)
        except OSError:
            pass
        else:
            for entry in entries:
                if dir_only:
                    try:
                        if not entry.is_dir(follow_symlinks=follow_symlinks):
                            continue
                    except OSError:
                        continue
                name = entry.name
                if match(name):
                    yield parent_path._make_child_relpath(name)


def _select_recursive(parent_paths, dir_only, follow_symlinks):
    
    if follow_symlinks is None:
        follow_symlinks = False
    for parent_path in parent_paths:
        paths = [parent_path]
        while paths:
            path = paths.pop()
            yield path
            try:
                
                
                with path._scandir() as scandir_it:
                    entries = list(scandir_it)
            except OSError:
                pass
            else:
                for entry in entries:
                    try:
                        if entry.is_dir(follow_symlinks=follow_symlinks):
                            paths.append(path._make_child_relpath(entry.name))
                            continue
                    except OSError:
                        pass
                    if not dir_only:
                        yield path._make_child_relpath(entry.name)


def _select_unique(paths):
    
    yielded = set()
    try:
        for path in paths:
            path_str = str(path)
            if path_str not in yielded:
                yield path
                yielded.add(path_str)
    finally:
        yielded.clear()






class UnsupportedOperation(NotImplementedError):
    
    pass


class _PathParents(Sequence):
    
    __slots__ = ('_path', '_drv', '_root', '_tail')

    def __init__(self, path):
        self._path = path
        self._drv = path.drive
        self._root = path.root
        self._tail = path._tail

    def __len__(self):
        return len(self._tail)

    def __getitem__(self, idx):
        if isinstance(idx, slice):
            return tuple(self[i] for i in range(*idx.indices(len(self))))

        if idx >= len(self) or idx < -len(self):
            raise IndexError(idx)
        if idx < 0:
            idx += len(self)
        return self._path._from_parsed_parts(self._drv, self._root,
                                             self._tail[:-idx - 1])

    def __repr__(self):
        return "<{}.parents>".format(type(self._path).__name__)


class PurePath:
    

    __slots__ = (
        
        
        '_raw_paths',

        
        
        
        
        
        
        
        '_drv', '_root', '_tail_cached',

        
        
        
        '_str',

        
        
        
        
        '_str_normcase_cached',

        
        
        
        
        '_parts_normcase_cached',

        
        
        '_hash',

        
        
        
        '_resolving',
    )
    pathmod = os.path

    def with_segments(self, *pathsegments):
        
        return type(self)(*pathsegments)

    @classmethod
    def _parse_path(cls, path):
        if not path:
            return '', '', []
        sep = cls.pathmod.sep
        altsep = cls.pathmod.altsep
        if altsep:
            path = path.replace(altsep, sep)
        drv, root, rel = cls.pathmod.splitroot(path)
        if not root and drv.startswith(sep) and not drv.endswith(sep):
            drv_parts = drv.split(sep)
            if len(drv_parts) == 4 and drv_parts[2] not in '?.':
                
                root = sep
            elif len(drv_parts) == 6:
                
                root = sep
        parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.']
        return drv, root, parsed

    def _load_parts(self):
        paths = self._raw_paths
        if len(paths) == 0:
            path = ''
        elif len(paths) == 1:
            path = paths[0]
        else:
            path = self.pathmod.join(*paths)
        drv, root, tail = self._parse_path(path)
        self._drv = drv
        self._root = root
        self._tail_cached = tail

    def _from_parsed_parts(self, drv, root, tail):
        path_str = self._format_parsed_parts(drv, root, tail)
        path = self.with_segments(path_str)
        path._str = path_str or '.'
        path._drv = drv
        path._root = root
        path._tail_cached = tail
        return path

    @classmethod
    def _format_parsed_parts(cls, drv, root, tail):
        if drv or root:
            return drv + root + cls.pathmod.sep.join(tail)
        elif tail and cls.pathmod.splitdrive(tail[0])[0]:
            tail = ['.'] + tail
        return cls.pathmod.sep.join(tail)

    def __str__(self):
        
        try:
            return self._str
        except AttributeError:
            self._str = self._format_parsed_parts(self.drive, self.root,
                                                  self._tail) or '.'
            return self._str

    def as_posix(self):
        
        return str(self).replace(self.pathmod.sep, '/')

    def __repr__(self):
        return "{}({!r})".format(self.__class__.__name__, self.as_posix())

    @property
    def drive(self):
        
        try:
            return self._drv
        except AttributeError:
            self._load_parts()
            return self._drv

    @property
    def root(self):
        
        try:
            return self._root
        except AttributeError:
            self._load_parts()
            return self._root

    @property
    def _tail(self):
        try:
            return self._tail_cached
        except AttributeError:
            self._load_parts()
            return self._tail_cached

    @property
    def anchor(self):
        
        anchor = self.drive + self.root
        return anchor

    @property
    def name(self):
        
        tail = self._tail
        if not tail:
            return ''
        return tail[-1]

    @property
    def suffix(self):
        
        name = self.name
        i = name.rfind('.')
        if 0 < i < len(name) - 1:
            return name[i:]
        else:
            return ''

    @property
    def suffixes(self):
        
        name = self.name
        if name.endswith('.'):
            return []
        name = name.lstrip('.')
        return ['.' + suffix for suffix in name.split('.')[1:]]

    @property
    def stem(self):
        
        name = self.name
        i = name.rfind('.')
        if 0 < i < len(name) - 1:
            return name[:i]
        else:
            return name

    def with_name(self, name):
        
        m = self.pathmod
        if not name or m.sep in name or (m.altsep and m.altsep in name) or name == '.':
            raise ValueError(f"Invalid name {name!r}")
        tail = self._tail.copy()
        if not tail:
            raise ValueError(f"{self!r} has an empty name")
        tail[-1] = name
        return self._from_parsed_parts(self.drive, self.root, tail)

    def with_stem(self, stem):
        
        return self.with_name(stem + self.suffix)

    def with_suffix(self, suffix):
        
        if not suffix:
            return self.with_name(self.stem)
        elif suffix.startswith('.') and len(suffix) > 1:
            return self.with_name(self.stem + suffix)
        else:
            raise ValueError(f"Invalid suffix {suffix!r}")

    def relative_to(self, other, /, *_deprecated, walk_up=False):
        
        if _deprecated:
            msg = ("support for supplying more than one positional argument "
                   "to pathlib.PurePath.relative_to() is deprecated and "
                   "scheduled for removal in Python {remove}")
            warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg,
                                 remove=(3, 14))
            other = self.with_segments(other, *_deprecated)
        elif not isinstance(other, PurePath):
            other = self.with_segments(other)
        for step, path in enumerate(chain([other], other.parents)):
            if path == self or path in self.parents:
                break
            elif not walk_up:
                raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
            elif path.name == '..':
                raise ValueError(f"'..' segment in {str(other)!r} cannot be walked")
        else:
            raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors")
        parts = ['..'] * step + self._tail[len(path._tail):]
        return self._from_parsed_parts('', '', parts)

    def is_relative_to(self, other, /, *_deprecated):
        
        if _deprecated:
            msg = ("support for supplying more than one argument to "
                   "pathlib.PurePath.is_relative_to() is deprecated and "
                   "scheduled for removal in Python {remove}")
            warnings._deprecated("pathlib.PurePath.is_relative_to(*args)",
                                 msg, remove=(3, 14))
            other = self.with_segments(other, *_deprecated)
        elif not isinstance(other, PurePath):
            other = self.with_segments(other)
        return other == self or other in self.parents

    @property
    def parts(self):
        
        if self.drive or self.root:
            return (self.drive + self.root,) + tuple(self._tail)
        else:
            return tuple(self._tail)

    def joinpath(self, *pathsegments):
        
        return self.with_segments(self, *pathsegments)

    def __truediv__(self, key):
        try:
            return self.joinpath(key)
        except TypeError:
            return NotImplemented

    def __rtruediv__(self, key):
        try:
            return self.with_segments(key, self)
        except TypeError:
            return NotImplemented

    @property
    def parent(self):
        
        drv = self.drive
        root = self.root
        tail = self._tail
        if not tail:
            return self
        path = self._from_parsed_parts(drv, root, tail[:-1])
        path._resolving = self._resolving
        return path

    @property
    def parents(self):
        
        
        
        return _PathParents(self)

    def is_absolute(self):
        
        if self.pathmod is ntpath:
            
            return bool(self.drive and self.root)
        elif self.pathmod is posixpath:
            
            for path in self._raw_paths:
                if path.startswith('/'):
                    return True
            return False
        else:
            return self.pathmod.isabs(str(self))

    def is_reserved(self):
        
        if self.pathmod is posixpath or not self._tail:
            return False

        
        
        
        
        if self.drive.startswith('\\\\'):
            
            return False
        name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ')
        return name.upper() in _WIN_RESERVED_NAMES

    def match(self, path_pattern, *, case_sensitive=None):
        
        if not isinstance(path_pattern, PurePath):
            path_pattern = self.with_segments(path_pattern)
        if case_sensitive is None:
            case_sensitive = _is_case_sensitive(self.pathmod)
        sep = path_pattern.pathmod.sep
        pattern_str = str(path_pattern)
        if path_pattern.drive or path_pattern.root:
            pass
        elif path_pattern._tail:
            pattern_str = f'**{sep}{pattern_str}'
        else:
            raise ValueError("empty pattern")
        match = _compile_pattern(pattern_str, sep, case_sensitive)
        return match(str(self)) is not None

    def __new__(cls, *args, **kwargs):
        
        if cls is PurePath:
            cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
        return object.__new__(cls)

    def __init__(self, *args):
        paths = []
        for arg in args:
            if isinstance(arg, PurePath):
                if arg.pathmod is ntpath and self.pathmod is posixpath:
                    
                    paths.extend(path.replace('\\', '/') for path in arg._raw_paths)
                else:
                    paths.extend(arg._raw_paths)
            else:
                try:
                    path = os.fspath(arg)
                except TypeError:
                    path = arg
                if not isinstance(path, str):
                    raise TypeError(
                        "argument should be a str or an os.PathLike "
                        "object where __fspath__ returns a str, "
                        f"not {type(path).__name__!r}")
                paths.append(path)
        self._raw_paths = paths
        self._resolving = False

    def __reduce__(self):
        
        
        return (self.__class__, self.parts)

    def __fspath__(self):
        return str(self)

    def __bytes__(self):
        
        return os.fsencode(self)

    @property
    def _str_normcase(self):
        
        try:
            return self._str_normcase_cached
        except AttributeError:
            if _is_case_sensitive(self.pathmod):
                self._str_normcase_cached = str(self)
            else:
                self._str_normcase_cached = str(self).lower()
            return self._str_normcase_cached

    def __hash__(self):
        try:
            return self._hash
        except AttributeError:
            self._hash = hash(self._str_normcase)
            return self._hash

    def __eq__(self, other):
        if not isinstance(other, PurePath):
            return NotImplemented
        return self._str_normcase == other._str_normcase and self.pathmod is other.pathmod

    @property
    def _parts_normcase(self):
        
        try:
            return self._parts_normcase_cached
        except AttributeError:
            self._parts_normcase_cached = self._str_normcase.split(self.pathmod.sep)
            return self._parts_normcase_cached

    def __lt__(self, other):
        if not isinstance(other, PurePath) or self.pathmod is not other.pathmod:
            return NotImplemented
        return self._parts_normcase < other._parts_normcase

    def __le__(self, other):
        if not isinstance(other, PurePath) or self.pathmod is not other.pathmod:
            return NotImplemented
        return self._parts_normcase <= other._parts_normcase

    def __gt__(self, other):
        if not isinstance(other, PurePath) or self.pathmod is not other.pathmod:
            return NotImplemented
        return self._parts_normcase > other._parts_normcase

    def __ge__(self, other):
        if not isinstance(other, PurePath) or self.pathmod is not other.pathmod:
            return NotImplemented
        return self._parts_normcase >= other._parts_normcase

    def as_uri(self):
        
        if not self.is_absolute():
            raise ValueError("relative path can't be expressed as a file URI")

        drive = self.drive
        if len(drive) == 2 and drive[1] == ':':
            
            prefix = 'file:///' + drive
            path = self.as_posix()[2:]
        elif drive:
            
            prefix = 'file:'
            path = self.as_posix()
        else:
            
            prefix = 'file://'
            path = str(self)
        from urllib.parse import quote_from_bytes
        return prefix + quote_from_bytes(os.fsencode(path))




os.PathLike.register(PurePath)


class PurePosixPath(PurePath):
    
    pathmod = posixpath
    __slots__ = ()


class PureWindowsPath(PurePath):
    
    pathmod = ntpath
    __slots__ = ()





class _PathBase(PurePath):
    
    __slots__ = ()
    __bytes__ = None
    __fspath__ = None  

    @classmethod
    def _unsupported(cls, method_name):
        msg = f"{cls.__name__}.{method_name}() is unsupported"
        if issubclass(cls, Path):
            msg += " on this system"
        raise UnsupportedOperation(msg)

    def stat(self, *, follow_symlinks=True):
        
        self._unsupported("stat")

    def lstat(self):
        
        return self.stat(follow_symlinks=False)


    

    def exists(self, *, follow_symlinks=True):
        
        try:
            self.stat(follow_symlinks=follow_symlinks)
        except OSError as e:
            if not _ignore_error(e):
                raise
            return False
        except ValueError:
            
            return False
        return True

    def is_dir(self, *, follow_symlinks=True):
        
        try:
            return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            
            return False
        except ValueError:
            
            return False

    def is_file(self, *, follow_symlinks=True):
        
        try:
            return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            
            return False
        except ValueError:
            
            return False

    def is_mount(self):
        
        
        if not self.exists() or not self.is_dir():
            return False

        try:
            parent_dev = self.parent.stat().st_dev
        except OSError:
            return False

        dev = self.stat().st_dev
        if dev != parent_dev:
            return True
        ino = self.stat().st_ino
        parent_ino = self.parent.stat().st_ino
        return ino == parent_ino

    def is_symlink(self):
        
        try:
            return S_ISLNK(self.lstat().st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            return False
        except ValueError:
            
            return False

    def is_junction(self):
        
        
        
        
        return False

    def is_block_device(self):
        
        try:
            return S_ISBLK(self.stat().st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            
            return False
        except ValueError:
            
            return False

    def is_char_device(self):
        
        try:
            return S_ISCHR(self.stat().st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            
            return False
        except ValueError:
            
            return False

    def is_fifo(self):
        
        try:
            return S_ISFIFO(self.stat().st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            
            return False
        except ValueError:
            
            return False

    def is_socket(self):
        
        try:
            return S_ISSOCK(self.stat().st_mode)
        except OSError as e:
            if not _ignore_error(e):
                raise
            
            
            return False
        except ValueError:
            
            return False

    def samefile(self, other_path):
        
        st = self.stat()
        try:
            other_st = other_path.stat()
        except AttributeError:
            other_st = self.with_segments(other_path).stat()
        return (st.st_ino == other_st.st_ino and
                st.st_dev == other_st.st_dev)

    def open(self, mode='r', buffering=-1, encoding=None,
             errors=None, newline=None):
        
        self._unsupported("open")

    def read_bytes(self):
        
        with self.open(mode='rb') as f:
            return f.read()

    def read_text(self, encoding=None, errors=None, newline=None):
        
        encoding = io.text_encoding(encoding)
        with self.open(mode='r', encoding=encoding, errors=errors, newline=newline) as f:
            return f.read()

    def write_bytes(self, data):
        
        
        view = memoryview(data)
        with self.open(mode='wb') as f:
            return f.write(view)

    def write_text(self, data, encoding=None, errors=None, newline=None):
        
        if not isinstance(data, str):
            raise TypeError('data must be str, not %s' %
                            data.__class__.__name__)
        encoding = io.text_encoding(encoding)
        with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
            return f.write(data)

    def iterdir(self):
        
        self._unsupported("iterdir")

    def _scandir(self):
        
        
        from contextlib import nullcontext
        return nullcontext(self.iterdir())

    def _make_child_relpath(self, name):
        path_str = str(self)
        tail = self._tail
        if tail:
            path_str = f'{path_str}{self.pathmod.sep}{name}'
        elif path_str != '.':
            path_str = f'{path_str}{name}'
        else:
            path_str = name
        path = self.with_segments(path_str)
        path._str = path_str
        path._drv = self.drive
        path._root = self.root
        path._tail_cached = tail + [name]
        return path

    def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
        
        sys.audit("pathlib.Path.glob", self, pattern)
        return self._glob(pattern, case_sensitive, follow_symlinks)

    def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
        
        sys.audit("pathlib.Path.rglob", self, pattern)
        return self._glob(f'**/{pattern}', case_sensitive, follow_symlinks)

    def _glob(self, pattern, case_sensitive, follow_symlinks):
        path_pattern = self.with_segments(pattern)
        if path_pattern.drive or path_pattern.root:
            raise NotImplementedError("Non-relative patterns are unsupported")
        elif not path_pattern._tail:
            raise ValueError("Unacceptable pattern: {!r}".format(pattern))

        pattern_parts = path_pattern._tail.copy()
        if pattern[-1] in (self.pathmod.sep, self.pathmod.altsep):
            
            pattern_parts.append('')
        if pattern_parts[-1] == '**':
            
            warnings.warn(
                "Pattern ending '**' will match files and directories in a "
                "future Python release. Add a trailing slash to match only "
                "directories and remove this warning.",
                FutureWarning, 3)
            pattern_parts.append('')

        if case_sensitive is None:
            
            case_sensitive = _is_case_sensitive(self.pathmod)

        
        
        
        
        
        
        
        filter_paths = follow_symlinks is not None and '..' not in pattern_parts
        deduplicate_paths = False
        sep = self.pathmod.sep
        paths = iter([self] if self.is_dir() else [])
        part_idx = 0
        while part_idx < len(pattern_parts):
            part = pattern_parts[part_idx]
            part_idx += 1
            if part == '':
                
                pass
            elif part == '..':
                paths = (path._make_child_relpath('..') for path in paths)
            elif part == '**':
                
                while part_idx < len(pattern_parts) and pattern_parts[part_idx] == '**':
                    part_idx += 1

                if filter_paths and part_idx < len(pattern_parts) and pattern_parts[part_idx] != '':
                    dir_only = pattern_parts[-1] == ''
                    paths = _select_recursive(paths, dir_only, follow_symlinks)

                    
                    prefix_len = len(str(self._make_child_relpath('_'))) - 1
                    match = _compile_pattern(str(path_pattern), sep, case_sensitive)
                    paths = (path for path in paths if match(str(path), prefix_len))
                    return paths

                dir_only = part_idx < len(pattern_parts)
                paths = _select_recursive(paths, dir_only, follow_symlinks)
                if deduplicate_paths:
                    
                    paths = _select_unique(paths)
                deduplicate_paths = True
            elif '**' in part:
                raise ValueError("Invalid pattern: '**' can only be an entire path component")
            else:
                dir_only = part_idx < len(pattern_parts)
                match = _compile_pattern(part, sep, case_sensitive)
                paths = _select_children(paths, dir_only, follow_symlinks, match)
        return paths

    def walk(self, top_down=True, on_error=None, follow_symlinks=False):
        
        sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
        paths = [self]

        while paths:
            path = paths.pop()
            if isinstance(path, tuple):
                yield path
                continue

            
            
            
            
            
            try:
                scandir_obj = path._scandir()
            except OSError as error:
                if on_error is not None:
                    on_error(error)
                continue

            with scandir_obj as scandir_it:
                dirnames = []
                filenames = []
                for entry in scandir_it:
                    try:
                        is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
                    except OSError:
                        
                        is_dir = False

                    if is_dir:
                        dirnames.append(entry.name)
                    else:
                        filenames.append(entry.name)

            if top_down:
                yield path, dirnames, filenames
            else:
                paths.append((path, dirnames, filenames))

            paths += [path._make_child_relpath(d) for d in reversed(dirnames)]

    def absolute(self):
        
        self._unsupported("absolute")

    @classmethod
    def cwd(cls):
        
        
        
        
        
        return cls().absolute()

    def expanduser(self):
        
        self._unsupported("expanduser")

    @classmethod
    def home(cls):
        
        return cls("~").expanduser()

    def readlink(self):
        
        self._unsupported("readlink")
    readlink._supported = False

    def _split_stack(self):
        
        if not self._tail:
            return self, []
        return self._from_parsed_parts(self.drive, self.root, []), self._tail[::-1]

    def resolve(self, strict=False):
        
        if self._resolving:
            return self
        path, parts = self._split_stack()
        try:
            path = path.absolute()
        except UnsupportedOperation:
            pass

        
        
        querying = strict or getattr(self.readlink, '_supported', True)
        link_count = 0
        while parts:
            part = parts.pop()
            if part == '..':
                if not path._tail:
                    if path.root:
                        
                        continue
                elif path._tail[-1] != '..':
                    
                    path = path.parent
                    continue
            next_path = path._make_child_relpath(part)
            if querying and part != '..':
                next_path._resolving = True
                try:
                    st = next_path.stat(follow_symlinks=False)
                    if S_ISLNK(st.st_mode):
                        
                        
                        link_count += 1
                        if link_count >= _MAX_SYMLINKS:
                            raise OSError(ELOOP, "Too many symbolic links in path", str(self))
                        target, target_parts = next_path.readlink()._split_stack()
                        
                        
                        if target.root:
                            path = target
                        
                        
                        parts.extend(target_parts)
                        continue
                    elif parts and not S_ISDIR(st.st_mode):
                        raise NotADirectoryError(ENOTDIR, "Not a directory", str(self))
                except OSError:
                    if strict:
                        raise
                    else:
                        querying = False
                next_path._resolving = False
            path = next_path
        return path

    def symlink_to(self, target, target_is_directory=False):
        
        self._unsupported("symlink_to")

    def hardlink_to(self, target):
        
        self._unsupported("hardlink_to")

    def touch(self, mode=0o666, exist_ok=True):
        
        self._unsupported("touch")

    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
        
        self._unsupported("mkdir")

    def rename(self, target):
        
        self._unsupported("rename")

    def replace(self, target):
        
        self._unsupported("replace")

    def chmod(self, mode, *, follow_symlinks=True):
        
        self._unsupported("chmod")

    def lchmod(self, mode):
        
        self.chmod(mode, follow_symlinks=False)

    def unlink(self, missing_ok=False):
        
        self._unsupported("unlink")

    def rmdir(self):
        
        self._unsupported("rmdir")

    def owner(self):
        
        self._unsupported("owner")

    def group(self):
        
        self._unsupported("group")

    @classmethod
    def from_uri(cls, uri):
        
        cls._unsupported("from_uri")

    def as_uri(self):
        
        self._unsupported("as_uri")


class Path(_PathBase):
    
    __slots__ = ()
    __bytes__ = PurePath.__bytes__
    __fspath__ = PurePath.__fspath__
    as_uri = PurePath.as_uri

    def __init__(self, *args, **kwargs):
        if kwargs:
            msg = ("support for supplying keyword arguments to pathlib.PurePath "
                   "is deprecated and scheduled for removal in Python {remove}")
            warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
        super().__init__(*args)

    def __new__(cls, *args, **kwargs):
        if cls is Path:
            cls = WindowsPath if os.name == 'nt' else PosixPath
        return object.__new__(cls)

    def stat(self, *, follow_symlinks=True):
        
        return os.stat(self, follow_symlinks=follow_symlinks)

    def is_mount(self):
        
        return os.path.ismount(self)

    def is_junction(self):
        
        return os.path.isjunction(self)

    def open(self, mode='r', buffering=-1, encoding=None,
             errors=None, newline=None):
        
        if "b" not in mode:
            encoding = io.text_encoding(encoding)
        return io.open(self, mode, buffering, encoding, errors, newline)

    def iterdir(self):
        
        return (self._make_child_relpath(name) for name in os.listdir(self))

    def _scandir(self):
        return os.scandir(self)

    def absolute(self):
        
        if self.is_absolute():
            return self
        elif self.drive:
            
            cwd = os.path.abspath(self.drive)
        else:
            cwd = os.getcwd()
            
            
            
            
            
            if not self.root and not self._tail:
                result = self.with_segments(cwd)
                result._str = cwd
                return result
        return self.with_segments(cwd, self)

    def resolve(self, strict=False):
        

        return self.with_segments(os.path.realpath(self, strict=strict))

    if pwd:
        def owner(self):
            
            return pwd.getpwuid(self.stat().st_uid).pw_name

    if grp:
        def group(self):
            
            return grp.getgrgid(self.stat().st_gid).gr_name

    if hasattr(os, "readlink"):
        def readlink(self):
            
            return self.with_segments(os.readlink(self))

    def touch(self, mode=0o666, exist_ok=True):
        

        if exist_ok:
            
            
            
            try:
                os.utime(self, None)
            except OSError:
                
                pass
            else:
                return
        flags = os.O_CREAT | os.O_WRONLY
        if not exist_ok:
            flags |= os.O_EXCL
        fd = os.open(self, flags, mode)
        os.close(fd)

    def mkdir(self, mode=0o777, parents=False, exist_ok=False):
        
        try:
            os.mkdir(self, mode)
        except FileNotFoundError:
            if not parents or self.parent == self:
                raise
            self.parent.mkdir(parents=True, exist_ok=True)
            self.mkdir(mode, parents=False, exist_ok=exist_ok)
        except OSError:
            
            
            if not exist_ok or not self.is_dir():
                raise

    def chmod(self, mode, *, follow_symlinks=True):
        
        os.chmod(self, mode, follow_symlinks=follow_symlinks)

    def unlink(self, missing_ok=False):
        
        try:
            os.unlink(self)
        except FileNotFoundError:
            if not missing_ok:
                raise

    def rmdir(self):
        
        os.rmdir(self)

    def rename(self, target):
        
        os.rename(self, target)
        return self.with_segments(target)

    def replace(self, target):
        
        os.replace(self, target)
        return self.with_segments(target)

    if hasattr(os, "symlink"):
        def symlink_to(self, target, target_is_directory=False):
            
            os.symlink(target, self, target_is_directory)

    if hasattr(os, "link"):
        def hardlink_to(self, target):
            
            os.link(target, self)

    def expanduser(self):
        
        if (not (self.drive or self.root) and
            self._tail and self._tail[0][:1] == '~'):
            homedir = os.path.expanduser(self._tail[0])
            if homedir[:1] == "~":
                raise RuntimeError("Could not determine home directory.")
            drv, root, tail = self._parse_path(homedir)
            return self._from_parsed_parts(drv, root, tail + self._tail[1:])

        return self

    @classmethod
    def from_uri(cls, uri):
        
        if not uri.startswith('file:'):
            raise ValueError(f"URI does not start with 'file:': {uri!r}")
        path = uri[5:]
        if path[:3] == '///':
            
            path = path[2:]
        elif path[:12] == '//localhost/':
            
            path = path[11:]
        if path[:3] == '///' or (path[:1] == '/' and path[2:3] in ':|'):
            
            path = path[1:]
        if path[1:2] == '|':
            
            path = path[:1] + ':' + path[2:]
        from urllib.parse import unquote_to_bytes
        path = cls(os.fsdecode(unquote_to_bytes(path)))
        if not path.is_absolute():
            raise ValueError(f"URI is not absolute: {uri!r}")
        return path


class PosixPath(Path, PurePosixPath):
    
    __slots__ = ()

    if os.name == 'nt':
        def __new__(cls, *args, **kwargs):
            raise UnsupportedOperation(
                f"cannot instantiate {cls.__name__!r} on your system")

class WindowsPath(Path, PureWindowsPath):
    
    __slots__ = ()

    if os.name != 'nt':
        def __new__(cls, *args, **kwargs):
            raise UnsupportedOperation(
                f"cannot instantiate {cls.__name__!r} on your system")