fix(islands): propagate notebook filename through MarimoIslandGenerator.from_file#9409
fix(islands): propagate notebook filename through MarimoIslandGenerator.from_file#9409ljchang wants to merge 3 commits intomarimo-team:mainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="marimo/_islands/_island_generator.py">
<violation number="1" location="marimo/_islands/_island_generator.py:281">
P2: Use the resolved file path instead of the raw input filename; otherwise relative paths can make `__file__`/`mo.notebook_dir()` depend on the current CWD at build time.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Client as Host Script
participant Gen as MarimoIslandGenerator
participant FM as AppFileManager
participant Runtime as run_app_until_completion
participant Kernel as Cell Execution Context
Note over Client,Kernel: Initialization via Notebook File
Client->>Gen: from_file(path)
Gen->>Gen: NEW: Store path in _source_filename
Gen-->>Client: generator instance
Note over Client,Kernel: Build / Execution Flow
Client->>Gen: build()
Gen->>FM: CHANGED: from_app(app, filename=path)
Note right of FM: assigns _filename directly
FM-->>Gen: file_manager instance
Gen->>Runtime: run_app_until_completion(file_manager)
Runtime->>Runtime: Create AppMetadata(filename=file_manager.path)
Runtime->>Kernel: Start Kernel with AppMetadata
Kernel->>Kernel: Patch __main__ module (sys.modules)
Note over Kernel: Kernel uses AppMetadata.filename<br/>to set __file__ and notebook_dir()
Kernel->>Kernel: Execute Notebook Cells
alt Happy Path: Path is provided
Kernel-->>Gen: Cells see notebook path in __file__
else Fallback: No path (manual generator flow)
Kernel-->>Gen: Cells see host script path (sys.argv[0])
end
Runtime-->>Gen: session (execution results)
Gen-->>Client: Ready to render HTML islands
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
Address review feedback on marimo-team#9409: store ``os.path.abspath(filename)`` on the generator so a ``chdir`` between ``from_file`` and ``build`` cannot change which absolute path cells see for ``__file__`` / ``mo.notebook_dir()``. Previously ``AppFileManager.path`` did the ``abspath`` lazily, picking up whatever CWD was active when ``build`` ran. Add a regression test that demonstrates the new guarantee by passing a relative filename, ``chdir``-ing to an unrelated directory, then calling ``build`` and asserting cells still see the original path.
There was a problem hiding this comment.
Pull request overview
This PR fixes the islands rendering path so notebook cells see the correct __file__ / mo.notebook_dir() when the app is built via MarimoIslandGenerator.from_file(...), by propagating the notebook source filename through to AppFileManager and the kernel metadata.
Changes:
- Track a source filename on
MarimoIslandGeneratorcreated viafrom_file()and pass it intobuild(). - Extend
AppFileManager.from_app(...)with an optionalfilenameparameter used to populateAppMetadata.filename. - Add regression tests covering
__file__/notebook_dir()correctness and relative-path snapshot semantics.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
marimo/_islands/_island_generator.py |
Captures absolute source path in from_file() and forwards it into AppFileManager.from_app(...) during build(). |
marimo/_session/notebook/file_manager.py |
Adds filename kwarg to from_app(...) and stores it on the manager so AppMetadata.filename is set. |
tests/_islands/test_island_generator.py |
Adds regression tests ensuring cells see the notebook’s path (including relative-path capture-time behavior). |
| manager = AppFileManager(None) | ||
| manager._filename = _maybe_path(filename) | ||
| manager.app = app |
There was a problem hiding this comment.
from_app(..., filename=...) stores filename as a raw Path via _maybe_path, and path later computes os.path.abspath(str(self._filename)). If callers ever pass a relative filename, file_manager.path (and therefore AppMetadata.filename / __file__) can change based on a subsequent chdir. Consider normalizing filename to an absolute path at assignment time (and prefer using the filename property setter instead of writing _filename directly) so the value is snapshotted when from_app is called.
There was a problem hiding this comment.
@ljchang this seems like a good suggestion.
also, main was in a bad state. mind rebasing off origin/main to fix CI
…or.from_file `MarimoIslandGenerator.from_file(path)` previously discarded the source path when constructing the generator, and `build()` then created the underlying `AppFileManager` with `filename=None`. The kernel inherited that as `app_metadata.filename = None`, so `create_main_module(file=None)` fell through to `sys.modules['__main__'].__file__` — i.e. the host process's launcher script (e.g. an installed CLI's `.venv/bin/<entry>` shim). This broke `__file__` and `mo.notebook_dir()` for cells run through islands while leaving `marimo edit` / `marimo export` unaffected. Thread the source path through: * `MarimoIslandGenerator.__init__` gains an `_source_filename` field (defaults to `None`, so manual `add_code()` flows are unchanged). * `from_file()` records the path on the instance. * `build()` passes it to `AppFileManager.from_app(self._app, filename=…)`. * `AppFileManager.from_app` accepts an optional `filename` kwarg and assigns `_filename` directly, so existing single-arg callers (`InternalApp` only) continue to work. `run_app_until_completion` already populates `AppMetadata(filename=file_manager.path, …)`, so once the file manager knows the path, the existing kernel/`patch_main_module` plumbing delivers the correct `__file__` to cells without further changes. Closes marimo-team#9391
Address review feedback on marimo-team#9409: store ``os.path.abspath(filename)`` on the generator so a ``chdir`` between ``from_file`` and ``build`` cannot change which absolute path cells see for ``__file__`` / ``mo.notebook_dir()``. Previously ``AppFileManager.path`` did the ``abspath`` lazily, picking up whatever CWD was active when ``build`` ran. Add a regression test that demonstrates the new guarantee by passing a relative filename, ``chdir``-ing to an unrelated directory, then calling ``build`` and asserting cells still see the original path.
…r.from_app Per Copilot review on marimo-team#9409: ``AppFileManager.from_app(..., filename=...)`` previously stored ``filename`` as a raw ``Path`` via ``_maybe_path``, and the ``path`` property lazily abspath'd on every read. A relative ``filename`` plus a ``chdir`` between ``from_app`` and ``path`` therefore let ``AppMetadata.filename`` / ``__file__`` shift under cells. Resolve to ``os.path.abspath`` at assignment time and route through the ``filename`` property setter rather than writing ``_filename`` directly. This is defense-in-depth: the island generator already abspaths its ``_source_filename`` before passing it in, but any other future caller of ``from_app`` now gets snapshot semantics for free.
0160a75 to
63f3273
Compare
|
@mscolnick thanks for the review! Pushed two changes:
Local run: 84 tests pass across Happy to add a label if you let me know which fits best ( |
Summary
Closes #9391
MarimoIslandGenerator.from_file(path)previously discarded the source path.build()then constructedAppFileManagerwithfilename=None, the kernel inheritedapp_metadata.filename = None, andcreate_main_module(file=None)fell through tosys.modules['__main__'].__file__— i.e. the host process's launcher script. Cells inside notebooks rendered through islands therefore saw__file__(andmo.notebook_dir()) resolve to the calling script (or to the installed CLI's.venv/bin/<entry>shim) rather than to the notebook source.marimo editandmarimo exportwere unaffected; only the islands code path was broken.The fix threads the source path through:
MarimoIslandGenerator.__init__gains a_source_filenamefield (defaults toNone, so manualMarimoIslandGenerator() + add_code()flows are unchanged).from_file()records the path on the instance.build()passes it toAppFileManager.from_app(self._app, filename=…).AppFileManager.from_appaccepts a new optionalfilenamekwarg and assigns_filenamedirectly. All existing single-arg callers (29 in tests + 1 here) continue to work.run_app_until_completionalready populatesAppMetadata(filename=file_manager.path, …), so once the file manager knows the path the existing kernel /patch_main_moduleplumbing delivers the correct__file__— no further changes in_runtime/.Before / after (issue's exact repro)
/tmp/repro/notebooks/nb.pyprints__file__andmo.notebook_dir()from a cell./tmp/repro/scripts/render.pycallsMarimoIslandGenerator.from_file(...).Before:
After:
Note on backward compatibility
This restores the documented / expected semantics, but it is a behavior change for any island user who relied on
__file__resolving to the host process. @mscolnick noted in #9391 that this may warrant a breaking-change classification — happy to take labeling / release-note guidance.Pre-Review Checklist
Merge Checklist
AppFileManager.from_appdocstring updated to document the newfilenameparameter.tests/_islands/test_island_generator.py::test_from_file_propagates_filename_to_cells.Verification
pytest tests/_islands/— 11 passed (10 existing + 1 new regression test)pytest tests/_server/test_file_manager.py tests/_server/test_sessions.py tests/_server/export/test_exporter.py— 81 passed (the 15 deselectedtest_export_html*failures are pre-existing onmaindue to nomake feartifact and unrelated to this change)ruff check/ruff format --check— clean on changed filesmypy marimo --exclude=marimo/_tutorials/— same 14 pre-existing errors asmain; zero new errors introduced