Skip to content

Commit cae4cdd

Browse files
nineteendoAlexWaygoodbarneygaleeendebakpt
authored
gh-117349: Micro-optimize a few os.path functions (#117350)
Co-authored-by: Alex Waygood <[email protected]> Co-authored-by: Barney Gale <[email protected]> Co-authored-by: Pieter Eendebak <[email protected]>
1 parent 8eda146 commit cae4cdd

File tree

4 files changed

+35
-39
lines changed

4 files changed

+35
-39
lines changed

Lib/ntpath.py

+13-16
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ def join(path, *paths):
102102
if isinstance(path, bytes):
103103
sep = b'\\'
104104
seps = b'\\/'
105-
colon = b':'
105+
colon_seps = b':\\/'
106106
else:
107107
sep = '\\'
108108
seps = '\\/'
109-
colon = ':'
109+
colon_seps = ':\\/'
110110
try:
111111
if not paths:
112112
path[:0] + sep #23780: Ensure compatible data type even if p is null.
@@ -135,7 +135,7 @@ def join(path, *paths):
135135
result_path = result_path + p_path
136136
## add separator between UNC and non-absolute path
137137
if (result_path and not result_root and
138-
result_drive and result_drive[-1:] not in colon + seps):
138+
result_drive and result_drive[-1] not in colon_seps):
139139
return result_drive + sep + result_path
140140
return result_drive + result_root + result_path
141141
except (TypeError, AttributeError, BytesWarning):
@@ -279,7 +279,7 @@ def isjunction(path):
279279
st = os.lstat(path)
280280
except (OSError, ValueError, AttributeError):
281281
return False
282-
return bool(st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT)
282+
return st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT
283283
else:
284284
# Use genericpath.isjunction as imported above
285285
pass
@@ -340,8 +340,8 @@ def isreserved(path):
340340
def _isreservedname(name):
341341
"""Return true if the filename is reserved by the system."""
342342
# Trailing dots and spaces are reserved.
343-
if name.endswith(('.', ' ')) and name not in ('.', '..'):
344-
return True
343+
if name[-1:] in ('.', ' '):
344+
return name not in ('.', '..')
345345
# Wildcards, separators, colon, and pipe (*?"<>/\:|) are reserved.
346346
# ASCII control characters (0-31) are reserved.
347347
# Colon is reserved for file streams (e.g. "name:stream[:type]").
@@ -350,9 +350,7 @@ def _isreservedname(name):
350350
# DOS device names are reserved (e.g. "nul" or "nul .txt"). The rules
351351
# are complex and vary across Windows versions. On the side of
352352
# caution, return True for names that may not be reserved.
353-
if name.partition('.')[0].rstrip(' ').upper() in _reserved_names:
354-
return True
355-
return False
353+
return name.partition('.')[0].rstrip(' ').upper() in _reserved_names
356354

357355

358356
# Expand paths beginning with '~' or '~user'.
@@ -381,13 +379,10 @@ def expanduser(path):
381379

382380
if 'USERPROFILE' in os.environ:
383381
userhome = os.environ['USERPROFILE']
384-
elif not 'HOMEPATH' in os.environ:
382+
elif 'HOMEPATH' not in os.environ:
385383
return path
386384
else:
387-
try:
388-
drive = os.environ['HOMEDRIVE']
389-
except KeyError:
390-
drive = ''
385+
drive = os.environ.get('HOMEDRIVE', '')
391386
userhome = join(drive, os.environ['HOMEPATH'])
392387

393388
if i != 1: #~user
@@ -727,15 +722,17 @@ def realpath(path, *, strict=False):
727722
new_unc_prefix = b'\\\\'
728723
cwd = os.getcwdb()
729724
# bpo-38081: Special case for realpath(b'nul')
730-
if normcase(path) == normcase(os.fsencode(devnull)):
725+
devnull = b'nul'
726+
if normcase(path) == devnull:
731727
return b'\\\\.\\NUL'
732728
else:
733729
prefix = '\\\\?\\'
734730
unc_prefix = '\\\\?\\UNC\\'
735731
new_unc_prefix = '\\\\'
736732
cwd = os.getcwd()
737733
# bpo-38081: Special case for realpath('nul')
738-
if normcase(path) == normcase(devnull):
734+
devnull = 'nul'
735+
if normcase(path) == devnull:
739736
return '\\\\.\\NUL'
740737
had_prefix = path.startswith(prefix)
741738
if not had_prefix and not isabs(path):

Lib/posixpath.py

+20-23
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,8 @@ def ismount(path):
213213
except (OSError, ValueError):
214214
return False
215215

216-
dev1 = s1.st_dev
217-
dev2 = s2.st_dev
218-
if dev1 != dev2:
219-
return True # path/.. on a different device as path
220-
ino1 = s1.st_ino
221-
ino2 = s2.st_ino
222-
if ino1 == ino2:
223-
return True # path/.. is the same i-node as path
224-
return False
216+
# path/.. on a different device as path or the same i-node as path
217+
return s1.st_dev != s2.st_dev or s1.st_ino == s2.st_ino
225218

226219

227220
# Expand paths beginning with '~' or '~user'.
@@ -270,7 +263,7 @@ def expanduser(path):
270263
return path
271264
name = path[1:i]
272265
if isinstance(name, bytes):
273-
name = str(name, 'ASCII')
266+
name = name.decode('ascii')
274267
try:
275268
pwent = pwd.getpwnam(name)
276269
except KeyError:
@@ -359,21 +352,19 @@ def normpath(path):
359352
path = os.fspath(path)
360353
if isinstance(path, bytes):
361354
sep = b'/'
362-
empty = b''
363355
dot = b'.'
364356
dotdot = b'..'
365357
else:
366358
sep = '/'
367-
empty = ''
368359
dot = '.'
369360
dotdot = '..'
370-
if path == empty:
361+
if not path:
371362
return dot
372363
_, initial_slashes, path = splitroot(path)
373364
comps = path.split(sep)
374365
new_comps = []
375366
for comp in comps:
376-
if comp in (empty, dot):
367+
if not comp or comp == dot:
377368
continue
378369
if (comp != dotdot or (not initial_slashes and not new_comps) or
379370
(new_comps and new_comps[-1] == dotdot)):
@@ -396,12 +387,12 @@ def normpath(path):
396387
def abspath(path):
397388
"""Return an absolute path."""
398389
path = os.fspath(path)
399-
if not isabs(path):
400-
if isinstance(path, bytes):
401-
cwd = os.getcwdb()
402-
else:
403-
cwd = os.getcwd()
404-
path = join(cwd, path)
390+
if isinstance(path, bytes):
391+
if not path.startswith(b'/'):
392+
path = join(os.getcwdb(), path)
393+
else:
394+
if not path.startswith('/'):
395+
path = join(os.getcwd(), path)
405396
return normpath(path)
406397

407398

@@ -417,6 +408,7 @@ def realpath(filename, *, strict=False):
417408

418409
# Join two paths, normalizing and eliminating any symbolic links
419410
# encountered in the second path.
411+
# Two leading slashes are replaced by a single slash.
420412
def _joinrealpath(path, rest, strict, seen):
421413
if isinstance(path, bytes):
422414
sep = b'/'
@@ -427,7 +419,7 @@ def _joinrealpath(path, rest, strict, seen):
427419
curdir = '.'
428420
pardir = '..'
429421

430-
if isabs(rest):
422+
if rest.startswith(sep):
431423
rest = rest[1:]
432424
path = sep
433425

@@ -439,10 +431,15 @@ def _joinrealpath(path, rest, strict, seen):
439431
if name == pardir:
440432
# parent dir
441433
if path:
442-
path, name = split(path)
434+
parent, name = split(path)
443435
if name == pardir:
444-
path = join(path, pardir, pardir)
436+
# ../..
437+
path = join(path, pardir)
438+
else:
439+
# foo/bar/.. -> foo
440+
path = parent
445441
else:
442+
# ..
446443
path = pardir
447444
continue
448445
newpath = join(path, name)

Misc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ Finn Bock
191191
Paul Boddie
192192
Matthew Boedicker
193193
Robin Boerdijk
194+
Wannes Boeykens
194195
Andra Bogildea
195196
Matt Bogosian
196197
Nikolay Bogoychev
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Optimise several functions in :mod:`os.path`.

0 commit comments

Comments
 (0)