• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Path operations common to more than one OS
3Do not use directly.  The OS specific modules import the appropriate
4functions from this module themselves.
5"""
6import os
7import stat
8
9__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',
10           'getsize', 'isdir', 'isfile', 'samefile', 'sameopenfile',
11           'samestat']
12
13
14# Does a path exist?
15# This is false for dangling symbolic links on systems that support them.
16def exists(path):
17    """Test whether a path exists.  Returns False for broken symbolic links"""
18    try:
19        os.stat(path)
20    except OSError:
21        return False
22    return True
23
24
25# This follows symbolic links, so both islink() and isdir() can be true
26# for the same path on systems that support symlinks
27def isfile(path):
28    """Test whether a path is a regular file"""
29    try:
30        st = os.stat(path)
31    except OSError:
32        return False
33    return stat.S_ISREG(st.st_mode)
34
35
36# Is a path a directory?
37# This follows symbolic links, so both islink() and isdir()
38# can be true for the same path on systems that support symlinks
39def isdir(s):
40    """Return true if the pathname refers to an existing directory."""
41    try:
42        st = os.stat(s)
43    except OSError:
44        return False
45    return stat.S_ISDIR(st.st_mode)
46
47
48def getsize(filename):
49    """Return the size of a file, reported by os.stat()."""
50    return os.stat(filename).st_size
51
52
53def getmtime(filename):
54    """Return the last modification time of a file, reported by os.stat()."""
55    return os.stat(filename).st_mtime
56
57
58def getatime(filename):
59    """Return the last access time of a file, reported by os.stat()."""
60    return os.stat(filename).st_atime
61
62
63def getctime(filename):
64    """Return the metadata change time of a file, reported by os.stat()."""
65    return os.stat(filename).st_ctime
66
67
68# Return the longest prefix of all list elements.
69def commonprefix(m):
70    "Given a list of pathnames, returns the longest common leading component"
71    if not m: return ''
72    # Some people pass in a list of pathname parts to operate in an OS-agnostic
73    # fashion; don't try to translate in that case as that's an abuse of the
74    # API and they are already doing what they need to be OS-agnostic and so
75    # they most likely won't be using an os.PathLike object in the sublists.
76    if not isinstance(m[0], (list, tuple)):
77        m = tuple(map(os.fspath, m))
78    s1 = min(m)
79    s2 = max(m)
80    for i, c in enumerate(s1):
81        if c != s2[i]:
82            return s1[:i]
83    return s1
84
85# Are two stat buffers (obtained from stat, fstat or lstat)
86# describing the same file?
87def samestat(s1, s2):
88    """Test whether two stat buffers reference the same file"""
89    return (s1.st_ino == s2.st_ino and
90            s1.st_dev == s2.st_dev)
91
92
93# Are two filenames really pointing to the same file?
94def samefile(f1, f2):
95    """Test whether two pathnames reference the same actual file"""
96    s1 = os.stat(f1)
97    s2 = os.stat(f2)
98    return samestat(s1, s2)
99
100
101# Are two open files really referencing the same file?
102# (Not necessarily the same file descriptor!)
103def sameopenfile(fp1, fp2):
104    """Test whether two open file objects reference the same file"""
105    s1 = os.fstat(fp1)
106    s2 = os.fstat(fp2)
107    return samestat(s1, s2)
108
109
110# Split a path in root and extension.
111# The extension is everything starting at the last dot in the last
112# pathname component; the root is everything before that.
113# It is always true that root + ext == p.
114
115# Generic implementation of splitext, to be parametrized with
116# the separators
117def _splitext(p, sep, altsep, extsep):
118    """Split the extension from a pathname.
119
120    Extension is everything from the last dot to the end, ignoring
121    leading dots.  Returns "(root, ext)"; ext may be empty."""
122    # NOTE: This code must work for text and bytes strings.
123
124    sepIndex = p.rfind(sep)
125    if altsep:
126        altsepIndex = p.rfind(altsep)
127        sepIndex = max(sepIndex, altsepIndex)
128
129    dotIndex = p.rfind(extsep)
130    if dotIndex > sepIndex:
131        # skip all leading dots
132        filenameIndex = sepIndex + 1
133        while filenameIndex < dotIndex:
134            if p[filenameIndex:filenameIndex+1] != extsep:
135                return p[:dotIndex], p[dotIndex:]
136            filenameIndex += 1
137
138    return p, p[:0]
139
140def _check_arg_types(funcname, *args):
141    hasstr = hasbytes = False
142    for s in args:
143        if isinstance(s, str):
144            hasstr = True
145        elif isinstance(s, bytes):
146            hasbytes = True
147        else:
148            raise TypeError('%s() argument must be str or bytes, not %r' %
149                            (funcname, s.__class__.__name__)) from None
150    if hasstr and hasbytes:
151        raise TypeError("Can't mix strings and bytes in path components") from None
152