From a7711a2a4e5cf16b34fc284085da724a8c2c06dd Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Wed, 1 May 2024 23:44:55 +0200 Subject: [PATCH] gh-117607: Speedup os.path.relpath() (GH-117608) --- Lib/ntpath.py | 19 ++++++++++--------- Lib/posixpath.py | 8 +++++--- ...-04-07-18-42-09.gh-issue-117607.C978BD.rst | 1 + 3 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-07-18-42-09.gh-issue-117607.C978BD.rst diff --git a/Lib/ntpath.py b/Lib/ntpath.py index e810b655e5ac85..b833e0bad2645f 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -805,6 +805,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'.' @@ -816,22 +819,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): @@ -842,7 +843,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 diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 56b7915826daf4..f189c3359fbea6 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -532,15 +532,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 diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-07-18-42-09.gh-issue-117607.C978BD.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-07-18-42-09.gh-issue-117607.C978BD.rst new file mode 100644 index 00000000000000..0c17dfd95ec0ec --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-07-18-42-09.gh-issue-117607.C978BD.rst @@ -0,0 +1 @@ +Speedup :func:`os.path.relpath`.