Skip to content

Commit ccc1841

Browse files
VishakBaddurdmadisettipre-commit-ci[bot]
authored
fix: resolve relative path sources in --sandbox uv export (#9052)
Fixes #8980 ## Problem `marimo edit --sandbox` fails when a script's inline metadata uses relative `path` sources in `[tool.uv.sources]`. `uv export --script` returns paths relative to the script file, but those lines get written to a temp requirements file. When `uv run --with-requirements` processes that file, it resolves paths relative to CWD - not the script's directory - causing path resolution failures. ## Fix In `_uv_export_script_requirements_txt` (`marimo/_cli/sandbox.py`), convert any relative paths (`.`-prefixed) to absolute paths using the script's parent directory as the base. Handles both editable (`-e ../../`) and non-editable (`../../`) path sources. Non-path deps and already-absolute paths are left unchanged. ## Test Added `test_uv_export_script_requirements_txt_resolves_relative_paths` covering: - Editable relative paths (`-e ../../`) → resolved to absolute - Non-editable relative paths (`../other_pkg`) → resolved to absolute - Regular deps (`numpy==1.26.0`) → unchanged - Already-absolute paths → unchanged --------- Co-authored-by: dmadisetti <dmadisetti@coreweave.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 4c071de commit ccc1841

2 files changed

Lines changed: 56 additions & 5 deletions

File tree

marimo/_cli/sandbox.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,24 @@ def include_features(dep: str, features: list[DepFeatures]) -> str:
182182
return filtered + [include_features(chosen, additional_features)]
183183

184184

185+
def _resolve_local_path_line(line: str, script_dir: Path) -> str:
186+
"""Resolve a relative local-path requirement to an absolute path.
187+
188+
>>> _resolve_local_path_line(
189+
... "-e ../pkg ; py<'3.12' # via foo", Path("/a/b")
190+
... )
191+
'-e /a/pkg ; py<\\'3.12\\' # via foo'
192+
"""
193+
rest = line.removeprefix("-e ")
194+
path_and_comment, _, _ = rest.partition(";")
195+
path_token, _, _ = path_and_comment.partition(" #")
196+
path_token = path_token.rstrip()
197+
if not path_token.startswith("."):
198+
return line
199+
resolved = str((script_dir / path_token).resolve())
200+
return line.replace(path_token, resolved, 1)
201+
202+
185203
def _uv_export_script_requirements_txt(
186204
name: str | None,
187205
) -> list[str]:
@@ -202,7 +220,11 @@ def _uv_export_script_requirements_txt(
202220
capture_output=True,
203221
text=True,
204222
)
205-
return result.stdout.split("\n")
223+
script_dir = Path(name).resolve().parent
224+
return [
225+
_resolve_local_path_line(line, script_dir)
226+
for line in result.stdout.split("\n")
227+
]
206228

207229

208230
def _resolve_requirements_txt_lines(pyproject: PyProjectReader) -> list[str]:

tests/_cli/test_sandbox.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
from __future__ import annotations
22

33
import os
4-
from typing import TYPE_CHECKING, Any
4+
from pathlib import Path
5+
from typing import Any
56
from unittest.mock import patch
67

7-
if TYPE_CHECKING:
8-
from pathlib import Path
9-
108
import pytest
119

1210
from marimo._cli.sandbox import (
@@ -845,3 +843,34 @@ def test_build_sandbox_venv_with_additional_deps(tmp_path: Path) -> None:
845843
assert os.path.exists(venv_python)
846844
finally:
847845
cleanup_sandbox_dir(sandbox_dir)
846+
847+
848+
def test_resolve_local_path_line() -> None:
849+
from marimo._cli.sandbox import _resolve_local_path_line
850+
851+
d = Path("/project/notebooks")
852+
_r = lambda p: str((d / p).resolve()) # noqa: E731
853+
854+
# Plain relative
855+
assert _resolve_local_path_line("../../mylib", d) == _r("../../mylib")
856+
# Editable
857+
assert _resolve_local_path_line("-e ../pkg", d) == f"-e {_r('../pkg')}"
858+
# Env marker
859+
result = _resolve_local_path_line("../pkg ; py<'3.12'", d)
860+
assert _r("../pkg") in result
861+
assert "py<'3.12'" in result
862+
# Inline comment
863+
result = _resolve_local_path_line("../pkg # via foo", d)
864+
assert _r("../pkg") in result
865+
assert "# via foo" in result
866+
# Both marker and comment
867+
result = _resolve_local_path_line("../pkg ; py<'3.12' # via foo", d)
868+
assert _r("../pkg") in result
869+
assert "py<'3.12'" in result
870+
assert "# via foo" in result
871+
# Spaces in path
872+
assert _r("../my lib") in _resolve_local_path_line("../my lib", d)
873+
# Non-relative unchanged
874+
assert _resolve_local_path_line("numpy==1.26.0", d) == "numpy==1.26.0"
875+
assert _resolve_local_path_line("/absolute/path", d) == "/absolute/path"
876+
assert _resolve_local_path_line("", d) == ""

0 commit comments

Comments
 (0)