| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame] | 1 | """Common operations on Posix pathnames. | 
 | 2 |  | 
 | 3 | Instead of importing this module directly, import os and refer to | 
 | 4 | this module as os.path.  The "os.path" name is an alias for this | 
 | 5 | module on Posix systems; on other systems (e.g. Mac, Windows), | 
 | 6 | os.path provides the same operations in a manner specific to that | 
 | 7 | platform, and is an alias to another module (e.g. macpath, ntpath). | 
 | 8 |  | 
 | 9 | Some of this can actually be useful on non-Posix systems too, e.g. | 
 | 10 | for manipulation of the pathname component of URLs. | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 11 | """ | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 12 |  | 
| Guido van Rossum | d3876d3 | 1996-07-23 03:47:28 +0000 | [diff] [blame] | 13 | import os | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 14 | import sys | 
| Guido van Rossum | 40d9304 | 1990-10-21 16:17:34 +0000 | [diff] [blame] | 15 | import stat | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 16 | import genericpath | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 17 | from genericpath import * | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 18 |  | 
| Skip Montanaro | c62c81e | 2001-02-12 02:00:42 +0000 | [diff] [blame] | 19 | __all__ = ["normcase","isabs","join","splitdrive","split","splitext", | 
 | 20 |            "basename","dirname","commonprefix","getsize","getmtime", | 
| Georg Brandl | f0de6a1 | 2005-08-22 18:02:59 +0000 | [diff] [blame] | 21 |            "getatime","getctime","islink","exists","lexists","isdir","isfile", | 
| Benjamin Peterson | d71ca41 | 2008-05-08 23:44:58 +0000 | [diff] [blame] | 22 |            "ismount", "expanduser","expandvars","normpath","abspath", | 
| Neal Norwitz | 61cdac6 | 2003-01-03 18:01:57 +0000 | [diff] [blame] | 23 |            "samefile","sameopenfile","samestat", | 
| Skip Montanaro | 117910d | 2003-02-14 19:35:31 +0000 | [diff] [blame] | 24 |            "curdir","pardir","sep","pathsep","defpath","altsep","extsep", | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 25 |            "devnull","realpath","supports_unicode_filenames","relpath"] | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 26 |  | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 27 | # Strings representing various path-related bits and pieces. | 
 | 28 | # These are primarily for export; internally, they are hardcoded. | 
| Skip Montanaro | 117910d | 2003-02-14 19:35:31 +0000 | [diff] [blame] | 29 | curdir = '.' | 
 | 30 | pardir = '..' | 
 | 31 | extsep = '.' | 
 | 32 | sep = '/' | 
 | 33 | pathsep = ':' | 
 | 34 | defpath = ':/bin:/usr/bin' | 
 | 35 | altsep = None | 
| Martin v. Löwis | bdec50f | 2004-06-08 08:29:33 +0000 | [diff] [blame] | 36 | devnull = '/dev/null' | 
| Skip Montanaro | 117910d | 2003-02-14 19:35:31 +0000 | [diff] [blame] | 37 |  | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 38 | def _get_sep(path): | 
 | 39 |     if isinstance(path, bytes): | 
 | 40 |         return b'/' | 
 | 41 |     else: | 
 | 42 |         return '/' | 
 | 43 |  | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 44 | # Normalize the case of a pathname.  Trivial in Posix, string.lower on Mac. | 
 | 45 | # On MS-DOS this may also turn slashes into backslashes; however, other | 
 | 46 | # normalizations (such as optimizing '../' away) are not allowed | 
 | 47 | # (another function should be defined to do that). | 
 | 48 |  | 
 | 49 | def normcase(s): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 50 |     """Normalize case of pathname.  Has no effect under Posix""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 51 |     # TODO: on Mac OS X, this should really return s.lower(). | 
| Ezio Melotti | 5a3ef5b | 2010-06-25 10:56:11 +0000 | [diff] [blame] | 52 |     if not isinstance(s, (bytes, str)): | 
 | 53 |         raise TypeError("normcase() argument must be str or bytes, " | 
 | 54 |                         "not '{}'".format(s.__class__.__name__)) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 55 |     return s | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 56 |  | 
 | 57 |  | 
| Jeremy Hylton | a05e293 | 2000-06-28 14:48:01 +0000 | [diff] [blame] | 58 | # Return whether a path is absolute. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 59 | # Trivial in Posix, harder on the Mac or MS-DOS. | 
 | 60 |  | 
 | 61 | def isabs(s): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 62 |     """Test whether a path is absolute""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 63 |     sep = _get_sep(s) | 
 | 64 |     return s.startswith(sep) | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 65 |  | 
 | 66 |  | 
| Barry Warsaw | 384d249 | 1997-02-18 21:53:25 +0000 | [diff] [blame] | 67 | # Join pathnames. | 
 | 68 | # Ignore the previous parts if a part is absolute. | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 69 | # Insert a '/' unless the first part is empty or already ends in '/'. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 70 |  | 
| Barry Warsaw | 384d249 | 1997-02-18 21:53:25 +0000 | [diff] [blame] | 71 | def join(a, *p): | 
| Guido van Rossum | 04110fb | 2007-08-24 16:32:05 +0000 | [diff] [blame] | 72 |     """Join two or more pathname components, inserting '/' as needed. | 
 | 73 |     If any component is an absolute path, all previous path components | 
| R David Murray | e3de175 | 2012-07-21 14:33:56 -0400 | [diff] [blame] | 74 |     will be discarded.  An empty last part will result in a path that | 
 | 75 |     ends with a separator.""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 76 |     sep = _get_sep(a) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 77 |     path = a | 
| Hynek Schlawack | 4774946 | 2012-07-15 16:21:30 +0200 | [diff] [blame] | 78 |     try: | 
 | 79 |         for b in p: | 
 | 80 |             if b.startswith(sep): | 
 | 81 |                 path = b | 
 | 82 |             elif not path or path.endswith(sep): | 
 | 83 |                 path += b | 
 | 84 |             else: | 
 | 85 |                 path += sep + b | 
 | 86 |     except TypeError: | 
| Hynek Schlawack | c5a4566 | 2012-07-17 13:05:43 +0200 | [diff] [blame] | 87 |         valid_types = all(isinstance(s, (str, bytes, bytearray)) | 
 | 88 |                           for s in (a, ) + p) | 
 | 89 |         if valid_types: | 
 | 90 |             # Must have a mixture of text and binary data | 
| Hynek Schlawack | 9ac4d88 | 2012-07-15 16:46:23 +0200 | [diff] [blame] | 91 |             raise TypeError("Can't mix strings and bytes in path " | 
 | 92 |                             "components.") from None | 
| Hynek Schlawack | c5a4566 | 2012-07-17 13:05:43 +0200 | [diff] [blame] | 93 |         raise | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 94 |     return path | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 95 |  | 
 | 96 |  | 
| Guido van Rossum | 2684738 | 1992-03-31 18:54:35 +0000 | [diff] [blame] | 97 | # Split a path in head (everything up to the last '/') and tail (the | 
| Guido van Rossum | a89b1ba | 1995-09-01 20:32:21 +0000 | [diff] [blame] | 98 | # rest).  If the path ends in '/', tail will be empty.  If there is no | 
 | 99 | # '/' in the path, head  will be empty. | 
 | 100 | # Trailing '/'es are stripped from head unless it is the root. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 101 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 102 | def split(p): | 
| Tim Peters | 2344fae | 2001-01-15 00:50:52 +0000 | [diff] [blame] | 103 |     """Split a pathname.  Returns tuple "(head, tail)" where "tail" is | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 104 |     everything after the final slash.  Either part may be empty.""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 105 |     sep = _get_sep(p) | 
 | 106 |     i = p.rfind(sep) + 1 | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 107 |     head, tail = p[:i], p[i:] | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 108 |     if head and head != sep*len(head): | 
 | 109 |         head = head.rstrip(sep) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 110 |     return head, tail | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 111 |  | 
 | 112 |  | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 113 | # Split a path in root and extension. | 
| Guido van Rossum | 422869a | 1996-08-20 20:24:17 +0000 | [diff] [blame] | 114 | # The extension is everything starting at the last dot in the last | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 115 | # pathname component; the root is everything before that. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 116 | # It is always true that root + ext == p. | 
 | 117 |  | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 118 | def splitext(p): | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 119 |     if isinstance(p, bytes): | 
 | 120 |         sep = b'/' | 
 | 121 |         extsep = b'.' | 
 | 122 |     else: | 
 | 123 |         sep = '/' | 
 | 124 |         extsep = '.' | 
 | 125 |     return genericpath._splitext(p, sep, None, extsep) | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 126 | splitext.__doc__ = genericpath._splitext.__doc__ | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 127 |  | 
| Guido van Rossum | 221df24 | 1995-08-07 20:17:55 +0000 | [diff] [blame] | 128 | # Split a pathname into a drive specification and the rest of the | 
 | 129 | # path.  Useful on DOS/Windows/NT; on Unix, the drive is always empty. | 
 | 130 |  | 
 | 131 | def splitdrive(p): | 
| Tim Peters | 2344fae | 2001-01-15 00:50:52 +0000 | [diff] [blame] | 132 |     """Split a pathname into drive and path. On Posix, drive is always | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 133 |     empty.""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 134 |     return p[:0], p | 
| Guido van Rossum | 221df24 | 1995-08-07 20:17:55 +0000 | [diff] [blame] | 135 |  | 
 | 136 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 137 | # Return the tail (basename) part of a path, same as split(path)[1]. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 138 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 139 | def basename(p): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 140 |     """Returns the final component of a pathname""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 141 |     sep = _get_sep(p) | 
 | 142 |     i = p.rfind(sep) + 1 | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 143 |     return p[i:] | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 144 |  | 
 | 145 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 146 | # Return the head (dirname) part of a path, same as split(path)[0]. | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 147 |  | 
 | 148 | def dirname(p): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 149 |     """Returns the directory component of a pathname""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 150 |     sep = _get_sep(p) | 
 | 151 |     i = p.rfind(sep) + 1 | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 152 |     head = p[:i] | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 153 |     if head and head != sep*len(head): | 
 | 154 |         head = head.rstrip(sep) | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 155 |     return head | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 156 |  | 
 | 157 |  | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 158 | # Is a path a symbolic link? | 
| Guido van Rossum | d3876d3 | 1996-07-23 03:47:28 +0000 | [diff] [blame] | 159 | # This will always return false on systems where os.lstat doesn't exist. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 160 |  | 
 | 161 | def islink(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 162 |     """Test whether a path is a symbolic link""" | 
 | 163 |     try: | 
 | 164 |         st = os.lstat(path) | 
| Andrew Svetlov | ad28c7f | 2012-12-18 22:02:39 +0200 | [diff] [blame] | 165 |     except (OSError, AttributeError): | 
| Guido van Rossum | 8ca162f | 2002-04-07 06:36:23 +0000 | [diff] [blame] | 166 |         return False | 
| Raymond Hettinger | 32200ae | 2002-06-01 19:51:15 +0000 | [diff] [blame] | 167 |     return stat.S_ISLNK(st.st_mode) | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 168 |  | 
| Johannes Gijsbers | ae882f7 | 2004-08-30 10:19:56 +0000 | [diff] [blame] | 169 | # Being true for dangling symbolic links is also useful. | 
 | 170 |  | 
 | 171 | def lexists(path): | 
 | 172 |     """Test whether a path exists.  Returns True for broken symbolic links""" | 
 | 173 |     try: | 
| Georg Brandl | 89fad14 | 2010-03-14 10:23:39 +0000 | [diff] [blame] | 174 |         os.lstat(path) | 
| Andrew Svetlov | ad28c7f | 2012-12-18 22:02:39 +0200 | [diff] [blame] | 175 |     except OSError: | 
| Johannes Gijsbers | ae882f7 | 2004-08-30 10:19:56 +0000 | [diff] [blame] | 176 |         return False | 
 | 177 |     return True | 
 | 178 |  | 
 | 179 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 180 | # Is a path a mount point? | 
| Guido van Rossum | d3876d3 | 1996-07-23 03:47:28 +0000 | [diff] [blame] | 181 | # (Does this work for all UNIXes?  Is it even guaranteed to work by Posix?) | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 182 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 183 | def ismount(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 184 |     """Test whether a path is a mount point""" | 
 | 185 |     try: | 
| Christian Heimes | faf2f63 | 2008-01-06 16:59:19 +0000 | [diff] [blame] | 186 |         s1 = os.lstat(path) | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 187 |     except OSError: | 
 | 188 |         # It doesn't exist -- so not a mount point. :-) | 
 | 189 |         return False | 
 | 190 |     else: | 
| Brian Curtin | a3852ff | 2013-07-22 19:05:48 -0500 | [diff] [blame] | 191 |         # A symlink can never be a mount point | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 192 |         if stat.S_ISLNK(s1.st_mode): | 
 | 193 |             return False | 
 | 194 |  | 
 | 195 |     if isinstance(path, bytes): | 
 | 196 |         parent = join(path, b'..') | 
 | 197 |     else: | 
 | 198 |         parent = join(path, '..') | 
 | 199 |     try: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 200 |         s2 = os.lstat(parent) | 
| Andrew Svetlov | ad28c7f | 2012-12-18 22:02:39 +0200 | [diff] [blame] | 201 |     except OSError: | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 202 |         return False | 
 | 203 |  | 
| Raymond Hettinger | 32200ae | 2002-06-01 19:51:15 +0000 | [diff] [blame] | 204 |     dev1 = s1.st_dev | 
 | 205 |     dev2 = s2.st_dev | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 206 |     if dev1 != dev2: | 
| Tim Peters | bc0e910 | 2002-04-04 22:55:58 +0000 | [diff] [blame] | 207 |         return True     # path/.. on a different device as path | 
| Raymond Hettinger | 32200ae | 2002-06-01 19:51:15 +0000 | [diff] [blame] | 208 |     ino1 = s1.st_ino | 
 | 209 |     ino2 = s2.st_ino | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 210 |     if ino1 == ino2: | 
| Tim Peters | bc0e910 | 2002-04-04 22:55:58 +0000 | [diff] [blame] | 211 |         return True     # path/.. is the same i-node as path | 
 | 212 |     return False | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 213 |  | 
 | 214 |  | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 215 | # Expand paths beginning with '~' or '~user'. | 
 | 216 | # '~' means $HOME; '~user' means that user's home directory. | 
 | 217 | # If the path doesn't begin with '~', or if the user or $HOME is unknown, | 
 | 218 | # the path is returned unchanged (leaving error reporting to whatever | 
 | 219 | # function is called with the expanded path as argument). | 
 | 220 | # See also module 'glob' for expansion of *, ? and [...] in pathnames. | 
 | 221 | # (A function should also be defined to do full *sh-style environment | 
 | 222 | # variable expansion.) | 
 | 223 |  | 
 | 224 | def expanduser(path): | 
| Tim Peters | 2344fae | 2001-01-15 00:50:52 +0000 | [diff] [blame] | 225 |     """Expand ~ and ~user constructions.  If user or $HOME is unknown, | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 226 |     do nothing.""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 227 |     if isinstance(path, bytes): | 
 | 228 |         tilde = b'~' | 
 | 229 |     else: | 
 | 230 |         tilde = '~' | 
 | 231 |     if not path.startswith(tilde): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 232 |         return path | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 233 |     sep = _get_sep(path) | 
 | 234 |     i = path.find(sep, 1) | 
| Walter Dörwald | a9da5ae | 2003-06-19 10:21:14 +0000 | [diff] [blame] | 235 |     if i < 0: | 
 | 236 |         i = len(path) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 237 |     if i == 1: | 
| Walter Dörwald | a9da5ae | 2003-06-19 10:21:14 +0000 | [diff] [blame] | 238 |         if 'HOME' not in os.environ: | 
| Neal Norwitz | 609ba81 | 2002-09-05 21:08:25 +0000 | [diff] [blame] | 239 |             import pwd | 
| Walter Dörwald | 77cdeaf | 2003-06-17 13:13:40 +0000 | [diff] [blame] | 240 |             userhome = pwd.getpwuid(os.getuid()).pw_dir | 
| Neal Norwitz | 609ba81 | 2002-09-05 21:08:25 +0000 | [diff] [blame] | 241 |         else: | 
 | 242 |             userhome = os.environ['HOME'] | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 243 |     else: | 
 | 244 |         import pwd | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 245 |         name = path[1:i] | 
 | 246 |         if isinstance(name, bytes): | 
 | 247 |             name = str(name, 'ASCII') | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 248 |         try: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 249 |             pwent = pwd.getpwnam(name) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 250 |         except KeyError: | 
 | 251 |             return path | 
| Walter Dörwald | 77cdeaf | 2003-06-17 13:13:40 +0000 | [diff] [blame] | 252 |         userhome = pwent.pw_dir | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 253 |     if isinstance(path, bytes): | 
| Victor Stinner | 16004ac | 2010-09-29 16:59:18 +0000 | [diff] [blame] | 254 |         userhome = os.fsencode(userhome) | 
| Benjamin Peterson | ef3e4c2 | 2009-04-11 19:48:14 +0000 | [diff] [blame] | 255 |         root = b'/' | 
 | 256 |     else: | 
 | 257 |         root = '/' | 
| Jesus Cea | 7f0d888 | 2012-05-10 05:10:50 +0200 | [diff] [blame] | 258 |     userhome = userhome.rstrip(root) | 
 | 259 |     return (userhome + path[i:]) or root | 
| Guido van Rossum | 4732ccf | 1992-08-09 13:54:50 +0000 | [diff] [blame] | 260 |  | 
 | 261 |  | 
 | 262 | # Expand paths containing shell variable substitutions. | 
| Guido van Rossum | b6775db | 1994-08-01 11:34:53 +0000 | [diff] [blame] | 263 | # This expands the forms $variable and ${variable} only. | 
| Jeremy Hylton | a05e293 | 2000-06-28 14:48:01 +0000 | [diff] [blame] | 264 | # Non-existent variables are left unchanged. | 
| Guido van Rossum | b6775db | 1994-08-01 11:34:53 +0000 | [diff] [blame] | 265 |  | 
 | 266 | _varprog = None | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 267 | _varprogb = None | 
| Guido van Rossum | 4732ccf | 1992-08-09 13:54:50 +0000 | [diff] [blame] | 268 |  | 
 | 269 | def expandvars(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 270 |     """Expand shell variables of form $var and ${var}.  Unknown variables | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 271 |     are left unchanged.""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 272 |     global _varprog, _varprogb | 
 | 273 |     if isinstance(path, bytes): | 
 | 274 |         if b'$' not in path: | 
 | 275 |             return path | 
 | 276 |         if not _varprogb: | 
 | 277 |             import re | 
 | 278 |             _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII) | 
 | 279 |         search = _varprogb.search | 
 | 280 |         start = b'{' | 
 | 281 |         end = b'}' | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 282 |         environ = getattr(os, 'environb', None) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 283 |     else: | 
 | 284 |         if '$' not in path: | 
 | 285 |             return path | 
 | 286 |         if not _varprog: | 
 | 287 |             import re | 
 | 288 |             _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII) | 
 | 289 |         search = _varprog.search | 
 | 290 |         start = '{' | 
 | 291 |         end = '}' | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 292 |         environ = os.environ | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 293 |     i = 0 | 
| Guido van Rossum | 8ca162f | 2002-04-07 06:36:23 +0000 | [diff] [blame] | 294 |     while True: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 295 |         m = search(path, i) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 296 |         if not m: | 
 | 297 |             break | 
 | 298 |         i, j = m.span(0) | 
 | 299 |         name = m.group(1) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 300 |         if name.startswith(start) and name.endswith(end): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 301 |             name = name[1:-1] | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 302 |         try: | 
 | 303 |             if environ is None: | 
| Serhiy Storchaka | ffadbb7 | 2014-02-13 10:45:14 +0200 | [diff] [blame] | 304 |                 value = os.fsencode(os.environ[os.fsdecode(name)]) | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 305 |             else: | 
 | 306 |                 value = environ[name] | 
 | 307 |         except KeyError: | 
 | 308 |             i = j | 
 | 309 |         else: | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 310 |             tail = path[j:] | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 311 |             path = path[:i] + value | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 312 |             i = len(path) | 
| Walter Dörwald | 77cdeaf | 2003-06-17 13:13:40 +0000 | [diff] [blame] | 313 |             path += tail | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 314 |     return path | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 315 |  | 
 | 316 |  | 
 | 317 | # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. | 
 | 318 | # It should be understood that this may change the meaning of the path | 
 | 319 | # if it contains symbolic links! | 
 | 320 |  | 
 | 321 | def normpath(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 322 |     """Normalize path, eliminating double slashes, etc.""" | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 323 |     if isinstance(path, bytes): | 
 | 324 |         sep = b'/' | 
 | 325 |         empty = b'' | 
 | 326 |         dot = b'.' | 
 | 327 |         dotdot = b'..' | 
 | 328 |     else: | 
 | 329 |         sep = '/' | 
 | 330 |         empty = '' | 
 | 331 |         dot = '.' | 
 | 332 |         dotdot = '..' | 
 | 333 |     if path == empty: | 
 | 334 |         return dot | 
 | 335 |     initial_slashes = path.startswith(sep) | 
| Marc-André Lemburg | bf222c9 | 2001-01-29 11:29:44 +0000 | [diff] [blame] | 336 |     # POSIX allows one or two initial slashes, but treats three or more | 
 | 337 |     # as single slash. | 
| Tim Peters | 658cba6 | 2001-02-09 20:06:00 +0000 | [diff] [blame] | 338 |     if (initial_slashes and | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 339 |         path.startswith(sep*2) and not path.startswith(sep*3)): | 
| Marc-André Lemburg | bf222c9 | 2001-01-29 11:29:44 +0000 | [diff] [blame] | 340 |         initial_slashes = 2 | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 341 |     comps = path.split(sep) | 
| Skip Montanaro | 018dfae | 2000-07-19 17:09:51 +0000 | [diff] [blame] | 342 |     new_comps = [] | 
 | 343 |     for comp in comps: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 344 |         if comp in (empty, dot): | 
| Skip Montanaro | 018dfae | 2000-07-19 17:09:51 +0000 | [diff] [blame] | 345 |             continue | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 346 |         if (comp != dotdot or (not initial_slashes and not new_comps) or | 
 | 347 |              (new_comps and new_comps[-1] == dotdot)): | 
| Skip Montanaro | 018dfae | 2000-07-19 17:09:51 +0000 | [diff] [blame] | 348 |             new_comps.append(comp) | 
 | 349 |         elif new_comps: | 
 | 350 |             new_comps.pop() | 
 | 351 |     comps = new_comps | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 352 |     path = sep.join(comps) | 
| Marc-André Lemburg | bf222c9 | 2001-01-29 11:29:44 +0000 | [diff] [blame] | 353 |     if initial_slashes: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 354 |         path = sep*initial_slashes + path | 
 | 355 |     return path or dot | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 356 |  | 
 | 357 |  | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 358 | def abspath(path): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame] | 359 |     """Return an absolute path.""" | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 360 |     if not isabs(path): | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 361 |         if isinstance(path, bytes): | 
 | 362 |             cwd = os.getcwdb() | 
 | 363 |         else: | 
 | 364 |             cwd = os.getcwd() | 
 | 365 |         path = join(cwd, path) | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 366 |     return normpath(path) | 
| Guido van Rossum | 83eeef4 | 2001-09-17 15:16:09 +0000 | [diff] [blame] | 367 |  | 
 | 368 |  | 
 | 369 | # Return a canonical path (i.e. the absolute location of a file on the | 
 | 370 | # filesystem). | 
 | 371 |  | 
 | 372 | def realpath(filename): | 
 | 373 |     """Return the canonical path of the specified filename, eliminating any | 
 | 374 | symbolic links encountered in the path.""" | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 375 |     path, ok = _joinrealpath(filename[:0], filename, {}) | 
 | 376 |     return abspath(path) | 
 | 377 |  | 
 | 378 | # Join two paths, normalizing ang eliminating any symbolic links | 
 | 379 | # encountered in the second path. | 
 | 380 | def _joinrealpath(path, rest, seen): | 
 | 381 |     if isinstance(path, bytes): | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 382 |         sep = b'/' | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 383 |         curdir = b'.' | 
 | 384 |         pardir = b'..' | 
| Johannes Gijsbers | 4ec4064 | 2004-08-14 15:01:53 +0000 | [diff] [blame] | 385 |     else: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 386 |         sep = '/' | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 387 |         curdir = '.' | 
 | 388 |         pardir = '..' | 
| Tim Peters | a45cacf | 2004-08-20 03:47:14 +0000 | [diff] [blame] | 389 |  | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 390 |     if isabs(rest): | 
 | 391 |         rest = rest[1:] | 
 | 392 |         path = sep | 
 | 393 |  | 
 | 394 |     while rest: | 
 | 395 |         name, _, rest = rest.partition(sep) | 
 | 396 |         if not name or name == curdir: | 
 | 397 |             # current dir | 
 | 398 |             continue | 
 | 399 |         if name == pardir: | 
 | 400 |             # parent dir | 
 | 401 |             if path: | 
| Serhiy Storchaka | 467393d | 2013-02-18 12:21:04 +0200 | [diff] [blame] | 402 |                 path, name = split(path) | 
 | 403 |                 if name == pardir: | 
 | 404 |                     path = join(path, pardir, pardir) | 
| Brett Cannon | f50299c | 2004-07-10 22:55:15 +0000 | [diff] [blame] | 405 |             else: | 
| Serhiy Storchaka | 467393d | 2013-02-18 12:21:04 +0200 | [diff] [blame] | 406 |                 path = pardir | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 407 |             continue | 
 | 408 |         newpath = join(path, name) | 
 | 409 |         if not islink(newpath): | 
 | 410 |             path = newpath | 
 | 411 |             continue | 
 | 412 |         # Resolve the symbolic link | 
 | 413 |         if newpath in seen: | 
 | 414 |             # Already seen this path | 
 | 415 |             path = seen[newpath] | 
 | 416 |             if path is not None: | 
 | 417 |                 # use cached value | 
 | 418 |                 continue | 
 | 419 |             # The symlink is not resolved, so we must have a symlink loop. | 
 | 420 |             # Return already resolved part + rest of the path unchanged. | 
 | 421 |             return join(newpath, rest), False | 
 | 422 |         seen[newpath] = None # not resolved symlink | 
 | 423 |         path, ok = _joinrealpath(path, os.readlink(newpath), seen) | 
 | 424 |         if not ok: | 
 | 425 |             return join(path, rest), False | 
 | 426 |         seen[newpath] = path # resolved symlink | 
| Tim Peters | b64bec3 | 2001-09-18 02:26:39 +0000 | [diff] [blame] | 427 |  | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 428 |     return path, True | 
| Tim Peters | a45cacf | 2004-08-20 03:47:14 +0000 | [diff] [blame] | 429 |  | 
| Brett Cannon | f50299c | 2004-07-10 22:55:15 +0000 | [diff] [blame] | 430 |  | 
| Victor Stinner | e797c16 | 2010-09-17 23:34:26 +0000 | [diff] [blame] | 431 | supports_unicode_filenames = (sys.platform == 'darwin') | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 432 |  | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 433 | def relpath(path, start=None): | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 434 |     """Return a relative version of a path""" | 
 | 435 |  | 
 | 436 |     if not path: | 
 | 437 |         raise ValueError("no path specified") | 
 | 438 |  | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 439 |     if isinstance(path, bytes): | 
 | 440 |         curdir = b'.' | 
 | 441 |         sep = b'/' | 
 | 442 |         pardir = b'..' | 
 | 443 |     else: | 
 | 444 |         curdir = '.' | 
 | 445 |         sep = '/' | 
 | 446 |         pardir = '..' | 
 | 447 |  | 
 | 448 |     if start is None: | 
 | 449 |         start = curdir | 
 | 450 |  | 
| Hirokazu Yamamoto | b08820a | 2010-10-18 12:13:18 +0000 | [diff] [blame] | 451 |     start_list = [x for x in abspath(start).split(sep) if x] | 
 | 452 |     path_list = [x for x in abspath(path).split(sep) if x] | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 453 |  | 
 | 454 |     # Work out how much of the filepath is shared by start and path. | 
 | 455 |     i = len(commonprefix([start_list, path_list])) | 
 | 456 |  | 
 | 457 |     rel_list = [pardir] * (len(start_list)-i) + path_list[i:] | 
| Christian Heimes | faf2f63 | 2008-01-06 16:59:19 +0000 | [diff] [blame] | 458 |     if not rel_list: | 
 | 459 |         return curdir | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 460 |     return join(*rel_list) |