Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion marimo/_cli/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@ def include_features(dep: str, features: list[DepFeatures]) -> str:
return filtered + [include_features(chosen, additional_features)]


def _resolve_local_path_line(line: str, script_dir: Path) -> str:
"""Resolve a relative local-path requirement to an absolute path.

>>> _resolve_local_path_line(
... "-e ../pkg ; py<'3.12' # via foo", Path("/a/b")
... )
'-e /a/pkg ; py<\\'3.12\\' # via foo'
"""
rest = line.removeprefix("-e ")
path_and_comment, _, _ = rest.partition(";")
path_token, _, _ = path_and_comment.partition(" #")
path_token = path_token.rstrip()
if not path_token.startswith("."):
return line
resolved = str((script_dir / path_token).resolve())
return line.replace(path_token, resolved, 1)


def _uv_export_script_requirements_txt(
name: str | None,
) -> list[str]:
Expand All @@ -202,7 +220,11 @@ def _uv_export_script_requirements_txt(
capture_output=True,
text=True,
)
return result.stdout.split("\n")
script_dir = Path(name).resolve().parent
return [
_resolve_local_path_line(line, script_dir)
for line in result.stdout.split("\n")
]


def _resolve_requirements_txt_lines(pyproject: PyProjectReader) -> list[str]:
Expand Down
37 changes: 33 additions & 4 deletions tests/_cli/test_sandbox.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from __future__ import annotations

import os
from typing import TYPE_CHECKING, Any
from pathlib import Path
from typing import Any
from unittest.mock import patch

if TYPE_CHECKING:
from pathlib import Path

import pytest

from marimo._cli.sandbox import (
Expand Down Expand Up @@ -845,3 +843,34 @@ def test_build_sandbox_venv_with_additional_deps(tmp_path: Path) -> None:
assert os.path.exists(venv_python)
finally:
cleanup_sandbox_dir(sandbox_dir)


def test_resolve_local_path_line() -> None:
from marimo._cli.sandbox import _resolve_local_path_line

d = Path("/project/notebooks")
_r = lambda p: str((d / p).resolve()) # noqa: E731

# Plain relative
assert _resolve_local_path_line("../../mylib", d) == _r("../../mylib")
# Editable
assert _resolve_local_path_line("-e ../pkg", d) == f"-e {_r('../pkg')}"
# Env marker
result = _resolve_local_path_line("../pkg ; py<'3.12'", d)
assert _r("../pkg") in result
assert "py<'3.12'" in result
# Inline comment
result = _resolve_local_path_line("../pkg # via foo", d)
assert _r("../pkg") in result
assert "# via foo" in result
# Both marker and comment
result = _resolve_local_path_line("../pkg ; py<'3.12' # via foo", d)
assert _r("../pkg") in result
assert "py<'3.12'" in result
assert "# via foo" in result
# Spaces in path
assert _r("../my lib") in _resolve_local_path_line("../my lib", d)
# Non-relative unchanged
assert _resolve_local_path_line("numpy==1.26.0", d) == "numpy==1.26.0"
assert _resolve_local_path_line("/absolute/path", d) == "/absolute/path"
assert _resolve_local_path_line("", d) == ""
Loading