Skip to content

gh-117607: Speedup os.path.relpath() #117608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 1, 2024
19 changes: 10 additions & 9 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,9 @@ def realpath(path, *, strict=False):
def relpath(path, start=None):
"""Return a relative version of a path"""
path = os.fspath(path)
if not path:
raise ValueError("no path specified")

if isinstance(path, bytes):
sep = b'\\'
curdir = b'.'
Expand All @@ -796,22 +799,20 @@ def relpath(path, start=None):

if start is None:
start = curdir
else:
start = os.fspath(start)

if not path:
raise ValueError("no path specified")

start = os.fspath(start)
try:
start_abs = abspath(normpath(start))
path_abs = abspath(normpath(path))
start_abs = abspath(start)
path_abs = abspath(path)
start_drive, _, start_rest = splitroot(start_abs)
path_drive, _, path_rest = splitroot(path_abs)
if normcase(start_drive) != normcase(path_drive):
raise ValueError("path is on mount %r, start on mount %r" % (
path_drive, start_drive))

start_list = [x for x in start_rest.split(sep) if x]
path_list = [x for x in path_rest.split(sep) if x]
start_list = start_rest.split(sep) if start_rest else []
path_list = path_rest.split(sep) if path_rest else []
# Work out how much of the filepath is shared by start and path.
i = 0
for e1, e2 in zip(start_list, path_list):
Expand All @@ -822,7 +823,7 @@ def relpath(path, start=None):
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return curdir
return join(*rel_list)
return sep.join(rel_list)
except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
genericpath._check_arg_types('relpath', path, start)
raise
Expand Down
8 changes: 5 additions & 3 deletions Lib/posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,15 +521,17 @@ def relpath(path, start=None):
start = os.fspath(start)

try:
start_list = [x for x in abspath(start).split(sep) if x]
path_list = [x for x in abspath(path).split(sep) if x]
start_tail = abspath(start).lstrip(sep)
path_tail = abspath(path).lstrip(sep)
start_list = start_tail.split(sep) if start_tail else []
path_list = path_tail.split(sep) if path_tail else []
# Work out how much of the filepath is shared by start and path.
i = len(commonprefix([start_list, path_list]))

rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return curdir
return join(*rel_list)
return sep.join(rel_list)
except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
genericpath._check_arg_types('relpath', path, start)
raise
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Speedup :func:`os.path.relpath`.