From 95fbdac55cb87d390dad1a9ac3a6469076d45833 Mon Sep 17 00:00:00 2001 From: Miloud Belarebia <136994453+miloudbelarebia@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:35:42 +0200 Subject: [PATCH] api: resolve get_url path relative to repo root `dvc.api.get_url()` documents `path` as relative to the repo root, but `get_data_index_entry` resolved a relative path against the current working directory. From a subdirectory of the repo this produced a wrong index key and raised OutputNotFoundError. Anchor the path at the dvcfs root marker. Closes #11029 --- dvc/repo/__init__.py | 6 +++++- tests/func/api/test_data.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/dvc/repo/__init__.py b/dvc/repo/__init__.py index a7c3d4d7ca..e878590342 100644 --- a/dvc/repo/__init__.py +++ b/dvc/repo/__init__.py @@ -388,8 +388,12 @@ def get_data_index_entry( workspace: str = "repo", ) -> tuple["DataIndex", "DataIndexEntry"]: if self.subrepos: - fs_path = self.dvcfs.from_os_path(path) fs = self.dvcfs.fs + fs_path = self.dvcfs.from_os_path(path) + # `path` is relative to the repo root, so anchor it there instead of + # letting it resolve against the current working directory (#11029). + if not fs_path.startswith(fs.root_marker): + fs_path = fs.join(fs.root_marker, fs_path) key = fs._get_key_from_relative(fs_path) subrepo, _, key = fs._get_subrepo_info(key) index = subrepo.index.data[workspace] diff --git a/tests/func/api/test_data.py b/tests/func/api/test_data.py index 48d4e98eed..2c948ae00c 100644 --- a/tests/func/api/test_data.py +++ b/tests/func/api/test_data.py @@ -32,6 +32,18 @@ def test_get_url_requires_dvc(tmp_dir, scm): api.get_url("foo", repo=f"file://{tmp_dir.as_posix()}") +def test_get_url_from_subdir(tmp_dir, dvc, local_remote): + # `path` is documented as relative to the repo root, so the result must not + # depend on the current working directory (see #11029). + tmp_dir.dvc_gen("foo", "foo") + subdir = tmp_dir / "subdir" + subdir.mkdir() + + expected = api.get_url("foo", repo=os.fspath(tmp_dir)) + with subdir.chdir(): + assert api.get_url("foo", repo=os.fspath(tmp_dir)) == expected + + def test_get_url_from_remote(tmp_dir, erepo_dir, cloud, local_cloud): erepo_dir.add_remote(config=cloud.config, name="other") erepo_dir.add_remote(config=local_cloud.config, default=True)