| 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 | 
| Victor Stinner | d7538dd | 2018-12-14 13:37:26 +0100 | [diff] [blame] | 5 | module on Posix systems; on other systems (e.g. Windows), | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame] | 6 | os.path provides the same operations in a manner specific to that | 
| Victor Stinner | d7538dd | 2018-12-14 13:37:26 +0100 | [diff] [blame] | 7 | platform, and is an alias to another module (e.g. ntpath). | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame] | 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 |  | 
| Serhiy Storchaka | 3460198 | 2018-01-07 17:54:31 +0200 | [diff] [blame] | 13 | # Strings representing various path-related bits and pieces. | 
 | 14 | # These are primarily for export; internally, they are hardcoded. | 
 | 15 | # Should be set before imports for resolving cyclic dependency. | 
 | 16 | curdir = '.' | 
 | 17 | pardir = '..' | 
 | 18 | extsep = '.' | 
 | 19 | sep = '/' | 
 | 20 | pathsep = ':' | 
| Victor Stinner | 2c4c02f | 2019-04-17 17:05:30 +0200 | [diff] [blame] | 21 | defpath = '/bin:/usr/bin' | 
| Serhiy Storchaka | 3460198 | 2018-01-07 17:54:31 +0200 | [diff] [blame] | 22 | altsep = None | 
 | 23 | devnull = '/dev/null' | 
 | 24 |  | 
| Guido van Rossum | d3876d3 | 1996-07-23 03:47:28 +0000 | [diff] [blame] | 25 | import os | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 26 | import sys | 
| Guido van Rossum | 40d9304 | 1990-10-21 16:17:34 +0000 | [diff] [blame] | 27 | import stat | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 28 | import genericpath | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 29 | from genericpath import * | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 30 |  | 
| Skip Montanaro | c62c81e | 2001-02-12 02:00:42 +0000 | [diff] [blame] | 31 | __all__ = ["normcase","isabs","join","splitdrive","split","splitext", | 
 | 32 |            "basename","dirname","commonprefix","getsize","getmtime", | 
| Georg Brandl | f0de6a1 | 2005-08-22 18:02:59 +0000 | [diff] [blame] | 33 |            "getatime","getctime","islink","exists","lexists","isdir","isfile", | 
| Benjamin Peterson | d71ca41 | 2008-05-08 23:44:58 +0000 | [diff] [blame] | 34 |            "ismount", "expanduser","expandvars","normpath","abspath", | 
| Neal Norwitz | 61cdac6 | 2003-01-03 18:01:57 +0000 | [diff] [blame] | 35 |            "samefile","sameopenfile","samestat", | 
| Skip Montanaro | 117910d | 2003-02-14 19:35:31 +0000 | [diff] [blame] | 36 |            "curdir","pardir","sep","pathsep","defpath","altsep","extsep", | 
| Serhiy Storchaka | 3822093 | 2015-03-31 15:31:53 +0300 | [diff] [blame] | 37 |            "devnull","realpath","supports_unicode_filenames","relpath", | 
 | 38 |            "commonpath"] | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 39 |  | 
| Skip Montanaro | 117910d | 2003-02-14 19:35:31 +0000 | [diff] [blame] | 40 |  | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 41 | def _get_sep(path): | 
 | 42 |     if isinstance(path, bytes): | 
 | 43 |         return b'/' | 
 | 44 |     else: | 
 | 45 |         return '/' | 
 | 46 |  | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 47 | # Normalize the case of a pathname.  Trivial in Posix, string.lower on Mac. | 
 | 48 | # On MS-DOS this may also turn slashes into backslashes; however, other | 
 | 49 | # normalizations (such as optimizing '../' away) are not allowed | 
 | 50 | # (another function should be defined to do that). | 
 | 51 |  | 
 | 52 | def normcase(s): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 53 |     """Normalize case of pathname.  Has no effect under Posix""" | 
| Wolfgang Maier | 74510e2 | 2019-03-28 22:47:18 +0100 | [diff] [blame] | 54 |     return os.fspath(s) | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 55 |  | 
 | 56 |  | 
| Jeremy Hylton | a05e293 | 2000-06-28 14:48:01 +0000 | [diff] [blame] | 57 | # Return whether a path is absolute. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 58 | # Trivial in Posix, harder on the Mac or MS-DOS. | 
 | 59 |  | 
 | 60 | def isabs(s): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 61 |     """Test whether a path is absolute""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 62 |     s = os.fspath(s) | 
| 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.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 76 |     a = os.fspath(a) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 77 |     sep = _get_sep(a) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 78 |     path = a | 
| Hynek Schlawack | 4774946 | 2012-07-15 16:21:30 +0200 | [diff] [blame] | 79 |     try: | 
| Serhiy Storchaka | 5bfc03f | 2015-05-19 11:00:07 +0300 | [diff] [blame] | 80 |         if not p: | 
 | 81 |             path[:0] + sep  #23780: Ensure compatible data type even if p is null. | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 82 |         for b in map(os.fspath, p): | 
| Hynek Schlawack | 4774946 | 2012-07-15 16:21:30 +0200 | [diff] [blame] | 83 |             if b.startswith(sep): | 
 | 84 |                 path = b | 
 | 85 |             elif not path or path.endswith(sep): | 
 | 86 |                 path += b | 
 | 87 |             else: | 
 | 88 |                 path += sep + b | 
| Serhiy Storchaka | 3deeeb0 | 2014-10-04 14:58:43 +0300 | [diff] [blame] | 89 |     except (TypeError, AttributeError, BytesWarning): | 
 | 90 |         genericpath._check_arg_types('join', a, *p) | 
 | 91 |         raise | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 92 |     return path | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 93 |  | 
 | 94 |  | 
| Guido van Rossum | 2684738 | 1992-03-31 18:54:35 +0000 | [diff] [blame] | 95 | # 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] | 96 | # rest).  If the path ends in '/', tail will be empty.  If there is no | 
 | 97 | # '/' in the path, head  will be empty. | 
 | 98 | # Trailing '/'es are stripped from head unless it is the root. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 99 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 100 | def split(p): | 
| Tim Peters | 2344fae | 2001-01-15 00:50:52 +0000 | [diff] [blame] | 101 |     """Split a pathname.  Returns tuple "(head, tail)" where "tail" is | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 102 |     everything after the final slash.  Either part may be empty.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 103 |     p = os.fspath(p) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 104 |     sep = _get_sep(p) | 
 | 105 |     i = p.rfind(sep) + 1 | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 106 |     head, tail = p[:i], p[i:] | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 107 |     if head and head != sep*len(head): | 
 | 108 |         head = head.rstrip(sep) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 109 |     return head, tail | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 110 |  | 
 | 111 |  | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 112 | # Split a path in root and extension. | 
| Guido van Rossum | 422869a | 1996-08-20 20:24:17 +0000 | [diff] [blame] | 113 | # 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] | 114 | # pathname component; the root is everything before that. | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 115 | # It is always true that root + ext == p. | 
 | 116 |  | 
| Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 117 | def splitext(p): | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 118 |     p = os.fspath(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.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 134 |     p = os.fspath(p) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 135 |     return p[:0], p | 
| Guido van Rossum | 221df24 | 1995-08-07 20:17:55 +0000 | [diff] [blame] | 136 |  | 
 | 137 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 138 | # 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] | 139 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 140 | def basename(p): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 141 |     """Returns the final component of a pathname""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 142 |     p = os.fspath(p) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 143 |     sep = _get_sep(p) | 
 | 144 |     i = p.rfind(sep) + 1 | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 145 |     return p[i:] | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 146 |  | 
 | 147 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 148 | # 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] | 149 |  | 
 | 150 | def dirname(p): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 151 |     """Returns the directory component of a pathname""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 152 |     p = os.fspath(p) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 153 |     sep = _get_sep(p) | 
 | 154 |     i = p.rfind(sep) + 1 | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 155 |     head = p[:i] | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 156 |     if head and head != sep*len(head): | 
 | 157 |         head = head.rstrip(sep) | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 158 |     return head | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 159 |  | 
 | 160 |  | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 161 | # Is a path a symbolic link? | 
| Guido van Rossum | d3876d3 | 1996-07-23 03:47:28 +0000 | [diff] [blame] | 162 | # 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] | 163 |  | 
 | 164 | def islink(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 165 |     """Test whether a path is a symbolic link""" | 
 | 166 |     try: | 
 | 167 |         st = os.lstat(path) | 
| Serhiy Storchaka | 0185f34 | 2018-09-18 11:28:51 +0300 | [diff] [blame] | 168 |     except (OSError, ValueError, AttributeError): | 
| Guido van Rossum | 8ca162f | 2002-04-07 06:36:23 +0000 | [diff] [blame] | 169 |         return False | 
| Raymond Hettinger | 32200ae | 2002-06-01 19:51:15 +0000 | [diff] [blame] | 170 |     return stat.S_ISLNK(st.st_mode) | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 171 |  | 
| Johannes Gijsbers | ae882f7 | 2004-08-30 10:19:56 +0000 | [diff] [blame] | 172 | # Being true for dangling symbolic links is also useful. | 
 | 173 |  | 
 | 174 | def lexists(path): | 
 | 175 |     """Test whether a path exists.  Returns True for broken symbolic links""" | 
 | 176 |     try: | 
| Georg Brandl | 89fad14 | 2010-03-14 10:23:39 +0000 | [diff] [blame] | 177 |         os.lstat(path) | 
| Serhiy Storchaka | 0185f34 | 2018-09-18 11:28:51 +0300 | [diff] [blame] | 178 |     except (OSError, ValueError): | 
| Johannes Gijsbers | ae882f7 | 2004-08-30 10:19:56 +0000 | [diff] [blame] | 179 |         return False | 
 | 180 |     return True | 
 | 181 |  | 
 | 182 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 183 | # Is a path a mount point? | 
| Guido van Rossum | d3876d3 | 1996-07-23 03:47:28 +0000 | [diff] [blame] | 184 | # (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] | 185 |  | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 186 | def ismount(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 187 |     """Test whether a path is a mount point""" | 
 | 188 |     try: | 
| Christian Heimes | faf2f63 | 2008-01-06 16:59:19 +0000 | [diff] [blame] | 189 |         s1 = os.lstat(path) | 
| Serhiy Storchaka | 0185f34 | 2018-09-18 11:28:51 +0300 | [diff] [blame] | 190 |     except (OSError, ValueError): | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 191 |         # It doesn't exist -- so not a mount point. :-) | 
 | 192 |         return False | 
 | 193 |     else: | 
| Brian Curtin | a3852ff | 2013-07-22 19:05:48 -0500 | [diff] [blame] | 194 |         # A symlink can never be a mount point | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 195 |         if stat.S_ISLNK(s1.st_mode): | 
 | 196 |             return False | 
 | 197 |  | 
 | 198 |     if isinstance(path, bytes): | 
 | 199 |         parent = join(path, b'..') | 
 | 200 |     else: | 
 | 201 |         parent = join(path, '..') | 
| R David Murray | 750018b | 2016-08-18 21:27:48 -0400 | [diff] [blame] | 202 |     parent = realpath(parent) | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 203 |     try: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 204 |         s2 = os.lstat(parent) | 
| Serhiy Storchaka | 0185f34 | 2018-09-18 11:28:51 +0300 | [diff] [blame] | 205 |     except (OSError, ValueError): | 
| Brian Curtin | 06f6fbf | 2013-07-22 13:07:52 -0500 | [diff] [blame] | 206 |         return False | 
 | 207 |  | 
| Raymond Hettinger | 32200ae | 2002-06-01 19:51:15 +0000 | [diff] [blame] | 208 |     dev1 = s1.st_dev | 
 | 209 |     dev2 = s2.st_dev | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 210 |     if dev1 != dev2: | 
| Tim Peters | bc0e910 | 2002-04-04 22:55:58 +0000 | [diff] [blame] | 211 |         return True     # path/.. on a different device as path | 
| Raymond Hettinger | 32200ae | 2002-06-01 19:51:15 +0000 | [diff] [blame] | 212 |     ino1 = s1.st_ino | 
 | 213 |     ino2 = s2.st_ino | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 214 |     if ino1 == ino2: | 
| Tim Peters | bc0e910 | 2002-04-04 22:55:58 +0000 | [diff] [blame] | 215 |         return True     # path/.. is the same i-node as path | 
 | 216 |     return False | 
| Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 217 |  | 
 | 218 |  | 
| Guido van Rossum | 7ac4878 | 1992-01-14 18:29:32 +0000 | [diff] [blame] | 219 | # Expand paths beginning with '~' or '~user'. | 
 | 220 | # '~' means $HOME; '~user' means that user's home directory. | 
 | 221 | # If the path doesn't begin with '~', or if the user or $HOME is unknown, | 
 | 222 | # the path is returned unchanged (leaving error reporting to whatever | 
 | 223 | # function is called with the expanded path as argument). | 
 | 224 | # See also module 'glob' for expansion of *, ? and [...] in pathnames. | 
 | 225 | # (A function should also be defined to do full *sh-style environment | 
 | 226 | # variable expansion.) | 
 | 227 |  | 
 | 228 | def expanduser(path): | 
| Tim Peters | 2344fae | 2001-01-15 00:50:52 +0000 | [diff] [blame] | 229 |     """Expand ~ and ~user constructions.  If user or $HOME is unknown, | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 230 |     do nothing.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 231 |     path = os.fspath(path) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 232 |     if isinstance(path, bytes): | 
 | 233 |         tilde = b'~' | 
 | 234 |     else: | 
 | 235 |         tilde = '~' | 
 | 236 |     if not path.startswith(tilde): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 237 |         return path | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 238 |     sep = _get_sep(path) | 
 | 239 |     i = path.find(sep, 1) | 
| Walter Dörwald | a9da5ae | 2003-06-19 10:21:14 +0000 | [diff] [blame] | 240 |     if i < 0: | 
 | 241 |         i = len(path) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 242 |     if i == 1: | 
| Walter Dörwald | a9da5ae | 2003-06-19 10:21:14 +0000 | [diff] [blame] | 243 |         if 'HOME' not in os.environ: | 
| Neal Norwitz | 609ba81 | 2002-09-05 21:08:25 +0000 | [diff] [blame] | 244 |             import pwd | 
| Victor Stinner | f2f4555 | 2018-12-05 16:49:35 +0100 | [diff] [blame] | 245 |             try: | 
 | 246 |                 userhome = pwd.getpwuid(os.getuid()).pw_dir | 
 | 247 |             except KeyError: | 
 | 248 |                 # bpo-10496: if the current user identifier doesn't exist in the | 
 | 249 |                 # password database, return the path unchanged | 
 | 250 |                 return path | 
| Neal Norwitz | 609ba81 | 2002-09-05 21:08:25 +0000 | [diff] [blame] | 251 |         else: | 
 | 252 |             userhome = os.environ['HOME'] | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 253 |     else: | 
 | 254 |         import pwd | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 255 |         name = path[1:i] | 
 | 256 |         if isinstance(name, bytes): | 
 | 257 |             name = str(name, 'ASCII') | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 258 |         try: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 259 |             pwent = pwd.getpwnam(name) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 260 |         except KeyError: | 
| Victor Stinner | f2f4555 | 2018-12-05 16:49:35 +0100 | [diff] [blame] | 261 |             # bpo-10496: if the user name from the path doesn't exist in the | 
 | 262 |             # password database, return the path unchanged | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 263 |             return path | 
| Walter Dörwald | 77cdeaf | 2003-06-17 13:13:40 +0000 | [diff] [blame] | 264 |         userhome = pwent.pw_dir | 
| pxinwr | 75dabfe | 2020-12-18 03:22:29 +0800 | [diff] [blame] | 265 |     # if no user home, return the path unchanged on VxWorks | 
 | 266 |     if userhome is None and sys.platform == "vxworks": | 
 | 267 |         return path | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 268 |     if isinstance(path, bytes): | 
| Victor Stinner | 16004ac | 2010-09-29 16:59:18 +0000 | [diff] [blame] | 269 |         userhome = os.fsencode(userhome) | 
| Benjamin Peterson | ef3e4c2 | 2009-04-11 19:48:14 +0000 | [diff] [blame] | 270 |         root = b'/' | 
 | 271 |     else: | 
 | 272 |         root = '/' | 
| Jesus Cea | 7f0d888 | 2012-05-10 05:10:50 +0200 | [diff] [blame] | 273 |     userhome = userhome.rstrip(root) | 
 | 274 |     return (userhome + path[i:]) or root | 
| Guido van Rossum | 4732ccf | 1992-08-09 13:54:50 +0000 | [diff] [blame] | 275 |  | 
 | 276 |  | 
 | 277 | # Expand paths containing shell variable substitutions. | 
| Guido van Rossum | b6775db | 1994-08-01 11:34:53 +0000 | [diff] [blame] | 278 | # This expands the forms $variable and ${variable} only. | 
| Jeremy Hylton | a05e293 | 2000-06-28 14:48:01 +0000 | [diff] [blame] | 279 | # Non-existent variables are left unchanged. | 
| Guido van Rossum | b6775db | 1994-08-01 11:34:53 +0000 | [diff] [blame] | 280 |  | 
 | 281 | _varprog = None | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 282 | _varprogb = None | 
| Guido van Rossum | 4732ccf | 1992-08-09 13:54:50 +0000 | [diff] [blame] | 283 |  | 
 | 284 | def expandvars(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 285 |     """Expand shell variables of form $var and ${var}.  Unknown variables | 
| Fred Drake | c0ab93e | 2000-09-28 16:22:52 +0000 | [diff] [blame] | 286 |     are left unchanged.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 287 |     path = os.fspath(path) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 288 |     global _varprog, _varprogb | 
 | 289 |     if isinstance(path, bytes): | 
 | 290 |         if b'$' not in path: | 
 | 291 |             return path | 
 | 292 |         if not _varprogb: | 
 | 293 |             import re | 
 | 294 |             _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII) | 
 | 295 |         search = _varprogb.search | 
 | 296 |         start = b'{' | 
 | 297 |         end = b'}' | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 298 |         environ = getattr(os, 'environb', None) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 299 |     else: | 
 | 300 |         if '$' not in path: | 
 | 301 |             return path | 
 | 302 |         if not _varprog: | 
 | 303 |             import re | 
 | 304 |             _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII) | 
 | 305 |         search = _varprog.search | 
 | 306 |         start = '{' | 
 | 307 |         end = '}' | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 308 |         environ = os.environ | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 309 |     i = 0 | 
| Guido van Rossum | 8ca162f | 2002-04-07 06:36:23 +0000 | [diff] [blame] | 310 |     while True: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 311 |         m = search(path, i) | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 312 |         if not m: | 
 | 313 |             break | 
 | 314 |         i, j = m.span(0) | 
 | 315 |         name = m.group(1) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 316 |         if name.startswith(start) and name.endswith(end): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 317 |             name = name[1:-1] | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 318 |         try: | 
 | 319 |             if environ is None: | 
| Serhiy Storchaka | ffadbb7 | 2014-02-13 10:45:14 +0200 | [diff] [blame] | 320 |                 value = os.fsencode(os.environ[os.fsdecode(name)]) | 
| Serhiy Storchaka | dbb1019 | 2014-02-13 10:13:53 +0200 | [diff] [blame] | 321 |             else: | 
 | 322 |                 value = environ[name] | 
 | 323 |         except KeyError: | 
 | 324 |             i = j | 
 | 325 |         else: | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 326 |             tail = path[j:] | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 327 |             path = path[:i] + value | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 328 |             i = len(path) | 
| Walter Dörwald | 77cdeaf | 2003-06-17 13:13:40 +0000 | [diff] [blame] | 329 |             path += tail | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 330 |     return path | 
| Guido van Rossum | c629d34 | 1992-11-05 10:43:02 +0000 | [diff] [blame] | 331 |  | 
 | 332 |  | 
 | 333 | # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. | 
 | 334 | # It should be understood that this may change the meaning of the path | 
 | 335 | # if it contains symbolic links! | 
 | 336 |  | 
 | 337 | def normpath(path): | 
| Guido van Rossum | 346f7af | 1997-12-05 19:04:51 +0000 | [diff] [blame] | 338 |     """Normalize path, eliminating double slashes, etc.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 339 |     path = os.fspath(path) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 340 |     if isinstance(path, bytes): | 
 | 341 |         sep = b'/' | 
 | 342 |         empty = b'' | 
 | 343 |         dot = b'.' | 
 | 344 |         dotdot = b'..' | 
 | 345 |     else: | 
 | 346 |         sep = '/' | 
 | 347 |         empty = '' | 
 | 348 |         dot = '.' | 
 | 349 |         dotdot = '..' | 
 | 350 |     if path == empty: | 
 | 351 |         return dot | 
 | 352 |     initial_slashes = path.startswith(sep) | 
| Marc-André Lemburg | bf222c9 | 2001-01-29 11:29:44 +0000 | [diff] [blame] | 353 |     # POSIX allows one or two initial slashes, but treats three or more | 
 | 354 |     # as single slash. | 
| Tim Peters | 658cba6 | 2001-02-09 20:06:00 +0000 | [diff] [blame] | 355 |     if (initial_slashes and | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 356 |         path.startswith(sep*2) and not path.startswith(sep*3)): | 
| Marc-André Lemburg | bf222c9 | 2001-01-29 11:29:44 +0000 | [diff] [blame] | 357 |         initial_slashes = 2 | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 358 |     comps = path.split(sep) | 
| Skip Montanaro | 018dfae | 2000-07-19 17:09:51 +0000 | [diff] [blame] | 359 |     new_comps = [] | 
 | 360 |     for comp in comps: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 361 |         if comp in (empty, dot): | 
| Skip Montanaro | 018dfae | 2000-07-19 17:09:51 +0000 | [diff] [blame] | 362 |             continue | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 363 |         if (comp != dotdot or (not initial_slashes and not new_comps) or | 
 | 364 |              (new_comps and new_comps[-1] == dotdot)): | 
| Skip Montanaro | 018dfae | 2000-07-19 17:09:51 +0000 | [diff] [blame] | 365 |             new_comps.append(comp) | 
 | 366 |         elif new_comps: | 
 | 367 |             new_comps.pop() | 
 | 368 |     comps = new_comps | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 369 |     path = sep.join(comps) | 
| Marc-André Lemburg | bf222c9 | 2001-01-29 11:29:44 +0000 | [diff] [blame] | 370 |     if initial_slashes: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 371 |         path = sep*initial_slashes + path | 
 | 372 |     return path or dot | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 373 |  | 
 | 374 |  | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 375 | def abspath(path): | 
| Guido van Rossum | 54f22ed | 2000-02-04 15:10:34 +0000 | [diff] [blame] | 376 |     """Return an absolute path.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 377 |     path = os.fspath(path) | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 378 |     if not isabs(path): | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 379 |         if isinstance(path, bytes): | 
 | 380 |             cwd = os.getcwdb() | 
 | 381 |         else: | 
 | 382 |             cwd = os.getcwd() | 
 | 383 |         path = join(cwd, path) | 
| Guido van Rossum | e294cf6 | 1999-01-29 18:05:18 +0000 | [diff] [blame] | 384 |     return normpath(path) | 
| Guido van Rossum | 83eeef4 | 2001-09-17 15:16:09 +0000 | [diff] [blame] | 385 |  | 
 | 386 |  | 
 | 387 | # Return a canonical path (i.e. the absolute location of a file on the | 
 | 388 | # filesystem). | 
 | 389 |  | 
 | 390 | def realpath(filename): | 
 | 391 |     """Return the canonical path of the specified filename, eliminating any | 
 | 392 | symbolic links encountered in the path.""" | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 393 |     filename = os.fspath(filename) | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 394 |     path, ok = _joinrealpath(filename[:0], filename, {}) | 
 | 395 |     return abspath(path) | 
 | 396 |  | 
| Martin Panter | 119e502 | 2016-04-16 09:28:57 +0000 | [diff] [blame] | 397 | # Join two paths, normalizing and eliminating any symbolic links | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 398 | # encountered in the second path. | 
 | 399 | def _joinrealpath(path, rest, seen): | 
 | 400 |     if isinstance(path, bytes): | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 401 |         sep = b'/' | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 402 |         curdir = b'.' | 
 | 403 |         pardir = b'..' | 
| Johannes Gijsbers | 4ec4064 | 2004-08-14 15:01:53 +0000 | [diff] [blame] | 404 |     else: | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 405 |         sep = '/' | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 406 |         curdir = '.' | 
 | 407 |         pardir = '..' | 
| Tim Peters | a45cacf | 2004-08-20 03:47:14 +0000 | [diff] [blame] | 408 |  | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 409 |     if isabs(rest): | 
 | 410 |         rest = rest[1:] | 
 | 411 |         path = sep | 
 | 412 |  | 
 | 413 |     while rest: | 
 | 414 |         name, _, rest = rest.partition(sep) | 
 | 415 |         if not name or name == curdir: | 
 | 416 |             # current dir | 
 | 417 |             continue | 
 | 418 |         if name == pardir: | 
 | 419 |             # parent dir | 
 | 420 |             if path: | 
| Serhiy Storchaka | 467393d | 2013-02-18 12:21:04 +0200 | [diff] [blame] | 421 |                 path, name = split(path) | 
 | 422 |                 if name == pardir: | 
 | 423 |                     path = join(path, pardir, pardir) | 
| Brett Cannon | f50299c | 2004-07-10 22:55:15 +0000 | [diff] [blame] | 424 |             else: | 
| Serhiy Storchaka | 467393d | 2013-02-18 12:21:04 +0200 | [diff] [blame] | 425 |                 path = pardir | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 426 |             continue | 
 | 427 |         newpath = join(path, name) | 
 | 428 |         if not islink(newpath): | 
 | 429 |             path = newpath | 
 | 430 |             continue | 
 | 431 |         # Resolve the symbolic link | 
 | 432 |         if newpath in seen: | 
 | 433 |             # Already seen this path | 
 | 434 |             path = seen[newpath] | 
 | 435 |             if path is not None: | 
 | 436 |                 # use cached value | 
 | 437 |                 continue | 
 | 438 |             # The symlink is not resolved, so we must have a symlink loop. | 
 | 439 |             # Return already resolved part + rest of the path unchanged. | 
 | 440 |             return join(newpath, rest), False | 
 | 441 |         seen[newpath] = None # not resolved symlink | 
 | 442 |         path, ok = _joinrealpath(path, os.readlink(newpath), seen) | 
 | 443 |         if not ok: | 
 | 444 |             return join(path, rest), False | 
 | 445 |         seen[newpath] = path # resolved symlink | 
| Tim Peters | b64bec3 | 2001-09-18 02:26:39 +0000 | [diff] [blame] | 446 |  | 
| Serhiy Storchaka | df32691 | 2013-02-10 12:22:07 +0200 | [diff] [blame] | 447 |     return path, True | 
| Tim Peters | a45cacf | 2004-08-20 03:47:14 +0000 | [diff] [blame] | 448 |  | 
| Brett Cannon | f50299c | 2004-07-10 22:55:15 +0000 | [diff] [blame] | 449 |  | 
| Victor Stinner | e797c16 | 2010-09-17 23:34:26 +0000 | [diff] [blame] | 450 | supports_unicode_filenames = (sys.platform == 'darwin') | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 451 |  | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 452 | def relpath(path, start=None): | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 453 |     """Return a relative version of a path""" | 
 | 454 |  | 
 | 455 |     if not path: | 
 | 456 |         raise ValueError("no path specified") | 
 | 457 |  | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 458 |     path = os.fspath(path) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 459 |     if isinstance(path, bytes): | 
 | 460 |         curdir = b'.' | 
 | 461 |         sep = b'/' | 
 | 462 |         pardir = b'..' | 
 | 463 |     else: | 
 | 464 |         curdir = '.' | 
 | 465 |         sep = '/' | 
 | 466 |         pardir = '..' | 
 | 467 |  | 
 | 468 |     if start is None: | 
 | 469 |         start = curdir | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 470 |     else: | 
 | 471 |         start = os.fspath(start) | 
| Guido van Rossum | f0af3e3 | 2008-10-02 18:55:37 +0000 | [diff] [blame] | 472 |  | 
| Serhiy Storchaka | 3deeeb0 | 2014-10-04 14:58:43 +0300 | [diff] [blame] | 473 |     try: | 
 | 474 |         start_list = [x for x in abspath(start).split(sep) if x] | 
 | 475 |         path_list = [x for x in abspath(path).split(sep) if x] | 
 | 476 |         # Work out how much of the filepath is shared by start and path. | 
 | 477 |         i = len(commonprefix([start_list, path_list])) | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 478 |  | 
| Serhiy Storchaka | 3deeeb0 | 2014-10-04 14:58:43 +0300 | [diff] [blame] | 479 |         rel_list = [pardir] * (len(start_list)-i) + path_list[i:] | 
 | 480 |         if not rel_list: | 
 | 481 |             return curdir | 
 | 482 |         return join(*rel_list) | 
| Serhiy Storchaka | e4f4708 | 2014-10-04 16:09:02 +0300 | [diff] [blame] | 483 |     except (TypeError, AttributeError, BytesWarning, DeprecationWarning): | 
| Serhiy Storchaka | 3deeeb0 | 2014-10-04 14:58:43 +0300 | [diff] [blame] | 484 |         genericpath._check_arg_types('relpath', path, start) | 
 | 485 |         raise | 
| Serhiy Storchaka | 3822093 | 2015-03-31 15:31:53 +0300 | [diff] [blame] | 486 |  | 
 | 487 |  | 
 | 488 | # Return the longest common sub-path of the sequence of paths given as input. | 
 | 489 | # The paths are not normalized before comparing them (this is the | 
 | 490 | # responsibility of the caller). Any trailing separator is stripped from the | 
 | 491 | # returned path. | 
 | 492 |  | 
 | 493 | def commonpath(paths): | 
 | 494 |     """Given a sequence of path names, returns the longest common sub-path.""" | 
 | 495 |  | 
 | 496 |     if not paths: | 
 | 497 |         raise ValueError('commonpath() arg is an empty sequence') | 
 | 498 |  | 
| Brett Cannon | 3f9183b | 2016-08-26 14:44:48 -0700 | [diff] [blame] | 499 |     paths = tuple(map(os.fspath, paths)) | 
| Serhiy Storchaka | 3822093 | 2015-03-31 15:31:53 +0300 | [diff] [blame] | 500 |     if isinstance(paths[0], bytes): | 
 | 501 |         sep = b'/' | 
 | 502 |         curdir = b'.' | 
 | 503 |     else: | 
 | 504 |         sep = '/' | 
 | 505 |         curdir = '.' | 
 | 506 |  | 
 | 507 |     try: | 
 | 508 |         split_paths = [path.split(sep) for path in paths] | 
 | 509 |  | 
 | 510 |         try: | 
 | 511 |             isabs, = set(p[:1] == sep for p in paths) | 
 | 512 |         except ValueError: | 
 | 513 |             raise ValueError("Can't mix absolute and relative paths") from None | 
 | 514 |  | 
 | 515 |         split_paths = [[c for c in s if c and c != curdir] for s in split_paths] | 
 | 516 |         s1 = min(split_paths) | 
 | 517 |         s2 = max(split_paths) | 
 | 518 |         common = s1 | 
 | 519 |         for i, c in enumerate(s1): | 
 | 520 |             if c != s2[i]: | 
 | 521 |                 common = s1[:i] | 
 | 522 |                 break | 
 | 523 |  | 
 | 524 |         prefix = sep if isabs else sep[:0] | 
 | 525 |         return prefix + sep.join(common) | 
 | 526 |     except (TypeError, AttributeError): | 
 | 527 |         genericpath._check_arg_types('commonpath', *paths) | 
 | 528 |         raise |