Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c90a883
Speed up `posixpath.ismount`
nineteendo Mar 28, 2024
5984959
Speed up `posixpath.expanduser`
nineteendo Mar 28, 2024
833ddc9
Speed up `posixpath.normpath`
nineteendo Mar 28, 2024
a4d9fcb
Refactor `posixpath.expandvars` & `ntpath.commonpath`
nineteendo Mar 28, 2024
b853d4d
Remove start- & endswith
nineteendo Mar 29, 2024
a8984dc
Remove `startswith`
nineteendo Mar 29, 2024
78929b0
Remove `isabs` calls
nineteendo Mar 29, 2024
afc7bbc
Rename result of `splitroot`
nineteendo Mar 29, 2024
f5bbaf6
Refactor `os.path`
nineteendo Mar 29, 2024
e740f10
fix unbound variable
nineteendo Mar 29, 2024
d02c726
hardcode constants like documented
nineteendo Mar 29, 2024
b794897
📜🤖 Added by blurb_it.
blurb-it[bot] Mar 29, 2024
c2c04bf
Fix typo
nineteendo Mar 29, 2024
7c9dcae
exclude stylistic-only changes
nineteendo Mar 29, 2024
d35783c
Revert renaming
nineteendo Mar 29, 2024
eb24723
Revert unnesting
nineteendo Mar 29, 2024
5ca9ea3
Revert further changes
nineteendo Mar 29, 2024
3e4d0e3
Revert renaming
nineteendo Mar 29, 2024
72babad
Remove newline
nineteendo Mar 29, 2024
abfe46c
Remove slice
nineteendo Mar 30, 2024
2a055ba
Speedup `posixpath.ismount`
nineteendo Mar 30, 2024
759b189
Update Lib/posixpath.py
nineteendo Mar 30, 2024
cca16ba
Revert unnesting
nineteendo Mar 30, 2024
7e21192
Merge branch 'speedup-os.path' of https://github.com/nineteendo/cpyth…
nineteendo Mar 30, 2024
581862e
Remove line breaks
nineteendo Mar 30, 2024
d2987fd
Revert `ntpath.expandvars`
nineteendo Mar 30, 2024
1866544
Unexpose `posixpath._normpath_fallback`
nineteendo Mar 30, 2024
4a01123
Update Lib/posixpath.py
nineteendo Mar 30, 2024
67f0620
Indent for git blame
nineteendo Mar 30, 2024
9905730
Merge branch 'speedup-os.path' of https://github.com/nineteendo/cpyth…
nineteendo Mar 30, 2024
9d18f8c
Move back in except
nineteendo Mar 30, 2024
9520cc6
Revert changing comment
nineteendo Mar 30, 2024
de4b09e
Split try except blocks
nineteendo Mar 30, 2024
6f8e7d7
Update Misc/NEWS.d/next/Core and Builtins/2024-03-29-15-04-13.gh-issu…
nineteendo Mar 30, 2024
47a4b57
Update ACKS
nineteendo Mar 30, 2024
48f2971
Remove `_get_sep()` call
nineteendo Mar 30, 2024
33259d9
Revert unnecessary change
nineteendo Mar 30, 2024
4568cd1
Revert insignificant changes
nineteendo Mar 30, 2024
1382f49
Fix incorrect change
nineteendo Mar 30, 2024
a81dc6e
Revert unnesting
nineteendo Mar 30, 2024
e6cb4a3
Move to new pull request
nineteendo Mar 30, 2024
67ec9a6
assign `devnull` first
nineteendo Mar 30, 2024
87d43b8
speedup `posixpath.realpath`
nineteendo Mar 31, 2024
6c8901a
Speedup `ntpath.isreserved()`
nineteendo Apr 1, 2024
7940a64
Revert starts- & endswith
nineteendo Apr 1, 2024
e637698
Revert `len()` call
nineteendo Apr 1, 2024
b5fdd27
;(
nineteendo Apr 1, 2024
c923e49
Merge branch 'main' into speedup-os.path
nineteendo Apr 2, 2024
887f3c1
Replace definition of colon
nineteendo Apr 2, 2024
e3ace2f
Merge branch 'speedup-os.path' of https://github.com/nineteendo/cpyth…
nineteendo Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor os.path
  • Loading branch information
nineteendo committed Mar 29, 2024
commit f5bbaf66b90e3640153f336774738334842725d3
164 changes: 77 additions & 87 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,17 @@ def _get_bothseps(path):
LCMapStringEx as _LCMapStringEx,
LOCALE_NAME_INVARIANT as _LOCALE_NAME_INVARIANT,
LCMAP_LOWERCASE as _LCMAP_LOWERCASE)
except ImportError:
def normcase(s):
"""Normalize case of pathname.

Comment thread
nineteendo marked this conversation as resolved.
Makes all characters lowercase and all slashes into backslashes.
"""
s = os.fspath(s)
if isinstance(s, bytes):
return os.fsencode(os.fsdecode(s).replace('/', '\\').lower())
return s.replace('/', '\\').lower()
else:
def normcase(s):
"""Normalize case of pathname.

Expand All @@ -66,16 +76,6 @@ def normcase(s):
return _LCMapStringEx(_LOCALE_NAME_INVARIANT,
_LCMAP_LOWERCASE,
s.replace('/', '\\'))
except ImportError:
Comment thread
AlexWaygood marked this conversation as resolved.
def normcase(s):
"""Normalize case of pathname.

Makes all characters lowercase and all slashes into backslashes.
"""
s = os.fspath(s)
if isinstance(s, bytes):
return os.fsencode(os.fsdecode(s).replace('/', '\\').lower())
return s.replace('/', '\\').lower()


def isabs(s):
Expand Down Expand Up @@ -279,9 +279,9 @@ def isjunction(path):
"""Test whether a path is a junction"""
try:
st = os.lstat(path)
return st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT
except (OSError, ValueError, AttributeError):
return False
return bool(st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT)
else:
# Use genericpath.isjunction as imported above
pass
Expand All @@ -301,6 +301,8 @@ def isjunction(path):
from nt import _getvolumepathname
except ImportError:
_getvolumepathname = None

Comment thread
AlexWaygood marked this conversation as resolved.
Outdated

def ismount(path):
"""Test whether a path is a mount point (a drive root, the root of a
share, or a mounted volume)"""
Expand All @@ -312,24 +314,22 @@ def ismount(path):
return not tail
if root and not tail:
return True

if _getvolumepathname:
x = path.rstrip(seps)
y =_getvolumepathname(path).rstrip(seps)
return x.casefold() == y.casefold()
else:
if not _getvolumepathname:
return False
x = path.rstrip(seps)
y = _getvolumepathname(path).rstrip(seps)
return x.casefold() == y.casefold()


_reserved_chars = frozenset(
{chr(i) for i in range(32)} |
{'"', '*', ':', '<', '>', '?', '|', '/', '\\'}
{chr(i) for i in range(32)}
| {'"', '*', ':', '<', '>', '?', '|', '/', '\\'}
)

_reserved_names = frozenset(
{'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
{f'COM{c}' for c in '123456789\xb9\xb2\xb3'} |
{f'LPT{c}' for c in '123456789\xb9\xb2\xb3'}
{'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'}
| {f'COM{c}' for c in '123456789\xb9\xb2\xb3'}
| {f'LPT{c}' for c in '123456789\xb9\xb2\xb3'}
)

def isreserved(path):
Expand All @@ -352,9 +352,7 @@ def _isreservedname(name):
# DOS device names are reserved (e.g. "nul" or "nul .txt"). The rules
# are complex and vary across Windows versions. On the side of
# caution, return True for names that may not be reserved.
if name.partition('.')[0].rstrip(' ').upper() in _reserved_names:
return True
return False
return name.partition('.')[0].rstrip(' ').upper() in _reserved_names


# Expand paths beginning with '~' or '~user'.
Expand Down Expand Up @@ -477,19 +475,17 @@ def expandvars(path):
pathlen = len(path)
try:
index = path.index(percent)
var = path[:index]
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
res += value
except ValueError:
res += percent + path
index = pathlen - 1
else:
var = path[:index]
try:
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
except KeyError:
value = percent + var + percent
res += value
except KeyError:
res += percent + var + percent
Comment thread
nineteendo marked this conversation as resolved.
Outdated
elif c == dollar: # variable or '$$'
if path[index + 1:index + 2] == dollar:
res += c
Expand All @@ -499,19 +495,17 @@ def expandvars(path):
pathlen = len(path)
try:
index = path.index(rbrace)
var = path[:index]
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
res += value
except ValueError:
res += dollar + brace + path
index = pathlen - 1
else:
var = path[:index]
try:
if environ is None:
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
except KeyError:
value = dollar + brace + var + rbrace
res += value
except KeyError:
res += dollar + brace + var + rbrace
Comment thread
nineteendo marked this conversation as resolved.
Outdated
else:
var = path[:0]
index += 1
Expand All @@ -525,9 +519,9 @@ def expandvars(path):
value = os.fsencode(os.environ[os.fsdecode(var)])
else:
value = environ[var]
res += value
except KeyError:
value = dollar + var
res += value
res += dollar + var
Comment thread
nineteendo marked this conversation as resolved.
Outdated
if c:
index -= 1
else:
Expand All @@ -542,6 +536,12 @@ def expandvars(path):
try:
from nt import _path_normpath

def normpath(path):
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
return _path_normpath(path) or "."
except ImportError:
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
Expand All @@ -564,29 +564,20 @@ def normpath(path):
while i < len(comps):
if not comps[i] or comps[i] == curdir:
del comps[i]
elif comps[i] == pardir:
if i > 0 and comps[i-1] != pardir:
del comps[i-1:i+1]
i -= 1
elif i == 0 and root:
del comps[i]
else:
i += 1
elif comps[i] != pardir:
i += 1
elif i > 0 and comps[i-1] != pardir:
del comps[i-1:i+1]
i -= 1
elif i == 0 and root:
del comps[i]
else:
i += 1
# If the path is now empty, substitute '.'
if not prefix and not comps:
comps.append(curdir)
return prefix + sep.join(comps)

Comment thread
nineteendo marked this conversation as resolved.
else:
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
return _path_normpath(path) or "."


def _abspath_fallback(path):
"""Return the absolute version of a path as a fallback function in case
Expand All @@ -607,10 +598,8 @@ def _abspath_fallback(path):
# Return an absolute path.
try:
from nt import _getfullpathname

Comment thread
AlexWaygood marked this conversation as resolved.
except ImportError: # not running on Windows - mock up something sensible
abspath = _abspath_fallback

else: # use native Windows method on Windows
def abspath(path):
"""Return the absolute version of a path."""
Expand Down Expand Up @@ -697,28 +686,28 @@ def _getfinalpathname_nonstrict(path):
except OSError as ex:
if ex.winerror not in allowed_winerror:
raise
try:
Comment thread
nineteendo marked this conversation as resolved.
Outdated
# The OS could not resolve this path fully, so we attempt
# to follow the link ourselves. If we succeed, join the tail
# and return.
new_path = _readlink_deep(path)
if new_path != path:
return join(new_path, tail) if tail else new_path
except OSError:
# If we fail to readlink(), let's keep traversing
pass
# If we get these errors, try to get the real name of the file without accessing it.
if ex.winerror in (1, 5, 32, 50, 87, 1920, 1921):
try:
# The OS could not resolve this path fully, so we attempt
# to follow the link ourselves. If we succeed, join the tail
# and return.
new_path = _readlink_deep(path)
if new_path != path:
return join(new_path, tail) if tail else new_path
name = _findfirstfile(path)
path, _ = split(path)
except OSError:
# If we fail to readlink(), let's keep traversing
pass
# If we get these errors, try to get the real name of the file without accessing it.
if ex.winerror in (1, 5, 32, 50, 87, 1920, 1921):
try:
name = _findfirstfile(path)
path, _ = split(path)
except OSError:
path, name = split(path)
else:
path, name = split(path)
if path and not name:
return path + tail
tail = join(name, tail) if tail else name
else:
path, name = split(path)
if path and not name:
return path + tail
tail = join(name, tail) if tail else name
return tail

def realpath(path, *, strict=False):
Expand Down Expand Up @@ -904,12 +893,13 @@ def commonpath(paths):

try:
from nt import _path_isdevdrive
except ImportError:
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
# Use genericpath.isdevdrive as imported above
pass
else:
def isdevdrive(path):
"""Determines whether the specified path is on a Windows Dev Drive."""
try:
return _path_isdevdrive(abspath(path))
except OSError:
return False
except ImportError:
# Use genericpath.isdevdrive as imported above
pass
18 changes: 8 additions & 10 deletions Lib/posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,9 @@ def split(p):
def splitext(p):
p = os.fspath(p)
if isinstance(p, bytes):
sep = b'/'
extsep = b'.'
return genericpath._splitext(p, b'/', None, b'.')
else:
sep = '/'
extsep = '.'
return genericpath._splitext(p, sep, None, extsep)
return genericpath._splitext(p, '/', None, '.')
splitext.__doc__ = genericpath._splitext.__doc__

# Split a pathname into a drive specification and the rest of the
Expand Down Expand Up @@ -248,9 +245,7 @@ def expanduser(path):
# bpo-10496: if the user name from the path doesn't exist in the
# password database, return the path unchanged
return path
elif 'HOME' in os.environ:
userhome = os.environ['HOME']
else:
elif 'HOME' not in os.environ:
try:
import pwd
userhome = pwd.getpwuid(os.getuid()).pw_dir
Expand All @@ -259,6 +254,8 @@ def expanduser(path):
# bpo-10496: if the current user identifier doesn't exist in the
# password database, return the path unchanged
return path
else:
userhome = os.environ['HOME']

# if no user home, return the path unchanged on VxWorks
if userhome is None and sys.platform == "vxworks":
Expand Down Expand Up @@ -361,14 +358,15 @@ def _normpath_fallback(path):

try:
from posix import _path_normpath
except ImportError:
normpath = _normpath_fallback
else:
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
path = os.fspath(path)
if isinstance(path, bytes):
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
return _path_normpath(path) or "."
except ImportError:
normpath = _normpath_fallback


def abspath(path):
Expand Down