Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(14)

Delta Between Two Patch Sets: Lib/posixpath.py

Issue 3055: combined patches from http://bugs.python.org/issue3187 (Closed) SVN Base: http://svn.python.org/view/*checkout*/python/branches/py3k/
Left Patch Set: Number 3 from Victor Created 1 year, 1 month ago , Downloaded from: http://bugs.python.org/file11680/python3_bytes_filename-3.patch
Right Patch Set: One more tweak (fold some long lines) Created 1 year, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 """Common operations on Posix pathnames. 1 """Common operations on Posix pathnames.
2 2
3 Instead of importing this module directly, import os and refer to 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 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), 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 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). 7 platform, and is an alias to another module (e.g. macpath, ntpath).
8 8
9 Some of this can actually be useful on non-Posix systems too, e.g. 9 Some of this can actually be useful on non-Posix systems too, e.g.
10 for manipulation of the pathname component of URLs. 10 for manipulation of the pathname component of URLs.
11 """ 11 """
12 12
13 import os 13 import os
14 import sys
14 import stat 15 import stat
15 import genericpath 16 import genericpath
16 from genericpath import * 17 from genericpath import *
17 import sys
18 18
19 __all__ = ["normcase","isabs","join","splitdrive","split","splitext", 19 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
20 "basename","dirname","commonprefix","getsize","getmtime", 20 "basename","dirname","commonprefix","getsize","getmtime",
21 "getatime","getctime","islink","exists","lexists","isdir","isfile", 21 "getatime","getctime","islink","exists","lexists","isdir","isfile",
22 "ismount", "expanduser","expandvars","normpath","abspath", 22 "ismount", "expanduser","expandvars","normpath","abspath",
23 "samefile","sameopenfile","samestat", 23 "samefile","sameopenfile","samestat",
24 "curdir","pardir","sep","pathsep","defpath","altsep","extsep", 24 "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
25 "devnull","realpath","supports_unicode_filenames","relpath"] 25 "devnull","realpath","supports_unicode_filenames","relpath"]
26 26
27 # strings representing various path-related bits and pieces 27 # Strings representing various path-related bits and pieces.
28 # These are primarily for export; internally, they are hardcoded.
28 curdir = '.' 29 curdir = '.'
29 pardir = '..' 30 pardir = '..'
30 extsep = '.' 31 extsep = '.'
31 sep = '/' 32 sep = '/'
32 pathsep = ':' 33 pathsep = ':'
33 defpath = ':/bin:/usr/bin' 34 defpath = ':/bin:/usr/bin'
34 altsep = None 35 altsep = None
35 devnull = '/dev/null' 36 devnull = '/dev/null'
36 37
37 def _get_sep(path): 38 def _get_sep(path):
38 if isinstance(path, (bytes, bytearray)): 39 if isinstance(path, bytes):
39 return b'/' 40 return b'/'
40 else: 41 else:
41 return '/' 42 return '/'
42 43
43 # Normalize the case of a pathname. Trivial in Posix, string.lower on Mac. 44 # Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
44 # On MS-DOS this may also turn slashes into backslashes; however, other 45 # On MS-DOS this may also turn slashes into backslashes; however, other
45 # normalizations (such as optimizing '../' away) are not allowed 46 # normalizations (such as optimizing '../' away) are not allowed
46 # (another function should be defined to do that). 47 # (another function should be defined to do that).
47 48
48 def normcase(s): 49 def normcase(s):
49 """Normalize case of pathname. Has no effect under Posix""" 50 """Normalize case of pathname. Has no effect under Posix"""
51 # TODO: on Mac OS X, this should really return s.lower().
50 return s 52 return s
51 53
52 54
53 # Return whether a path is absolute. 55 # Return whether a path is absolute.
54 # Trivial in Posix, harder on the Mac or MS-DOS. 56 # Trivial in Posix, harder on the Mac or MS-DOS.
55 57
56 def isabs(s): 58 def isabs(s):
57 """Test whether a path is absolute""" 59 """Test whether a path is absolute"""
58 sep = _get_sep(s) 60 sep = _get_sep(s)
59 return s.startswith(sep) 61 return s.startswith(sep)
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 head = head.rstrip(sep) 96 head = head.rstrip(sep)
95 return head, tail 97 return head, tail
96 98
97 99
98 # Split a path in root and extension. 100 # Split a path in root and extension.
99 # The extension is everything starting at the last dot in the last 101 # The extension is everything starting at the last dot in the last
100 # pathname component; the root is everything before that. 102 # pathname component; the root is everything before that.
101 # It is always true that root + ext == p. 103 # It is always true that root + ext == p.
102 104
103 def splitext(p): 105 def splitext(p):
104 return genericpath._splitext(p, sep, altsep, extsep) 106 if isinstance(p, bytes):
107 sep = b'/'
108 extsep = b'.'
109 else:
110 sep = '/'
111 extsep = '.'
112 return genericpath._splitext(p, sep, None, extsep)
105 splitext.__doc__ = genericpath._splitext.__doc__ 113 splitext.__doc__ = genericpath._splitext.__doc__
106 114
107 # Split a pathname into a drive specification and the rest of the 115 # Split a pathname into a drive specification and the rest of the
108 # path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. 116 # path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
109 117
110 def splitdrive(p): 118 def splitdrive(p):
111 """Split a pathname into drive and path. On Posix, drive is always 119 """Split a pathname into drive and path. On Posix, drive is always
112 empty.""" 120 empty."""
113 if isinstance(p, (bytes, bytearray)): 121 return p[:0], p
114 return b'', p
115 else:
116 return '', p
117 122
118 123
119 # Return the tail (basename) part of a path, same as split(path)[1]. 124 # Return the tail (basename) part of a path, same as split(path)[1].
120 125
121 def basename(p): 126 def basename(p):
122 """Returns the final component of a pathname""" 127 """Returns the final component of a pathname"""
123 sep = _get_sep(p) 128 sep = _get_sep(p)
124 i = p.rfind(sep) + 1 129 i = p.rfind(sep) + 1
125 return p[i:] 130 return p[i:]
126 131
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 s1.st_dev == s2.st_dev 192 s1.st_dev == s2.st_dev
188 193
189 194
190 # Is a path a mount point? 195 # Is a path a mount point?
191 # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) 196 # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
192 197
193 def ismount(path): 198 def ismount(path):
194 """Test whether a path is a mount point""" 199 """Test whether a path is a mount point"""
195 try: 200 try:
196 s1 = os.lstat(path) 201 s1 = os.lstat(path)
197 if isinstance(path, (bytes, bytearray)): 202 if isinstance(path, bytes):
198 parent = join(path, b'..') 203 parent = join(path, b'..')
199 else: 204 else:
200 parent = join(path, '..') 205 parent = join(path, '..')
201 s2 = os.lstat(parent) 206 s2 = os.lstat(parent)
202 except os.error: 207 except os.error:
203 return False # It doesn't exist -- so not a mount point :-) 208 return False # It doesn't exist -- so not a mount point :-)
204 dev1 = s1.st_dev 209 dev1 = s1.st_dev
205 dev2 = s2.st_dev 210 dev2 = s2.st_dev
206 if dev1 != dev2: 211 if dev1 != dev2:
207 return True # path/.. on a different device as path 212 return True # path/.. on a different device as path
208 ino1 = s1.st_ino 213 ino1 = s1.st_ino
209 ino2 = s2.st_ino 214 ino2 = s2.st_ino
210 if ino1 == ino2: 215 if ino1 == ino2:
211 return True # path/.. is the same i-node as path 216 return True # path/.. is the same i-node as path
212 return False 217 return False
213 218
214 219
215 # Expand paths beginning with '~' or '~user'. 220 # Expand paths beginning with '~' or '~user'.
216 # '~' means $HOME; '~user' means that user's home directory. 221 # '~' 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, 222 # 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 223 # the path is returned unchanged (leaving error reporting to whatever
219 # function is called with the expanded path as argument). 224 # function is called with the expanded path as argument).
220 # See also module 'glob' for expansion of *, ? and [...] in pathnames. 225 # See also module 'glob' for expansion of *, ? and [...] in pathnames.
221 # (A function should also be defined to do full *sh-style environment 226 # (A function should also be defined to do full *sh-style environment
222 # variable expansion.) 227 # variable expansion.)
223 228
224 def expanduser(path): 229 def expanduser(path):
225 """Expand ~ and ~user constructions. If user or $HOME is unknown, 230 """Expand ~ and ~user constructions. If user or $HOME is unknown,
226 do nothing.""" 231 do nothing."""
227 if isinstance(path, (bytes, bytearray)): 232 if isinstance(path, bytes):
228 tilde = b'~' 233 tilde = b'~'
229 else: 234 else:
230 tilde = '~' 235 tilde = '~'
231 if not path.startswith(tilde): 236 if not path.startswith(tilde):
232 return path 237 return path
233 sep = _get_sep(path) 238 sep = _get_sep(path)
234 i = path.find(sep, 1) 239 i = path.find(sep, 1)
235 if i < 0: 240 if i < 0:
236 i = len(path) 241 i = len(path)
237 if i == 1: 242 if i == 1:
238 if 'HOME' not in os.environ: 243 if 'HOME' not in os.environ:
239 import pwd 244 import pwd
240 userhome = pwd.getpwuid(os.getuid()).pw_dir 245 userhome = pwd.getpwuid(os.getuid()).pw_dir
241 else: 246 else:
242 userhome = os.environ['HOME'] 247 userhome = os.environ['HOME']
243 else: 248 else:
244 import pwd 249 import pwd
245 name = path[1:i] 250 name = path[1:i]
246 if isinstance(name, (bytes, bytearray)): 251 if isinstance(name, bytes):
247 name = str(name, 'ASCII') 252 name = str(name, 'ASCII')
248 try: 253 try:
249 pwent = pwd.getpwnam(name) 254 pwent = pwd.getpwnam(name)
250 except KeyError: 255 except KeyError:
251 return path 256 return path
252 userhome = pwent.pw_dir 257 userhome = pwent.pw_dir
253 if isinstance(path, (bytes, bytearray)): 258 if isinstance(path, bytes):
254 userhome = userhome.encode(sys.getfilesystemencoding()) 259 userhome = userhome.encode(sys.getfilesystemencoding())
255 userhome = userhome.rstrip(sep) 260 userhome = userhome.rstrip(sep)
256 return userhome + path[i:] 261 return userhome + path[i:]
257 262
258 263
259 # Expand paths containing shell variable substitutions. 264 # Expand paths containing shell variable substitutions.
260 # This expands the forms $variable and ${variable} only. 265 # This expands the forms $variable and ${variable} only.
261 # Non-existent variables are left unchanged. 266 # Non-existent variables are left unchanged.
262 267
263 _varprog = None 268 _varprog = None
264 _varprogb = None 269 _varprogb = None
265 270
266 def expandvars(path): 271 def expandvars(path):
267 """Expand shell variables of form $var and ${var}. Unknown variables 272 """Expand shell variables of form $var and ${var}. Unknown variables
268 are left unchanged.""" 273 are left unchanged."""
269 global _varprog, _varprogb 274 global _varprog, _varprogb
270 if isinstance(path, (bytes, bytearray)): 275 if isinstance(path, bytes):
271 if b'$' not in path: 276 if b'$' not in path:
272 return path 277 return path
273 if not _varprogb: 278 if not _varprogb:
274 import re 279 import re
275 _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII) 280 _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
276 search = _varprogb.search 281 search = _varprogb.search
277 start = b'{' 282 start = b'{'
278 end = b'}' 283 end = b'}'
279 else: 284 else:
280 if '$' not in path: 285 if '$' not in path:
281 return path 286 return path
282 if not _varprog: 287 if not _varprog:
283 import re 288 import re
284 _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII) 289 _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
285 search = _varprog.search 290 search = _varprog.search
286 start = '{' 291 start = '{'
287 end = '}' 292 end = '}'
288 i = 0 293 i = 0
289 while True: 294 while True:
290 m = search(path, i) 295 m = search(path, i)
291 if not m: 296 if not m:
292 break 297 break
293 i, j = m.span(0) 298 i, j = m.span(0)
294 name = m.group(1) 299 name = m.group(1)
295 if name.startswith(start) and name.endswith(end): 300 if name.startswith(start) and name.endswith(end):
296 name = name[1:-1] 301 name = name[1:-1]
297 if isinstance(name, (bytes, bytearray)): 302 if isinstance(name, bytes):
298 name = str(name, 'ASCII') 303 name = str(name, 'ASCII')
299 if name in os.environ: 304 if name in os.environ:
300 tail = path[j:] 305 tail = path[j:]
301 value = os.environ[name] 306 value = os.environ[name]
302 if isinstance(path, (bytes, bytearray)): 307 if isinstance(path, bytes):
303 value = value.encode('ASCII') 308 value = value.encode('ASCII')
304 path = path[:i] + value 309 path = path[:i] + value
305 i = len(path) 310 i = len(path)
306 path += tail 311 path += tail
307 else: 312 else:
308 i = j 313 i = j
309 return path 314 return path
310 315
311 316
312 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. 317 # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
313 # It should be understood that this may change the meaning of the path 318 # It should be understood that this may change the meaning of the path
314 # if it contains symbolic links! 319 # if it contains symbolic links!
315 320
316 def normpath(path): 321 def normpath(path):
317 """Normalize path, eliminating double slashes, etc.""" 322 """Normalize path, eliminating double slashes, etc."""
318 if isinstance(path, (bytes, bytearray)): 323 if isinstance(path, bytes):
319 sep = b'/' 324 sep = b'/'
320 empty = b'' 325 empty = b''
321 dot = b'.' 326 dot = b'.'
322 dotdot = b'..' 327 dotdot = b'..'
323 else: 328 else:
324 sep = '/' 329 sep = '/'
325 empty = '' 330 empty = ''
326 dot = '.' 331 dot = '.'
327 dotdot = '..' 332 dotdot = '..'
328 if path == empty: 333 if path == empty:
(...skipping 17 matching lines...) Expand all
346 comps = new_comps 351 comps = new_comps
347 path = sep.join(comps) 352 path = sep.join(comps)
348 if initial_slashes: 353 if initial_slashes:
349 path = sep*initial_slashes + path 354 path = sep*initial_slashes + path
350 return path or dot 355 return path or dot
351 356
352 357
353 def abspath(path): 358 def abspath(path):
354 """Return an absolute path.""" 359 """Return an absolute path."""
355 if not isabs(path): 360 if not isabs(path):
356 if isinstance(path, (bytes, bytearray)): 361 if isinstance(path, bytes):
357 cwd = os.getcwdb() 362 cwd = os.getcwdb()
358 else: 363 else:
359 cwd = os.getcwd() 364 cwd = os.getcwd()
360 path = join(cwd, path) 365 path = join(cwd, path)
361 return normpath(path) 366 return normpath(path)
362 367
363 368
364 # Return a canonical path (i.e. the absolute location of a file on the 369 # Return a canonical path (i.e. the absolute location of a file on the
365 # filesystem). 370 # filesystem).
366 371
367 def realpath(filename): 372 def realpath(filename):
368 """Return the canonical path of the specified filename, eliminating any 373 """Return the canonical path of the specified filename, eliminating any
369 symbolic links encountered in the path.""" 374 symbolic links encountered in the path."""
370 if isinstance(filename, (bytes, bytearray)): 375 if isinstance(filename, bytes):
371 sep = b'/' 376 sep = b'/'
372 empty = b'' 377 empty = b''
373 else: 378 else:
374 sep = '/' 379 sep = '/'
375 empty = '' 380 empty = ''
376 if isabs(filename): 381 if isabs(filename):
377 bits = [sep] + filename.split(sep)[1:] 382 bits = [sep] + filename.split(sep)[1:]
378 else: 383 else:
379 bits = [empty] + filename.split(sep) 384 bits = [empty] + filename.split(sep)
380 385
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 return path 419 return path
415 420
416 supports_unicode_filenames = False 421 supports_unicode_filenames = False
417 422
418 def relpath(path, start=None): 423 def relpath(path, start=None):
419 """Return a relative version of a path""" 424 """Return a relative version of a path"""
420 425
421 if not path: 426 if not path:
422 raise ValueError("no path specified") 427 raise ValueError("no path specified")
423 428
424 if isinstance(path, (bytes, bytearray)): 429 if isinstance(path, bytes):
425 curdir = b'.' 430 curdir = b'.'
426 sep = b'/' 431 sep = b'/'
427 pardir = b'..' 432 pardir = b'..'
428 else: 433 else:
429 curdir = '.' 434 curdir = '.'
430 sep = '/' 435 sep = '/'
431 pardir = '..' 436 pardir = '..'
432 437
433 if start is None: 438 if start is None:
434 start = curdir 439 start = curdir
435 440
436 start_list = abspath(start).split(sep) 441 start_list = abspath(start).split(sep)
437 path_list = abspath(path).split(sep) 442 path_list = abspath(path).split(sep)
438 443
439 # Work out how much of the filepath is shared by start and path. 444 # Work out how much of the filepath is shared by start and path.
440 i = len(commonprefix([start_list, path_list])) 445 i = len(commonprefix([start_list, path_list]))
441 446
442 rel_list = [pardir] * (len(start_list)-i) + path_list[i:] 447 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
443 if not rel_list: 448 if not rel_list:
444 return curdir 449 return curdir
445 return join(*rel_list) 450 return join(*rel_list)
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld r483