Skip to content

Commit 58fc7f7

Browse files
committed
fix: Support notebook arguments when exporting thumbnail
Specifically for the thumbnails, special logic was used to support multiple paths as arguments. Unfortunately, that logic broke when using notebook arguments. Since `--` is not passed through by click when interspersed args are allowed, and every argument is wrongly extracted as a path. Removing the logic to split paths out of the arguments drops the support for multiple paths at once, restores the support to forward notebook arguments, while retaining the ability to put export options before or after the path. It makes things most consistent with other export commands. I added two tests that do run the command and assert that it completes successfully, only when the required dependencies are present and without verifying the output. I am also leaving some simple tests that test Click more than they test actual Marimo code, but might be useful as illustration/sandbox anyways.
1 parent a431d66 commit 58fc7f7

File tree

2 files changed

+93
-15
lines changed

2 files changed

+93
-15
lines changed

marimo/_cli/export/thumbnail.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,6 @@
3737
_READINESS_WAIT_TIMEOUT_MS = 30_000
3838

3939

40-
def _split_paths_and_args(
41-
name: str, args: tuple[str, ...]
42-
) -> tuple[list[str], tuple[str, ...]]:
43-
paths = [name]
44-
for index, arg in enumerate(args):
45-
if arg == "--":
46-
return paths, args[index + 1 :]
47-
paths.append(arg)
48-
return paths, ()
49-
50-
5140
def _collect_notebooks(paths: Iterable[Path]) -> list[MarimoPath]:
5241
notebooks: dict[str, MarimoPath] = {}
5342

@@ -531,8 +520,7 @@ def thumbnail(
531520
) from None
532521
raise
533522

534-
paths, notebook_args = _split_paths_and_args(str(name), args)
535-
notebooks = _collect_notebooks([Path(p) for p in paths])
523+
notebooks = _collect_notebooks([Path(name)])
536524
if not notebooks:
537525
raise click.ClickException("No marimo notebooks found.")
538526
if output is not None and len(notebooks) > 1:
@@ -562,7 +550,7 @@ def thumbnail(
562550
overwrite=overwrite,
563551
include_code=include_code,
564552
execute=execute,
565-
notebook_args=notebook_args,
553+
notebook_args=args,
566554
continue_on_error=continue_on_error,
567555
sandbox=sandbox_mode is not None,
568556
)

tests/_cli/test_cli_export.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
import time
1111
from os import path
1212
from pathlib import Path
13-
from typing import TYPE_CHECKING
13+
from typing import TYPE_CHECKING, Any
1414

15+
import click
1516
import pytest
1617

1718
from marimo._dependencies.dependencies import DependencyManager
@@ -860,3 +861,92 @@ def test_export_pdf_missing_dependencies(
860861
stderr = p.stderr.decode()
861862
assert "nbconvert" in stderr
862863
assert "pip install" in stderr
864+
865+
866+
@pytest.mark.skipif(
867+
not DependencyManager.playwright.has(),
868+
reason="This test requires playwright.",
869+
)
870+
class TestExportThumbnail:
871+
def test_export_thumbnail(self, temp_marimo_file: str) -> None:
872+
p = _run_export("thumbnail", temp_marimo_file)
873+
_assert_success(p)
874+
875+
def test_export_thumbnail_with_args(self, temp_marimo_file: str) -> None:
876+
p = _run_export("thumbnail", temp_marimo_file, "--", "--foo", "123")
877+
_assert_success(p)
878+
879+
880+
class TestClickArgsParsing:
881+
"""
882+
Tests below are technically testing Click more than Marimo. This was created as part of an investigation into
883+
the Click option to allow interspersed arguments or not, and the presence of "--" in the `args` parameter.
884+
885+
In review, we discussed leaving some of the tests behind to continue illustrating. They can also act as a sort of
886+
sandbox to try alternative approaches.
887+
"""
888+
889+
@staticmethod
890+
def _params(
891+
command, expected_name, expected_args, expected_opt
892+
) -> tuple[Any, ...]:
893+
return pytest.param(
894+
command,
895+
expected_name,
896+
expected_args,
897+
expected_opt,
898+
id=f"`test_command {' '.join(command)}`",
899+
)
900+
901+
@pytest.mark.parametrize(
902+
(
903+
"command",
904+
"expected_name",
905+
"expected_args",
906+
"expected_opt",
907+
),
908+
[
909+
_params(["nb.py"], "nb.py", (), False),
910+
_params(["--opt", "nb.py"], "nb.py", (), True),
911+
_params(["nb.py", "--opt"], "nb.py", (), True),
912+
_params(
913+
["nb.py", "--", "--foo", "123"],
914+
"nb.py",
915+
("--foo", "123"),
916+
False,
917+
),
918+
_params(
919+
["--opt", "nb.py", "--", "--foo", "123"],
920+
"nb.py",
921+
("--foo", "123"),
922+
True,
923+
),
924+
_params(
925+
["nb.py", "--opt", "--", "--foo", "123"],
926+
"nb.py",
927+
("--foo", "123"),
928+
True,
929+
),
930+
],
931+
)
932+
def test_click_args_parsing(
933+
self,
934+
command: list[str],
935+
expected_name: str,
936+
expected_args: tuple[str, ...],
937+
expected_opt: bool,
938+
) -> None:
939+
@click.command("test_command")
940+
@click.argument("name")
941+
@click.option("--opt/--no-opt", default=False)
942+
@click.argument("args", nargs=-1, type=click.UNPROCESSED)
943+
def test_command(
944+
name: str, opt: bool, args: tuple[str, ...]
945+
) -> tuple[str, tuple[str, ...], bool]:
946+
return name, args, opt
947+
948+
assert test_command.main(command, standalone_mode=False) == (
949+
expected_name,
950+
expected_args,
951+
expected_opt,
952+
)

0 commit comments

Comments
 (0)