From e8e1c76504895f846ef5724c02f5414f4a251f7f Mon Sep 17 00:00:00 2001 From: Ruslan Kuprieiev Date: Tue, 7 Dec 2021 19:29:04 +0200 Subject: [PATCH] fs: path: use ntpath/posixpath This is less error-prone than implementing these methods ourselves. --- dvc/fs/path.py | 56 +++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/dvc/fs/path.py b/dvc/fs/path.py index f06c3b1224..cde2b44f2d 100644 --- a/dvc/fs/path.py +++ b/dvc/fs/path.py @@ -1,34 +1,44 @@ +import ntpath import posixpath class Path: - """ - Class for operations on simple string paths. + def __init__(self, sep): + if sep == posixpath.sep: + self.flavour = posixpath + elif sep == ntpath.sep: + self.flavour = ntpath + else: + raise ValueError(f"unsupported separator '{sep}'") - This is meant to be very efficient and so doesn't use os.path, - doesn't have any notion of cwd and assumes that we are always - operating on absolute paths. - """ + def join(self, *parts): + return self.flavour.join(*parts) - def __init__(self, sep: str): - self.sep = sep + def parts(self, path): + drive, path = self.flavour.splitdrive(path) - def join(self, *parts): - if len(parts) == 0: - return None - if len(parts) == 1: - return parts[0] + ret = [] + while True: + path, part = self.flavour.split(path) - return self.sep.join(parts) + if part: + ret.append(part) + continue - def parts(self, path): - return tuple(path.split(self.sep)) + if path: + ret.append(path) + + break + + ret.reverse() + + if drive: + ret = [drive] + ret + + return tuple(ret) def parent(self, path): - parts = path.rsplit(self.sep, 1) - if len(parts) == 1: - return "" - return parts[0] + return self.flavour.dirname(path) def parents(self, path): parts = self.parts(path) @@ -73,12 +83,12 @@ def overlaps(self, left, right): def relpath(self, path, base): assert len(path) > len(base) assert path.startswith(base) - normpath = path.rstrip(self.sep) - normbase = base.rstrip(self.sep) + normpath = path.rstrip(self.flavour.sep) + normbase = base.rstrip(self.flavour.sep) return normpath[len(normbase) + 1 :] def relparts(self, path, base): return self.parts(self.relpath(path, base)) def as_posix(self, path): - return path.replace(self.sep, posixpath.sep) + return path.replace(self.flavour.sep, posixpath.sep)