Skip to content

Commit e2107bf

Browse files
authored
Merge pull request #13 from MITLibraries/IN-1441-base-url-flag
IN 1441 - support a base URL on notebook launch
2 parents 190fbaf + 7b3616c commit e2107bf

File tree

5 files changed

+194
-129
lines changed

5 files changed

+194
-129
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,20 @@ NOTEBOOK_PORT= ### port to serve running notebook on
118118
Base command
119119

120120
```text
121-
Usage: launcher [OPTIONS] COMMAND [ARGS]...
121+
Usage: uv run marimo-launcher [OPTIONS] COMMAND [ARGS]...
122122
123123
Options:
124124
-v, --verbose Pass to log at debug level instead of info
125125
--help Show this message and exit.
126126
127127
Commands:
128-
run
129-
validate
128+
run Launch notebook in 'run' or 'edit' mode.
130129
```
131130

132131
### `launcher run`
133132

134133
```text
135-
Usage: python -m launcher.cli run [OPTIONS]
134+
Usage: uv run marimo-launcher run [OPTIONS]
136135
137136
Launch notebook in 'run' or 'edit' mode.
138137
@@ -154,6 +153,9 @@ Options:
154153
--port INTEGER port to bind (env: NOTEBOOK_PORT) [default: 2718]
155154
--token TEXT set a required authentication token/password for the
156155
notebook; if not set, no token/password is required
156+
(env: NOTEBOOK_TOKEN)
157+
--base-url TEXT explicit base URL prefix to pass through to marimo on
158+
notebook launch (env: NOTEBOOK_BASE_URL)
157159
--help Show this message and exit.
158160
```
159161

launcher/cli.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,17 @@ def cli(
9494
show_default=True,
9595
help=(
9696
"set a required authentication token/password for the notebook; "
97-
"if not set, no token/password is required"
97+
"if not set, no token/password is required (env: NOTEBOOK_TOKEN)"
98+
),
99+
)
100+
@click.option(
101+
"--base-url",
102+
envvar="NOTEBOOK_BASE_URL",
103+
default=None,
104+
show_default=True,
105+
help=(
106+
"explicit base URL prefix to pass through to marimo on notebook launch "
107+
"(env: NOTEBOOK_BASE_URL)"
98108
),
99109
)
100110
@click.pass_context
@@ -110,6 +120,7 @@ def run(
110120
host: str,
111121
port: int,
112122
token: str | None,
123+
base_url: str | None,
113124
) -> None:
114125
"""Launch notebook in 'run' or 'edit' mode."""
115126
notebook_dir_path = resolve_notebook_directory(
@@ -126,6 +137,7 @@ def run(
126137
token=token,
127138
notebook_path=notebook_path,
128139
requirements_file=requirements_file,
140+
base_url=base_url,
129141
)
130142

131143
logger.info(f"launching notebook '{full_notebook_path}' with args {cmd}")
@@ -230,6 +242,7 @@ def prepare_run_command(
230242
token: str | None,
231243
notebook_path: str,
232244
requirements_file: Path | None,
245+
base_url: str | None = None,
233246
) -> list[str]:
234247
"""Build the shell command used to launch a marimo notebook via `uv run`.
235248
@@ -253,6 +266,8 @@ def prepare_run_command(
253266
- notebook_path: path to the marimo notebook file.
254267
- requirements_file: optional path to a requirements file for `uv` (enables
255268
`--with-requirements`).
269+
- base_url: base URL path launched notebook will listen on
270+
e.g. host:port/<base_url>
256271
"""
257272
# start with `uv run` so marimo executes in a managed Python environment
258273
cmd: list[str] = ["uv", "run"]
@@ -281,6 +296,10 @@ def prepare_run_command(
281296
else:
282297
cmd += ["--no-token"]
283298

299+
# set base url flag if passed
300+
if base_url:
301+
cmd += ["--base-url", base_url]
302+
284303
# path to the notebook is the final positional argument
285304
cmd += [str(notebook_path)]
286305

tests/fixtures/inline_deps/notebook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# requires-python = ">=3.13"
33
# dependencies = [
44
# "marimo",
5-
# "tinydb==4.8.2",
5+
# "tinydb",
66
# ]
77
# ///
88

tests/test_cli.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,43 @@ def test_cli_subprocess_run_minimal_required_args_get_defaults_success(runner):
139139
]
140140

141141

142+
def test_cli_subprocess_run_base_url_override(runner):
143+
args = [
144+
"run",
145+
"--mount",
146+
"tests/fixtures/inline_deps",
147+
"--base-url",
148+
"/my/super/path.py",
149+
]
150+
151+
with mock.patch("launcher.cli.subprocess.run") as mock_subprocess_run:
152+
mock_subprocess_run.return_value = subprocess.CompletedProcess(
153+
args=args, returncode=0
154+
)
155+
_result = runner.invoke(cli, args)
156+
157+
# assert subproces.run has correct working directory of notebook
158+
assert mock_subprocess_run.call_args.kwargs.get("cwd") == "tests/fixtures/inline_deps"
159+
160+
# assert subprocess.run had defaults applied
161+
assert mock_subprocess_run.call_args.args[0] == [
162+
"uv",
163+
"run",
164+
"marimo",
165+
"run",
166+
"--headless",
167+
"--host",
168+
"0.0.0.0",
169+
"--port",
170+
"2718",
171+
"--sandbox",
172+
"--no-token",
173+
"--base-url",
174+
"/my/super/path.py",
175+
"notebook.py",
176+
]
177+
178+
142179
def test_cli_subprocess_run_missing_mount_or_repo_args_error(runner):
143180
args = ["run"]
144181

0 commit comments

Comments
 (0)