+++ /dev/null
-"""Common operations on Posix pathnames.\r
-\r
-Instead of importing this module directly, import os and refer to\r
-this module as os.path. The "os.path" name is an alias for this\r
-module on Posix systems; on other systems (e.g. Mac, Windows),\r
-os.path provides the same operations in a manner specific to that\r
-platform, and is an alias to another module (e.g. macpath, ntpath).\r
-\r
-Some of this can actually be useful on non-Posix systems too, e.g.\r
-for manipulation of the pathname component of URLs.\r
-"""\r
-\r
-import os\r
-import sys\r
-import stat\r
-import genericpath\r
-import warnings\r
-from genericpath import *\r
-\r
-__all__ = ["normcase","isabs","join","splitdrive","split","splitext",\r
- "basename","dirname","commonprefix","getsize","getmtime",\r
- "getatime","getctime","islink","exists","lexists","isdir","isfile",\r
- "ismount","walk","expanduser","expandvars","normpath","abspath",\r
- "samefile","sameopenfile","samestat",\r
- "curdir","pardir","sep","pathsep","defpath","altsep","extsep",\r
- "devnull","realpath","supports_unicode_filenames","relpath"]\r
-\r
-# strings representing various path-related bits and pieces\r
-curdir = '.'\r
-pardir = '..'\r
-extsep = '.'\r
-sep = '/'\r
-pathsep = ':'\r
-defpath = ':/bin:/usr/bin'\r
-altsep = None\r
-devnull = '/dev/null'\r
-\r
-# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.\r
-# On MS-DOS this may also turn slashes into backslashes; however, other\r
-# normalizations (such as optimizing '../' away) are not allowed\r
-# (another function should be defined to do that).\r
-\r
-def normcase(s):\r
- """Normalize case of pathname. Has no effect under Posix"""\r
- return s\r
-\r
-\r
-# Return whether a path is absolute.\r
-# Trivial in Posix, harder on the Mac or MS-DOS.\r
-\r
-def isabs(s):\r
- """Test whether a path is absolute"""\r
- return s.startswith('/')\r
-\r
-\r
-# Join pathnames.\r
-# Ignore the previous parts if a part is absolute.\r
-# Insert a '/' unless the first part is empty or already ends in '/'.\r
-\r
-def join(a, *p):\r
- """Join two or more pathname components, inserting '/' as needed.\r
- If any component is an absolute path, all previous path components\r
- will be discarded."""\r
- path = a\r
- for b in p:\r
- if b.startswith('/'):\r
- path = b\r
- elif path == '' or path.endswith('/'):\r
- path += b\r
- else:\r
- path += '/' + b\r
- return path\r
-\r
-\r
-# Split a path in head (everything up to the last '/') and tail (the\r
-# rest). If the path ends in '/', tail will be empty. If there is no\r
-# '/' in the path, head will be empty.\r
-# Trailing '/'es are stripped from head unless it is the root.\r
-\r
-def split(p):\r
- """Split a pathname. Returns tuple "(head, tail)" where "tail" is\r
- everything after the final slash. Either part may be empty."""\r
- i = p.rfind('/') + 1\r
- head, tail = p[:i], p[i:]\r
- if head and head != '/'*len(head):\r
- head = head.rstrip('/')\r
- return head, tail\r
-\r
-\r
-# Split a path in root and extension.\r
-# The extension is everything starting at the last dot in the last\r
-# pathname component; the root is everything before that.\r
-# It is always true that root + ext == p.\r
-\r
-def splitext(p):\r
- return genericpath._splitext(p, sep, altsep, extsep)\r
-splitext.__doc__ = genericpath._splitext.__doc__\r
-\r
-# Split a pathname into a drive specification and the rest of the\r
-# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.\r
-\r
-def splitdrive(p):\r
- """Split a pathname into drive and path. On Posix, drive is always\r
- empty."""\r
- return '', p\r
-\r
-\r
-# Return the tail (basename) part of a path, same as split(path)[1].\r
-\r
-def basename(p):\r
- """Returns the final component of a pathname"""\r
- i = p.rfind('/') + 1\r
- return p[i:]\r
-\r
-\r
-# Return the head (dirname) part of a path, same as split(path)[0].\r
-\r
-def dirname(p):\r
- """Returns the directory component of a pathname"""\r
- i = p.rfind('/') + 1\r
- head = p[:i]\r
- if head and head != '/'*len(head):\r
- head = head.rstrip('/')\r
- return head\r
-\r
-\r
-# Is a path a symbolic link?\r
-# This will always return false on systems where os.lstat doesn't exist.\r
-\r
-def islink(path):\r
- """Test whether a path is a symbolic link"""\r
- try:\r
- st = os.lstat(path)\r
- except (os.error, AttributeError):\r
- return False\r
- return stat.S_ISLNK(st.st_mode)\r
-\r
-# Being true for dangling symbolic links is also useful.\r
-\r
-def lexists(path):\r
- """Test whether a path exists. Returns True for broken symbolic links"""\r
- try:\r
- os.lstat(path)\r
- except os.error:\r
- return False\r
- return True\r
-\r
-\r
-# Are two filenames really pointing to the same file?\r
-\r
-def samefile(f1, f2):\r
- """Test whether two pathnames reference the same actual file"""\r
- s1 = os.stat(f1)\r
- s2 = os.stat(f2)\r
- return samestat(s1, s2)\r
-\r
-\r
-# Are two open files really referencing the same file?\r
-# (Not necessarily the same file descriptor!)\r
-\r
-def sameopenfile(fp1, fp2):\r
- """Test whether two open file objects reference the same file"""\r
- s1 = os.fstat(fp1)\r
- s2 = os.fstat(fp2)\r
- return samestat(s1, s2)\r
-\r
-\r
-# Are two stat buffers (obtained from stat, fstat or lstat)\r
-# describing the same file?\r
-\r
-def samestat(s1, s2):\r
- """Test whether two stat buffers reference the same file"""\r
- return s1.st_ino == s2.st_ino and \\r
- s1.st_dev == s2.st_dev\r
-\r
-\r
-# Is a path a mount point?\r
-# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)\r
-\r
-def ismount(path):\r
- """Test whether a path is a mount point"""\r
- if islink(path):\r
- # A symlink can never be a mount point\r
- return False\r
- try:\r
- s1 = os.lstat(path)\r
- s2 = os.lstat(join(path, '..'))\r
- except os.error:\r
- return False # It doesn't exist -- so not a mount point :-)\r
- dev1 = s1.st_dev\r
- dev2 = s2.st_dev\r
- if dev1 != dev2:\r
- return True # path/.. on a different device as path\r
- ino1 = s1.st_ino\r
- ino2 = s2.st_ino\r
- if ino1 == ino2:\r
- return True # path/.. is the same i-node as path\r
- return False\r
-\r
-\r
-# Directory tree walk.\r
-# For each directory under top (including top itself, but excluding\r
-# '.' and '..'), func(arg, dirname, filenames) is called, where\r
-# dirname is the name of the directory and filenames is the list\r
-# of files (and subdirectories etc.) in the directory.\r
-# The func may modify the filenames list, to implement a filter,\r
-# or to impose a different order of visiting.\r
-\r
-def walk(top, func, arg):\r
- """Directory tree walk with callback function.\r
-\r
- For each directory in the directory tree rooted at top (including top\r
- itself, but excluding '.' and '..'), call func(arg, dirname, fnames).\r
- dirname is the name of the directory, and fnames a list of the names of\r
- the files and subdirectories in dirname (excluding '.' and '..'). func\r
- may modify the fnames list in-place (e.g. via del or slice assignment),\r
- and walk will only recurse into the subdirectories whose names remain in\r
- fnames; this can be used to implement a filter, or to impose a specific\r
- order of visiting. No semantics are defined for, or required of, arg,\r
- beyond that arg is always passed to func. It can be used, e.g., to pass\r
- a filename pattern, or a mutable object designed to accumulate\r
- statistics. Passing None for arg is common."""\r
- warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.",\r
- stacklevel=2)\r
- try:\r
- names = os.listdir(top)\r
- except os.error:\r
- return\r
- func(arg, top, names)\r
- for name in names:\r
- name = join(top, name)\r
- try:\r
- st = os.lstat(name)\r
- except os.error:\r
- continue\r
- if stat.S_ISDIR(st.st_mode):\r
- walk(name, func, arg)\r
-\r
-\r
-# Expand paths beginning with '~' or '~user'.\r
-# '~' means $HOME; '~user' means that user's home directory.\r
-# If the path doesn't begin with '~', or if the user or $HOME is unknown,\r
-# the path is returned unchanged (leaving error reporting to whatever\r
-# function is called with the expanded path as argument).\r
-# See also module 'glob' for expansion of *, ? and [...] in pathnames.\r
-# (A function should also be defined to do full *sh-style environment\r
-# variable expansion.)\r
-\r
-def expanduser(path):\r
- """Expand ~ and ~user constructions. If user or $HOME is unknown,\r
- do nothing."""\r
- if not path.startswith('~'):\r
- return path\r
- i = path.find('/', 1)\r
- if i < 0:\r
- i = len(path)\r
- if i == 1:\r
- if 'HOME' not in os.environ:\r
- import pwd\r
- userhome = pwd.getpwuid(os.getuid()).pw_dir\r
- else:\r
- userhome = os.environ['HOME']\r
- else:\r
- import pwd\r
- try:\r
- pwent = pwd.getpwnam(path[1:i])\r
- except KeyError:\r
- return path\r
- userhome = pwent.pw_dir\r
- userhome = userhome.rstrip('/') or userhome\r
- return userhome + path[i:]\r
-\r
-\r
-# Expand paths containing shell variable substitutions.\r
-# This expands the forms $variable and ${variable} only.\r
-# Non-existent variables are left unchanged.\r
-\r
-_varprog = None\r
-\r
-def expandvars(path):\r
- """Expand shell variables of form $var and ${var}. Unknown variables\r
- are left unchanged."""\r
- global _varprog\r
- if '$' not in path:\r
- return path\r
- if not _varprog:\r
- import re\r
- _varprog = re.compile(r'\$(\w+|\{[^}]*\})')\r
- i = 0\r
- while True:\r
- m = _varprog.search(path, i)\r
- if not m:\r
- break\r
- i, j = m.span(0)\r
- name = m.group(1)\r
- if name.startswith('{') and name.endswith('}'):\r
- name = name[1:-1]\r
- if name in os.environ:\r
- tail = path[j:]\r
- path = path[:i] + os.environ[name]\r
- i = len(path)\r
- path += tail\r
- else:\r
- i = j\r
- return path\r
-\r
-\r
-# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.\r
-# It should be understood that this may change the meaning of the path\r
-# if it contains symbolic links!\r
-\r
-def normpath(path):\r
- """Normalize path, eliminating double slashes, etc."""\r
- # Preserve unicode (if path is unicode)\r
- slash, dot = (u'/', u'.') if isinstance(path, unicode) else ('/', '.')\r
- if path == '':\r
- return dot\r
- initial_slashes = path.startswith('/')\r
- # POSIX allows one or two initial slashes, but treats three or more\r
- # as single slash.\r
- if (initial_slashes and\r
- path.startswith('//') and not path.startswith('///')):\r
- initial_slashes = 2\r
- comps = path.split('/')\r
- new_comps = []\r
- for comp in comps:\r
- if comp in ('', '.'):\r
- continue\r
- if (comp != '..' or (not initial_slashes and not new_comps) or\r
- (new_comps and new_comps[-1] == '..')):\r
- new_comps.append(comp)\r
- elif new_comps:\r
- new_comps.pop()\r
- comps = new_comps\r
- path = slash.join(comps)\r
- if initial_slashes:\r
- path = slash*initial_slashes + path\r
- return path or dot\r
-\r
-\r
-def abspath(path):\r
- """Return an absolute path."""\r
- if not isabs(path):\r
- if isinstance(path, unicode):\r
- cwd = os.getcwdu()\r
- else:\r
- cwd = os.getcwd()\r
- path = join(cwd, path)\r
- return normpath(path)\r
-\r
-\r
-# Return a canonical path (i.e. the absolute location of a file on the\r
-# filesystem).\r
-\r
-def realpath(filename):\r
- """Return the canonical path of the specified filename, eliminating any\r
-symbolic links encountered in the path."""\r
- if isabs(filename):\r
- bits = ['/'] + filename.split('/')[1:]\r
- else:\r
- bits = [''] + filename.split('/')\r
-\r
- for i in range(2, len(bits)+1):\r
- component = join(*bits[0:i])\r
- # Resolve symbolic links.\r
- if islink(component):\r
- resolved = _resolve_link(component)\r
- if resolved is None:\r
- # Infinite loop -- return original component + rest of the path\r
- return abspath(join(*([component] + bits[i:])))\r
- else:\r
- newpath = join(*([resolved] + bits[i:]))\r
- return realpath(newpath)\r
-\r
- return abspath(filename)\r
-\r
-\r
-def _resolve_link(path):\r
- """Internal helper function. Takes a path and follows symlinks\r
- until we either arrive at something that isn't a symlink, or\r
- encounter a path we've seen before (meaning that there's a loop).\r
- """\r
- paths_seen = set()\r
- while islink(path):\r
- if path in paths_seen:\r
- # Already seen this path, so we must have a symlink loop\r
- return None\r
- paths_seen.add(path)\r
- # Resolve where the link points to\r
- resolved = os.readlink(path)\r
- if not isabs(resolved):\r
- dir = dirname(path)\r
- path = normpath(join(dir, resolved))\r
- else:\r
- path = normpath(resolved)\r
- return path\r
-\r
-supports_unicode_filenames = (sys.platform == 'darwin')\r
-\r
-def relpath(path, start=curdir):\r
- """Return a relative version of a path"""\r
-\r
- if not path:\r
- raise ValueError("no path specified")\r
-\r
- start_list = [x for x in abspath(start).split(sep) if x]\r
- path_list = [x for x in abspath(path).split(sep) if x]\r
-\r
- # Work out how much of the filepath is shared by start and path.\r
- i = len(commonprefix([start_list, path_list]))\r
-\r
- rel_list = [pardir] * (len(start_list)-i) + path_list[i:]\r
- if not rel_list:\r
- return curdir\r
- return join(*rel_list)\r