From 4b6ebc75277d201da3c36600ff7251075d9fc18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Musa=20Atl=C4=B1han?= Date: Mon, 19 Oct 2020 11:53:01 +0300 Subject: [PATCH] make pull --run-cache work with local remote having relative path (#4670) * Fixes #4637 * use PathInfo instead of Path * catch ValueError with PathInfo.relative_to and fallback to dvc.utils.relpath * cleanup * add test Co-authored-by: Peter Rowlands --- dvc/path_info.py | 11 +++++++++++ tests/unit/test_path_info.py | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/dvc/path_info.py b/dvc/path_info.py index 18ffaf04a..c170086bd 100644 --- a/dvc/path_info.py +++ b/dvc/path_info.py @@ -75,6 +75,17 @@ class PathInfo(pathlib.PurePath, _BasePath): n = len(other._cparts) return len(self._cparts) > n and self._cparts[:n] == other._cparts + def relative_to(self, other): # pylint: disable=arguments-differ + # pathlib relative_to raises exception when one path is not a direct + # descendant of the other when os.path.relpath would return abspath. + # For DVC PathInfo we only need the relpath behavior. + # See: https://bugs.python.org/issue40358 + try: + path = super().relative_to(other) + except ValueError: + path = relpath(self, other) + return self.__class__(path) + class WindowsPathInfo(PathInfo, pathlib.PureWindowsPath): pass diff --git a/tests/unit/test_path_info.py b/tests/unit/test_path_info.py index 9f4ba3e1b..c4f6bc40e 100644 --- a/tests/unit/test_path_info.py +++ b/tests/unit/test_path_info.py @@ -1,4 +1,5 @@ import copy +import os import pathlib import pytest @@ -102,3 +103,17 @@ def test_url_replace_path(): assert u.params == new_u.params assert u.query == new_u.query assert u.fragment == new_u.fragment + + +@pytest.mark.parametrize( + "p1, p2", + [ + ("/foo/bar", "/baz"), + ("/baz", "/foo/bar"), + ("/foo/bar", "../baz"), + ("../baz", "/foo/bar"), + ], +) +def test_relative_to_different_subpath(p1, p2): + expected = PathInfo(os.path.relpath(p1, p2)) + assert PathInfo(p1).relative_to(PathInfo(p2)) == expected