common operations on posix pathnames instead of importing this module directly import os and refer to this module as os path the os path name is an alias for this module on posix systems on other systems e g windows os path provides the same operations in a manner specific to that platform and is an alias to another module e g ntpath some of this can actually be useful on nonposix systems too e g for manipulation of the pathname component of urls strings representing various pathrelated bits and pieces these are primarily for export internally they are hardcoded should be set before imports for resolving cyclic dependency normalize the case of a pathname trivial in posix string lower on mac on msdos this may also turn slashes into backslashes however other normalizations such as optimizing away are not allowed another function should be defined to do that normalize case of pathname has no effect under posix return os fspaths return whether a path is absolute trivial in posix harder on the mac or msdos def isabss join pathnames ignore the previous parts if a part is absolute insert a unless the first part is empty or already ends in join two or more pathname components inserting as needed if any component is an absolute path all previous path components will be discarded an empty last part will result in a path that ends with a separator a os fspatha sep getsepa path a try if not p path 0 sep 23780 ensure compatible data type even if p is null for b in mapos fspath p if b startswithsep path b elif not path or path endswithsep path b else path sep b except typeerror attributeerror byteswarning genericpath checkargtypes join a p raise return path split a path in head everything up to the last and tail the rest if the path ends in tail will be empty if there is no in the path head will be empty trailing es are stripped from head unless it is the root def splitp split a path in root and extension the extension is everything starting at the last dot in the last pathname component the root is everything before that it is always true that root ext p split a pathname into a drive specification and the rest of the path useful on doswindowsnt on unix the drive is always empty split a pathname into drive and path on posix drive is always empty p os fspathp return p 0 p def splitrootp p os fspathp if isinstancep bytes sep b empty b else sep empty if p 1 sep relative path e g foo return empty empty p elif p1 2 sep or p2 3 sep absolute path e g foo foo foo etc return empty sep p1 else precisely two leading slashes e g foo implementation defined per posix see https pubs opengroup orgonlinepubs9699919799basedefsv1chap04 htmltag0413 return empty p 2 p2 return the tail basename part of a path same as splitpath1 def basenamep return the head dirname part of a path same as splitpath0 returns the directory component of a pathname p os fspathp sep getsepp i p rfindsep 1 head p i if head and head seplenhead head head rstripsep return head is a path a junction def isjunctionpath being true for dangling symbolic links is also useful test whether a path exists returns true for broken symbolic links try os lstatpath except oserror valueerror return false return true is a path a mount point does this work for all unixes is it even guaranteed to work by posix def ismountpath it doesn t exist so not a mount point a symlink can never be a mount point expand paths beginning with or user means home user means that user s home directory if the path doesn t begin with or if the user or home is unknown the path is returned unchanged leaving error reporting to whatever function is called with the expanded path as argument see also module glob for expansion of and in pathnames a function should also be defined to do full shstyle environment variable expansion expand and user constructions if user or home is unknown do nothing path os fspathpath if isinstancepath bytes tilde b else tilde if not path startswithtilde return path sep getseppath i path findsep 1 if i 0 i lenpath if i 1 if home not in os environ try import pwd except importerror pwd module unavailable return path unchanged return path try userhome pwd getpwuidos getuid pwdir except keyerror bpo10496 if the current user identifier doesn t exist in the password database return the path unchanged return path else userhome os environ home else try import pwd except importerror pwd module unavailable return path unchanged return path name path1 i if isinstancename bytes name strname ascii try pwent pwd getpwnamname except keyerror bpo10496 if the user name from the path doesn t exist in the password database return the path unchanged return path userhome pwent pwdir if no user home return the path unchanged on vxworks if userhome is none and sys platform vxworks return path if isinstancepath bytes userhome os fsencodeuserhome root b else root userhome userhome rstriproot return userhome pathi or root expand paths containing shell variable substitutions this expands the forms variable and variable only nonexistent variables are left unchanged varprog none varprogb none def expandvarspath normalize a path e g ab a b and afoo b all become ab it should be understood that this may change the meaning of the path if it contains symbolic links normalize path eliminating double slashes etc path os fspathpath if isinstancepath bytes sep b empty b dot b dotdot b else sep empty dot dotdot if path empty return dot initialslashes path splitrootpath comps path splitsep newcomps for comp in comps if comp in empty dot continue if comp dotdot or not initialslashes and not newcomps or newcomps and newcomps1 dotdot newcomps appendcomp elif newcomps newcomps pop comps newcomps path initialslashes sep joincomps return path or dot else def normpathpath return an absolute path path os fspathpath if not isabspath if isinstancepath bytes cwd os getcwdb else cwd os getcwd path joincwd path return normpathpath return a canonical path i e the absolute location of a file on the filesystem def realpathfilename strictfalse join two paths normalizing and eliminating any symbolic links encountered in the second path current dir parent dir resolve the symbolic link already seen this path use cached value the symlink is not resolved so we must have a symlink loop raise oserrorerrno eloop return already resolved part rest of the path unchanged return a relative version of a path if not path raise valueerrorno path specified path os fspathpath if isinstancepath bytes curdir b sep b pardir b else curdir sep pardir if start is none start curdir else start os fspathstart try startlist x for x in abspathstart splitsep if x pathlist x for x in abspathpath splitsep if x work out how much of the filepath is shared by start and path i lencommonprefixstartlist pathlist rellist pardir lenstartlisti pathlisti if not rellist return curdir return joinrellist except typeerror attributeerror byteswarning deprecationwarning genericpath checkargtypes relpath path start raise return the longest common subpath of the sequence of paths given as input the paths are not normalized before comparing them this is the responsibility of the caller any trailing separator is stripped from the returned path def commonpathpaths strings representing various path related bits and pieces these are primarily for export internally they are hardcoded should be set before imports for resolving cyclic dependency normalize the case of a pathname trivial in posix string lower on mac on ms dos this may also turn slashes into backslashes however other normalizations such as optimizing away are not allowed another function should be defined to do that normalize case of pathname has no effect under posix return whether a path is absolute trivial in posix harder on the mac or ms dos test whether a path is absolute join pathnames ignore the previous parts if a part is absolute insert a unless the first part is empty or already ends in join two or more pathname components inserting as needed if any component is an absolute path all previous path components will be discarded an empty last part will result in a path that ends with a separator 23780 ensure compatible data type even if p is null split a path in head everything up to the last and tail the rest if the path ends in tail will be empty if there is no in the path head will be empty trailing es are stripped from head unless it is the root split a pathname returns tuple head tail where tail is everything after the final slash either part may be empty split a path in root and extension the extension is everything starting at the last dot in the last pathname component the root is everything before that it is always true that root ext p split a pathname into a drive specification and the rest of the path useful on dos windows nt on unix the drive is always empty split a pathname into drive and path on posix drive is always empty split a pathname into drive root and tail on posix drive is always empty the root may be empty a single slash or two slashes the tail contains anything after the root for example splitroot foo bar foo bar splitroot foo bar foo bar splitroot foo bar foo bar splitroot foo bar foo bar relative path e g foo absolute path e g foo foo foo etc precisely two leading slashes e g foo implementation defined per posix see https pubs opengroup org onlinepubs 9699919799 basedefs v1_chap04 html tag_04_13 return the tail basename part of a path same as split path 1 returns the final component of a pathname return the head dirname part of a path same as split path 0 returns the directory component of a pathname is a path a junction test whether a path is a junction junctions are not a part of posix semantics being true for dangling symbolic links is also useful test whether a path exists returns true for broken symbolic links is a path a mount point does this work for all unixes is it even guaranteed to work by posix test whether a path is a mount point it doesn t exist so not a mount point a symlink can never be a mount point path on a different device as path path is the same i node as path expand paths beginning with or user means home user means that user s home directory if the path doesn t begin with or if the user or home is unknown the path is returned unchanged leaving error reporting to whatever function is called with the expanded path as argument see also module glob for expansion of and in pathnames a function should also be defined to do full sh style environment variable expansion expand and user constructions if user or home is unknown do nothing pwd module unavailable return path unchanged bpo 10496 if the current user identifier doesn t exist in the password database return the path unchanged pwd module unavailable return path unchanged bpo 10496 if the user name from the path doesn t exist in the password database return the path unchanged if no user home return the path unchanged on vxworks expand paths containing shell variable substitutions this expands the forms variable and variable only non existent variables are left unchanged expand shell variables of form var and var unknown variables are left unchanged normalize a path e g a b a b and a foo b all become a b it should be understood that this may change the meaning of the path if it contains symbolic links normalize path eliminating double slashes etc normalize path eliminating double slashes etc return an absolute path return a canonical path i e the absolute location of a file on the filesystem return the canonical path of the specified filename eliminating any symbolic links encountered in the path join two paths normalizing and eliminating any symbolic links encountered in the second path current dir parent dir resolve the symbolic link already seen this path use cached value the symlink is not resolved so we must have a symlink loop raise oserror errno eloop return already resolved part rest of the path unchanged not resolved symlink resolved symlink return a relative version of a path work out how much of the filepath is shared by start and path return the longest common sub path of the sequence of paths given as input the paths are not normalized before comparing them this is the responsibility of the caller any trailing separator is stripped from the returned path given a sequence of path names returns the longest common sub path
curdir = '.'
pardir = '..'
extsep = '.'
sep = '/'
pathsep = ':'
defpath = '/bin:/usr/bin'
altsep = None
devnull = '/dev/null'

import os
import sys
import stat
import genericpath
from genericpath import *

__all__ = ["normcase","isabs","join","splitdrive","splitroot","split","splitext",
           "basename","dirname","commonprefix","getsize","getmtime",
           "getatime","getctime","islink","exists","lexists","isdir","isfile",
           "ismount", "expanduser","expandvars","normpath","abspath",
           "samefile","sameopenfile","samestat",
           "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
           "devnull","realpath","supports_unicode_filenames","relpath",
           "commonpath", "isjunction"]


def _get_sep(path):
    if isinstance(path, bytes):
        return b'/'
    else:
        return '/'






def normcase(s):
    
    return os.fspath(s)





def isabs(s):
    
    s = os.fspath(s)
    sep = _get_sep(s)
    return s.startswith(sep)






def join(a, *p):
    
    a = os.fspath(a)
    sep = _get_sep(a)
    path = a
    try:
        if not p:
            path[:0] + sep  
        for b in map(os.fspath, p):
            if b.startswith(sep):
                path = b
            elif not path or path.endswith(sep):
                path += b
            else:
                path += sep + b
    except (TypeError, AttributeError, BytesWarning):
        genericpath._check_arg_types('join', a, *p)
        raise
    return path







def split(p):
    
    p = os.fspath(p)
    sep = _get_sep(p)
    i = p.rfind(sep) + 1
    head, tail = p[:i], p[i:]
    if head and head != sep*len(head):
        head = head.rstrip(sep)
    return head, tail







def splitext(p):
    p = os.fspath(p)
    if isinstance(p, bytes):
        sep = b'/'
        extsep = b'.'
    else:
        sep = '/'
        extsep = '.'
    return genericpath._splitext(p, sep, None, extsep)
splitext.__doc__ = genericpath._splitext.__doc__




def splitdrive(p):
    
    p = os.fspath(p)
    return p[:0], p


def splitroot(p):
    
    p = os.fspath(p)
    if isinstance(p, bytes):
        sep = b'/'
        empty = b''
    else:
        sep = '/'
        empty = ''
    if p[:1] != sep:
        
        return empty, empty, p
    elif p[1:2] != sep or p[2:3] == sep:
        
        return empty, sep, p[1:]
    else:
        
        
        return empty, p[:2], p[2:]




def basename(p):
    
    p = os.fspath(p)
    sep = _get_sep(p)
    i = p.rfind(sep) + 1
    return p[i:]




def dirname(p):
    
    p = os.fspath(p)
    sep = _get_sep(p)
    i = p.rfind(sep) + 1
    head = p[:i]
    if head and head != sep*len(head):
        head = head.rstrip(sep)
    return head




def isjunction(path):
    
    os.fspath(path)
    return False




def lexists(path):
    
    try:
        os.lstat(path)
    except (OSError, ValueError):
        return False
    return True





def ismount(path):
    
    try:
        s1 = os.lstat(path)
    except (OSError, ValueError):
        
        return False
    else:
        
        if stat.S_ISLNK(s1.st_mode):
            return False

    path = os.fspath(path)
    if isinstance(path, bytes):
        parent = join(path, b'..')
    else:
        parent = join(path, '..')
    parent = realpath(parent)
    try:
        s2 = os.lstat(parent)
    except (OSError, ValueError):
        return False

    dev1 = s1.st_dev
    dev2 = s2.st_dev
    if dev1 != dev2:
        return True     
    ino1 = s1.st_ino
    ino2 = s2.st_ino
    if ino1 == ino2:
        return True     
    return False











def expanduser(path):
    
    path = os.fspath(path)
    if isinstance(path, bytes):
        tilde = b'~'
    else:
        tilde = '~'
    if not path.startswith(tilde):
        return path
    sep = _get_sep(path)
    i = path.find(sep, 1)
    if i < 0:
        i = len(path)
    if i == 1:
        if 'HOME' not in os.environ:
            try:
                import pwd
            except ImportError:
                
                return path
            try:
                userhome = pwd.getpwuid(os.getuid()).pw_dir
            except KeyError:
                
                
                return path
        else:
            userhome = os.environ['HOME']
    else:
        try:
            import pwd
        except ImportError:
            
            return path
        name = path[1:i]
        if isinstance(name, bytes):
            name = str(name, 'ASCII')
        try:
            pwent = pwd.getpwnam(name)
        except KeyError:
            
            
            return path
        userhome = pwent.pw_dir
    
    if userhome is None and sys.platform == "vxworks":
        return path
    if isinstance(path, bytes):
        userhome = os.fsencode(userhome)
        root = b'/'
    else:
        root = '/'
    userhome = userhome.rstrip(root)
    return (userhome + path[i:]) or root






_varprog = None
_varprogb = None

def expandvars(path):
    
    path = os.fspath(path)
    global _varprog, _varprogb
    if isinstance(path, bytes):
        if b'$' not in path:
            return path
        if not _varprogb:
            import re
            _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
        search = _varprogb.search
        start = b'{'
        end = b'}'
        environ = getattr(os, 'environb', None)
    else:
        if '$' not in path:
            return path
        if not _varprog:
            import re
            _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
        search = _varprog.search
        start = '{'
        end = '}'
        environ = os.environ
    i = 0
    while True:
        m = search(path, i)
        if not m:
            break
        i, j = m.span(0)
        name = m.group(1)
        if name.startswith(start) and name.endswith(end):
            name = name[1:-1]
        try:
            if environ is None:
                value = os.fsencode(os.environ[os.fsdecode(name)])
            else:
                value = environ[name]
        except KeyError:
            i = j
        else:
            tail = path[j:]
            path = path[:i] + value
            i = len(path)
            path += tail
    return path






try:
    from posix import _path_normpath

except ImportError:
    def normpath(path):
        
        path = os.fspath(path)
        if isinstance(path, bytes):
            sep = b'/'
            empty = b''
            dot = b'.'
            dotdot = b'..'
        else:
            sep = '/'
            empty = ''
            dot = '.'
            dotdot = '..'
        if path == empty:
            return dot
        _, initial_slashes, path = splitroot(path)
        comps = path.split(sep)
        new_comps = []
        for comp in comps:
            if comp in (empty, dot):
                continue
            if (comp != dotdot or (not initial_slashes and not new_comps) or
                 (new_comps and new_comps[-1] == dotdot)):
                new_comps.append(comp)
            elif new_comps:
                new_comps.pop()
        comps = new_comps
        path = initial_slashes + sep.join(comps)
        return path or dot

else:
    def normpath(path):
        
        path = os.fspath(path)
        if isinstance(path, bytes):
            return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
        return _path_normpath(path) or "."


def abspath(path):
    
    path = os.fspath(path)
    if not isabs(path):
        if isinstance(path, bytes):
            cwd = os.getcwdb()
        else:
            cwd = os.getcwd()
        path = join(cwd, path)
    return normpath(path)





def realpath(filename, *, strict=False):
    
    filename = os.fspath(filename)
    path, ok = _joinrealpath(filename[:0], filename, strict, {})
    return abspath(path)



def _joinrealpath(path, rest, strict, seen):
    if isinstance(path, bytes):
        sep = b'/'
        curdir = b'.'
        pardir = b'..'
    else:
        sep = '/'
        curdir = '.'
        pardir = '..'

    if isabs(rest):
        rest = rest[1:]
        path = sep

    while rest:
        name, _, rest = rest.partition(sep)
        if not name or name == curdir:
            
            continue
        if name == pardir:
            
            if path:
                path, name = split(path)
                if name == pardir:
                    path = join(path, pardir, pardir)
            else:
                path = pardir
            continue
        newpath = join(path, name)
        try:
            st = os.lstat(newpath)
        except OSError:
            if strict:
                raise
            is_link = False
        else:
            is_link = stat.S_ISLNK(st.st_mode)
        if not is_link:
            path = newpath
            continue
        
        if newpath in seen:
            
            path = seen[newpath]
            if path is not None:
                
                continue
            
            if strict:
                
                os.stat(newpath)
            else:
                
                return join(newpath, rest), False
        seen[newpath] = None 
        path, ok = _joinrealpath(path, os.readlink(newpath), strict, seen)
        if not ok:
            return join(path, rest), False
        seen[newpath] = path 

    return path, True


supports_unicode_filenames = (sys.platform == 'darwin')

def relpath(path, start=None):
    

    if not path:
        raise ValueError("no path specified")

    path = os.fspath(path)
    if isinstance(path, bytes):
        curdir = b'.'
        sep = b'/'
        pardir = b'..'
    else:
        curdir = '.'
        sep = '/'
        pardir = '..'

    if start is None:
        start = curdir
    else:
        start = os.fspath(start)

    try:
        start_list = [x for x in abspath(start).split(sep) if x]
        path_list = [x for x in abspath(path).split(sep) if x]
        
        i = len(commonprefix([start_list, path_list]))

        rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
        if not rel_list:
            return curdir
        return join(*rel_list)
    except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
        genericpath._check_arg_types('relpath', path, start)
        raise







def commonpath(paths):
    

    if not paths:
        raise ValueError('commonpath() arg is an empty sequence')

    paths = tuple(map(os.fspath, paths))
    if isinstance(paths[0], bytes):
        sep = b'/'
        curdir = b'.'
    else:
        sep = '/'
        curdir = '.'

    try:
        split_paths = [path.split(sep) for path in paths]

        try:
            isabs, = set(p[:1] == sep for p in paths)
        except ValueError:
            raise ValueError("Can't mix absolute and relative paths") from None

        split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
        s1 = min(split_paths)
        s2 = max(split_paths)
        common = s1
        for i, c in enumerate(s1):
            if c != s2[i]:
                common = s1[:i]
                break

        prefix = sep if isabs else sep[:0]
        return prefix + sep.join(common)
    except (TypeError, AttributeError):
        genericpath._check_arg_types('commonpath', *paths)
        raise