Skip to content

fix(islands): propagate notebook filename through MarimoIslandGenerator.from_file#9409

Open
ljchang wants to merge 3 commits intomarimo-team:mainfrom
ljchang:fix/island-generator-filename-9391
Open

fix(islands): propagate notebook filename through MarimoIslandGenerator.from_file#9409
ljchang wants to merge 3 commits intomarimo-team:mainfrom
ljchang:fix/island-generator-filename-9391

Conversation

@ljchang
Copy link
Copy Markdown

@ljchang ljchang commented Apr 28, 2026

Summary

Closes #9391

MarimoIslandGenerator.from_file(path) previously discarded the source path. build() then constructed AppFileManager with filename=None, the kernel inherited app_metadata.filename = None, and create_main_module(file=None) fell through to sys.modules['__main__'].__file__ — i.e. the host process's launcher script. Cells inside notebooks rendered through islands therefore saw __file__ (and mo.notebook_dir()) resolve to the calling script (or to the installed CLI's .venv/bin/<entry> shim) rather than to the notebook source. marimo edit and marimo export were unaffected; only the islands code path was broken.

The fix threads the source path through:

  • MarimoIslandGenerator.__init__ gains a _source_filename field (defaults to None, so manual MarimoIslandGenerator() + 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 a new optional filename kwarg and assigns _filename directly. All existing single-arg callers (29 in tests + 1 here) 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__ — no further changes in _runtime/.

Before / after (issue's exact repro)

/tmp/repro/notebooks/nb.py prints __file__ and mo.notebook_dir() from a cell. /tmp/repro/scripts/render.py calls MarimoIslandGenerator.from_file(...).

Before:

__file__ = '/tmp/repro/scripts/render.py'
notebook_dir() = PosixPath('/tmp/repro/scripts')

After:

__file__ = '/tmp/repro/notebooks/nb.py'
notebook_dir() = PosixPath('/tmp/repro/notebooks')

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

  • I have read the contributor guidelines.
  • Documentation has been updated where applicable, including docstrings for API changes. — AppFileManager.from_app docstring updated to document the new filename parameter.
  • Tests have been added for the changes made. — 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 deselected test_export_html* failures are pre-existing on main due to no make fe artifact and unrelated to this change)
  • ruff check / ruff format --check — clean on changed files
  • mypy marimo --exclude=marimo/_tutorials/ — same 14 pre-existing errors as main; zero new errors introduced

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment May 5, 2026 4:32pm

Request Review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@ljchang
Copy link
Copy Markdown
Author

ljchang commented Apr 28, 2026

I have read the CLA Document and I hereby sign the CLA

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread marimo/_islands/_island_generator.py Outdated
ljchang added a commit to ljchang/marimo that referenced this pull request Apr 28, 2026
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.
@mscolnick mscolnick requested a review from Copilot April 28, 2026 13:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 MarimoIslandGenerator created via from_file() and pass it into build().
  • Extend AppFileManager.from_app(...) with an optional filename parameter used to populate AppMetadata.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).

Comment on lines 113 to 115
manager = AppFileManager(None)
manager._filename = _maybe_path(filename)
manager.app = app
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ljchang this seems like a good suggestion.

also, main was in a bad state. mind rebasing off origin/main to fix CI

ljchang added 3 commits May 5, 2026 12:07
…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.
@ljchang ljchang force-pushed the fix/island-generator-filename-9391 branch from 0160a75 to 63f3273 Compare May 5, 2026 16:31
@ljchang
Copy link
Copy Markdown
Author

ljchang commented May 5, 2026

@mscolnick thanks for the review! Pushed two changes:

  1. Addressed Copilot's file_manager.py suggestion in 63f327355: AppFileManager.from_app(..., filename=...) now os.path.abspaths at assignment time and routes through the filename property setter instead of writing _filename directly. Added a unit test (test_from_app_snapshots_relative_filename_to_absolute) to lock in the snapshot semantics at this layer too — the previous regression test only covered the MarimoIslandGenerator.from_file entry point.
  2. Rebased onto origin/main (was 21 commits behind, including the CellManager/NotebookDocument consolidate refactor). Clean replay, no conflicts. CI should be green now.

Local run: 84 tests pass across tests/_server/test_file_manager* + tests/_islands/test_island_generator.py.

Happy to add a label if you let me know which fits best (bug? enhancement?) — enforce-label was the only non-flaky CI failure, and it needs a maintainer-set label.

@mscolnick mscolnick added bug Something isn't working breaking A breaking change labels May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking A breaking change bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MarimoIslandGenerator: __file__ and notebook_dir() resolve to the host's __main__ instead of the notebook source

3 participants