ยปCore Development>Code coverage>Lib/posixpath.py

Python code coverage for Lib/posixpath.py

#countcontent
1n/a"""Common operations on Posix pathnames.
2n/a
3n/aInstead of importing this module directly, import os and refer to
4n/athis module as os.path. The "os.path" name is an alias for this
5n/amodule on Posix systems; on other systems (e.g. Mac, Windows),
6n/aos.path provides the same operations in a manner specific to that
7n/aplatform, and is an alias to another module (e.g. macpath, ntpath).
8n/a
9n/aSome of this can actually be useful on non-Posix systems too, e.g.
10n/afor manipulation of the pathname component of URLs.
11n/a"""
12n/a
13n/aimport os
14n/aimport sys
15n/aimport stat
16n/aimport genericpath
17n/afrom genericpath import *
18n/a
19n/a__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
20n/a "basename","dirname","commonprefix","getsize","getmtime",
21n/a "getatime","getctime","islink","exists","lexists","isdir","isfile",
22n/a "ismount", "expanduser","expandvars","normpath","abspath",
23n/a "samefile","sameopenfile","samestat",
24n/a "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
25n/a "devnull","realpath","supports_unicode_filenames","relpath",
26n/a "commonpath"]
27n/a
28n/a# Strings representing various path-related bits and pieces.
29n/a# These are primarily for export; internally, they are hardcoded.
30n/acurdir = '.'
31n/apardir = '..'
32n/aextsep = '.'
33n/asep = '/'
34n/apathsep = ':'
35n/adefpath = ':/bin:/usr/bin'
36n/aaltsep = None
37n/adevnull = '/dev/null'
38n/a
39n/adef _get_sep(path):
40n/a if isinstance(path, bytes):
41n/a return b'/'
42n/a else:
43n/a return '/'
44n/a
45n/a# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
46n/a# On MS-DOS this may also turn slashes into backslashes; however, other
47n/a# normalizations (such as optimizing '../' away) are not allowed
48n/a# (another function should be defined to do that).
49n/a
50n/adef normcase(s):
51n/a """Normalize case of pathname. Has no effect under Posix"""
52n/a s = os.fspath(s)
53n/a if not isinstance(s, (bytes, str)):
54n/a raise TypeError("normcase() argument must be str or bytes, "
55n/a "not '{}'".format(s.__class__.__name__))
56n/a return s
57n/a
58n/a
59n/a# Return whether a path is absolute.
60n/a# Trivial in Posix, harder on the Mac or MS-DOS.
61n/a
62n/adef isabs(s):
63n/a """Test whether a path is absolute"""
64n/a s = os.fspath(s)
65n/a sep = _get_sep(s)
66n/a return s.startswith(sep)
67n/a
68n/a
69n/a# Join pathnames.
70n/a# Ignore the previous parts if a part is absolute.
71n/a# Insert a '/' unless the first part is empty or already ends in '/'.
72n/a
73n/adef join(a, *p):
74n/a """Join two or more pathname components, inserting '/' as needed.
75n/a If any component is an absolute path, all previous path components
76n/a will be discarded. An empty last part will result in a path that
77n/a ends with a separator."""
78n/a a = os.fspath(a)
79n/a sep = _get_sep(a)
80n/a path = a
81n/a try:
82n/a if not p:
83n/a path[:0] + sep #23780: Ensure compatible data type even if p is null.
84n/a for b in map(os.fspath, p):
85n/a if b.startswith(sep):
86n/a path = b
87n/a elif not path or path.endswith(sep):
88n/a path += b
89n/a else:
90n/a path += sep + b
91n/a except (TypeError, AttributeError, BytesWarning):
92n/a genericpath._check_arg_types('join', a, *p)
93n/a raise
94n/a return path
95n/a
96n/a
97n/a# Split a path in head (everything up to the last '/') and tail (the
98n/a# rest). If the path ends in '/', tail will be empty. If there is no
99n/a# '/' in the path, head will be empty.
100n/a# Trailing '/'es are stripped from head unless it is the root.
101n/a
102n/adef split(p):
103n/a """Split a pathname. Returns tuple "(head, tail)" where "tail" is
104n/a everything after the final slash. Either part may be empty."""
105n/a p = os.fspath(p)
106n/a sep = _get_sep(p)
107n/a i = p.rfind(sep) + 1
108n/a head, tail = p[:i], p[i:]
109n/a if head and head != sep*len(head):
110n/a head = head.rstrip(sep)
111n/a return head, tail
112n/a
113n/a
114n/a# Split a path in root and extension.
115n/a# The extension is everything starting at the last dot in the last
116n/a# pathname component; the root is everything before that.
117n/a# It is always true that root + ext == p.
118n/a
119n/adef splitext(p):
120n/a p = os.fspath(p)
121n/a if isinstance(p, bytes):
122n/a sep = b'/'
123n/a extsep = b'.'
124n/a else:
125n/a sep = '/'
126n/a extsep = '.'
127n/a return genericpath._splitext(p, sep, None, extsep)
128n/asplitext.__doc__ = genericpath._splitext.__doc__
129n/a
130n/a# Split a pathname into a drive specification and the rest of the
131n/a# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
132n/a
133n/adef splitdrive(p):
134n/a """Split a pathname into drive and path. On Posix, drive is always
135n/a empty."""
136n/a p = os.fspath(p)
137n/a return p[:0], p
138n/a
139n/a
140n/a# Return the tail (basename) part of a path, same as split(path)[1].
141n/a
142n/adef basename(p):
143n/a """Returns the final component of a pathname"""
144n/a p = os.fspath(p)
145n/a sep = _get_sep(p)
146n/a i = p.rfind(sep) + 1
147n/a return p[i:]
148n/a
149n/a
150n/a# Return the head (dirname) part of a path, same as split(path)[0].
151n/a
152n/adef dirname(p):
153n/a """Returns the directory component of a pathname"""
154n/a p = os.fspath(p)
155n/a sep = _get_sep(p)
156n/a i = p.rfind(sep) + 1
157n/a head = p[:i]
158n/a if head and head != sep*len(head):
159n/a head = head.rstrip(sep)
160n/a return head
161n/a
162n/a
163n/a# Is a path a symbolic link?
164n/a# This will always return false on systems where os.lstat doesn't exist.
165n/a
166n/adef islink(path):
167n/a """Test whether a path is a symbolic link"""
168n/a try:
169n/a st = os.lstat(path)
170n/a except (OSError, AttributeError):
171n/a return False
172n/a return stat.S_ISLNK(st.st_mode)
173n/a
174n/a# Being true for dangling symbolic links is also useful.
175n/a
176n/adef lexists(path):
177n/a """Test whether a path exists. Returns True for broken symbolic links"""
178n/a try:
179n/a os.lstat(path)
180n/a except OSError:
181n/a return False
182n/a return True
183n/a
184n/a
185n/a# Is a path a mount point?
186n/a# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
187n/a
188n/adef ismount(path):
189n/a """Test whether a path is a mount point"""
190n/a try:
191n/a s1 = os.lstat(path)
192n/a except OSError:
193n/a # It doesn't exist -- so not a mount point. :-)
194n/a return False
195n/a else:
196n/a # A symlink can never be a mount point
197n/a if stat.S_ISLNK(s1.st_mode):
198n/a return False
199n/a
200n/a if isinstance(path, bytes):
201n/a parent = join(path, b'..')
202n/a else:
203n/a parent = join(path, '..')
204n/a parent = realpath(parent)
205n/a try:
206n/a s2 = os.lstat(parent)
207n/a except OSError:
208n/a return False
209n/a
210n/a dev1 = s1.st_dev
211n/a dev2 = s2.st_dev
212n/a if dev1 != dev2:
213n/a return True # path/.. on a different device as path
214n/a ino1 = s1.st_ino
215n/a ino2 = s2.st_ino
216n/a if ino1 == ino2:
217n/a return True # path/.. is the same i-node as path
218n/a return False
219n/a
220n/a
221n/a# Expand paths beginning with '~' or '~user'.
222n/a# '~' means $HOME; '~user' means that user's home directory.
223n/a# If the path doesn't begin with '~', or if the user or $HOME is unknown,
224n/a# the path is returned unchanged (leaving error reporting to whatever
225n/a# function is called with the expanded path as argument).
226n/a# See also module 'glob' for expansion of *, ? and [...] in pathnames.
227n/a# (A function should also be defined to do full *sh-style environment
228n/a# variable expansion.)
229n/a
230n/adef expanduser(path):
231n/a """Expand ~ and ~user constructions. If user or $HOME is unknown,
232n/a do nothing."""
233n/a path = os.fspath(path)
234n/a if isinstance(path, bytes):
235n/a tilde = b'~'
236n/a else:
237n/a tilde = '~'
238n/a if not path.startswith(tilde):
239n/a return path
240n/a sep = _get_sep(path)
241n/a i = path.find(sep, 1)
242n/a if i < 0:
243n/a i = len(path)
244n/a if i == 1:
245n/a if 'HOME' not in os.environ:
246n/a import pwd
247n/a userhome = pwd.getpwuid(os.getuid()).pw_dir
248n/a else:
249n/a userhome = os.environ['HOME']
250n/a else:
251n/a import pwd
252n/a name = path[1:i]
253n/a if isinstance(name, bytes):
254n/a name = str(name, 'ASCII')
255n/a try:
256n/a pwent = pwd.getpwnam(name)
257n/a except KeyError:
258n/a return path
259n/a userhome = pwent.pw_dir
260n/a if isinstance(path, bytes):
261n/a userhome = os.fsencode(userhome)
262n/a root = b'/'
263n/a else:
264n/a root = '/'
265n/a userhome = userhome.rstrip(root)
266n/a return (userhome + path[i:]) or root
267n/a
268n/a
269n/a# Expand paths containing shell variable substitutions.
270n/a# This expands the forms $variable and ${variable} only.
271n/a# Non-existent variables are left unchanged.
272n/a
273n/a_varprog = None
274n/a_varprogb = None
275n/a
276n/adef expandvars(path):
277n/a """Expand shell variables of form $var and ${var}. Unknown variables
278n/a are left unchanged."""
279n/a path = os.fspath(path)
280n/a global _varprog, _varprogb
281n/a if isinstance(path, bytes):
282n/a if b'$' not in path:
283n/a return path
284n/a if not _varprogb:
285n/a import re
286n/a _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
287n/a search = _varprogb.search
288n/a start = b'{'
289n/a end = b'}'
290n/a environ = getattr(os, 'environb', None)
291n/a else:
292n/a if '$' not in path:
293n/a return path
294n/a if not _varprog:
295n/a import re
296n/a _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
297n/a search = _varprog.search
298n/a start = '{'
299n/a end = '}'
300n/a environ = os.environ
301n/a i = 0
302n/a while True:
303n/a m = search(path, i)
304n/a if not m:
305n/a break
306n/a i, j = m.span(0)
307n/a name = m.group(1)
308n/a if name.startswith(start) and name.endswith(end):
309n/a name = name[1:-1]
310n/a try:
311n/a if environ is None:
312n/a value = os.fsencode(os.environ[os.fsdecode(name)])
313n/a else:
314n/a value = environ[name]
315n/a except KeyError:
316n/a i = j
317n/a else:
318n/a tail = path[j:]
319n/a path = path[:i] + value
320n/a i = len(path)
321n/a path += tail
322n/a return path
323n/a
324n/a
325n/a# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
326n/a# It should be understood that this may change the meaning of the path
327n/a# if it contains symbolic links!
328n/a
329n/adef normpath(path):
330n/a """Normalize path, eliminating double slashes, etc."""
331n/a path = os.fspath(path)
332n/a if isinstance(path, bytes):
333n/a sep = b'/'
334n/a empty = b''
335n/a dot = b'.'
336n/a dotdot = b'..'
337n/a else:
338n/a sep = '/'
339n/a empty = ''
340n/a dot = '.'
341n/a dotdot = '..'
342n/a if path == empty:
343n/a return dot
344n/a initial_slashes = path.startswith(sep)
345n/a # POSIX allows one or two initial slashes, but treats three or more
346n/a # as single slash.
347n/a if (initial_slashes and
348n/a path.startswith(sep*2) and not path.startswith(sep*3)):
349n/a initial_slashes = 2
350n/a comps = path.split(sep)
351n/a new_comps = []
352n/a for comp in comps:
353n/a if comp in (empty, dot):
354n/a continue
355n/a if (comp != dotdot or (not initial_slashes and not new_comps) or
356n/a (new_comps and new_comps[-1] == dotdot)):
357n/a new_comps.append(comp)
358n/a elif new_comps:
359n/a new_comps.pop()
360n/a comps = new_comps
361n/a path = sep.join(comps)
362n/a if initial_slashes:
363n/a path = sep*initial_slashes + path
364n/a return path or dot
365n/a
366n/a
367n/adef abspath(path):
368n/a """Return an absolute path."""
369n/a path = os.fspath(path)
370n/a if not isabs(path):
371n/a if isinstance(path, bytes):
372n/a cwd = os.getcwdb()
373n/a else:
374n/a cwd = os.getcwd()
375n/a path = join(cwd, path)
376n/a return normpath(path)
377n/a
378n/a
379n/a# Return a canonical path (i.e. the absolute location of a file on the
380n/a# filesystem).
381n/a
382n/adef realpath(filename):
383n/a """Return the canonical path of the specified filename, eliminating any
384n/asymbolic links encountered in the path."""
385n/a filename = os.fspath(filename)
386n/a path, ok = _joinrealpath(filename[:0], filename, {})
387n/a return abspath(path)
388n/a
389n/a# Join two paths, normalizing and eliminating any symbolic links
390n/a# encountered in the second path.
391n/adef _joinrealpath(path, rest, seen):
392n/a if isinstance(path, bytes):
393n/a sep = b'/'
394n/a curdir = b'.'
395n/a pardir = b'..'
396n/a else:
397n/a sep = '/'
398n/a curdir = '.'
399n/a pardir = '..'
400n/a
401n/a if isabs(rest):
402n/a rest = rest[1:]
403n/a path = sep
404n/a
405n/a while rest:
406n/a name, _, rest = rest.partition(sep)
407n/a if not name or name == curdir:
408n/a # current dir
409n/a continue
410n/a if name == pardir:
411n/a # parent dir
412n/a if path:
413n/a path, name = split(path)
414n/a if name == pardir:
415n/a path = join(path, pardir, pardir)
416n/a else:
417n/a path = pardir
418n/a continue
419n/a newpath = join(path, name)
420n/a if not islink(newpath):
421n/a path = newpath
422n/a continue
423n/a # Resolve the symbolic link
424n/a if newpath in seen:
425n/a # Already seen this path
426n/a path = seen[newpath]
427n/a if path is not None:
428n/a # use cached value
429n/a continue
430n/a # The symlink is not resolved, so we must have a symlink loop.
431n/a # Return already resolved part + rest of the path unchanged.
432n/a return join(newpath, rest), False
433n/a seen[newpath] = None # not resolved symlink
434n/a path, ok = _joinrealpath(path, os.readlink(newpath), seen)
435n/a if not ok:
436n/a return join(path, rest), False
437n/a seen[newpath] = path # resolved symlink
438n/a
439n/a return path, True
440n/a
441n/a
442n/asupports_unicode_filenames = (sys.platform == 'darwin')
443n/a
444n/adef relpath(path, start=None):
445n/a """Return a relative version of a path"""
446n/a
447n/a if not path:
448n/a raise ValueError("no path specified")
449n/a
450n/a path = os.fspath(path)
451n/a if isinstance(path, bytes):
452n/a curdir = b'.'
453n/a sep = b'/'
454n/a pardir = b'..'
455n/a else:
456n/a curdir = '.'
457n/a sep = '/'
458n/a pardir = '..'
459n/a
460n/a if start is None:
461n/a start = curdir
462n/a else:
463n/a start = os.fspath(start)
464n/a
465n/a try:
466n/a start_list = [x for x in abspath(start).split(sep) if x]
467n/a path_list = [x for x in abspath(path).split(sep) if x]
468n/a # Work out how much of the filepath is shared by start and path.
469n/a i = len(commonprefix([start_list, path_list]))
470n/a
471n/a rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
472n/a if not rel_list:
473n/a return curdir
474n/a return join(*rel_list)
475n/a except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
476n/a genericpath._check_arg_types('relpath', path, start)
477n/a raise
478n/a
479n/a
480n/a# Return the longest common sub-path of the sequence of paths given as input.
481n/a# The paths are not normalized before comparing them (this is the
482n/a# responsibility of the caller). Any trailing separator is stripped from the
483n/a# returned path.
484n/a
485n/adef commonpath(paths):
486n/a """Given a sequence of path names, returns the longest common sub-path."""
487n/a
488n/a if not paths:
489n/a raise ValueError('commonpath() arg is an empty sequence')
490n/a
491n/a paths = tuple(map(os.fspath, paths))
492n/a if isinstance(paths[0], bytes):
493n/a sep = b'/'
494n/a curdir = b'.'
495n/a else:
496n/a sep = '/'
497n/a curdir = '.'
498n/a
499n/a try:
500n/a split_paths = [path.split(sep) for path in paths]
501n/a
502n/a try:
503n/a isabs, = set(p[:1] == sep for p in paths)
504n/a except ValueError:
505n/a raise ValueError("Can't mix absolute and relative paths") from None
506n/a
507n/a split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
508n/a s1 = min(split_paths)
509n/a s2 = max(split_paths)
510n/a common = s1
511n/a for i, c in enumerate(s1):
512n/a if c != s2[i]:
513n/a common = s1[:i]
514n/a break
515n/a
516n/a prefix = sep if isabs else sep[:0]
517n/a return prefix + sep.join(common)
518n/a except (TypeError, AttributeError):
519n/a genericpath._check_arg_types('commonpath', *paths)
520n/a raise