fix: forward cell names and configs on external file reload (#8421)#8433
fix: forward cell names and configs on external file reload (#8421)#8433
Conversation
When editing a `.mo.py` notebook externally while `marimo edit --watch` is running, cell metadata like `hide_code=True` and cell function names were silently dropped. The file watcher detected changes and reloaded code, but only cell codes and IDs were sent to the frontend — names and configs were discarded. On the next UI save, the frontend's stale state would overwrite the file without the externally-added metadata. ## Changes **Backend:** - Add `names` and `configs` fields to `UpdateCellCodesNotification` (with defaults for backward compatibility) - Update `EditModeReloadStrategy.handle_reload()` to extract and forward cell names and configs in both lazy and autorun paths - Update `AppFileManager.reload()` to detect config-only and name-only changes (previously only compared code) **Frontend:** - Update `setCellCodes` reducer to accept and apply optional `names` and `configs` from the notification - Pass `names` and `configs` from the WebSocket message handler Closes #8421
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Fixes loss of cell metadata (cell names and @app.cell(...) config like hide_code) when reloading a notebook due to external file edits while marimo edit --watch is running, by ensuring metadata is detected on reload and forwarded to the frontend.
Changes:
- Extend the backend
UpdateCellCodesNotificationpayload to optionally includenamesandconfigs, and send them during edit-mode reloads (lazy + autorun). - Improve reload change detection to consider name/config changes in addition to code changes.
- Update frontend WebSocket handling + cell reducer to apply
names/configs, with new tests for backward compatibility and metadata updates.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/_session/test_file_change_handler.py | Adds/updates tests asserting reload forwards names/configs and reload detects name/config-only changes |
| marimo/_session/file_change_handler.py | For edit-mode reload, collects and forwards cell names/configs (and sends update-codes in autorun path) |
| marimo/_session/notebook/file_manager.py | Reload change detection now compares full cell data (code/name/config), not just code |
| marimo/_messaging/notification.py | Adds names and configs fields (with defaults) to UpdateCellCodesNotification |
| packages/openapi/api.yaml | Updates OpenAPI schema for UpdateCellCodesNotification to include names/configs; updates API version |
| packages/openapi/src/api.ts | Updates generated TS types for UpdateCellCodesNotification with optional names/configs |
| frontend/src/core/websocket/useMarimoKernelConnection.tsx | Passes names/configs through to setCellCodes on update-cell-codes notifications |
| frontend/src/core/cells/cells.ts | Enhances setCellCodes reducer to optionally apply names/configs during code updates |
| frontend/src/core/cells/tests/cells.test.ts | Adds reducer tests for names/configs application and backward compatibility |
Comments suppressed due to low confidence (3)
packages/openapi/api.yaml:4473
- The OpenAPI schema description for
UpdateCellCodesNotificationstill frames this as “kiosk mode”, but this PR extends its use to edit-mode file reload syncing. Updating the description would prevent API docs from becoming inaccurate.
UpdateCellCodesNotification:
description: "Updates cell code contents (kiosk mode).\n\n Attributes:\n\
\ cell_ids: Cells to update.\n codes: New code for each cell.\n\
\ code_is_stale: If True, code was not executed on backend (output\
\ may not match).\n names: Cell names for each cell (optional, for\
\ file reload).\n configs: Cell configs for each cell (optional, for\
\ file reload)."
packages/openapi/src/api.ts:5764
- The generated TS docs for
UpdateCellCodesNotificationstill describe it as kiosk-mode only, but it’s now also used for edit-mode reload syncing (names/configs are explicitly for that). Consider updating the comment text so consumers aren’t misled.
* cell_ids: Cells to update.
* codes: New code for each cell.
* code_is_stale: If True, code was not executed on backend (output may not match).
* names: Cell names for each cell (optional, for file reload).
* configs: Cell configs for each cell (optional, for file reload).
*/
marimo/_session/notebook/file_manager.py:126
AppFileManager.reload()now treats changes in code, config, and cell name as modifications, but the method docstring above still says it detects changes by comparing only IDs and code. Please update the docstring to match the new behavior to avoid confusion for future maintainers.
# Check for added or modified cells (code, config, or name)
for cell_id in current_cell_ids:
if cell_id not in prev_cell_ids:
changed_cell_ids.add(cell_id)
else:
new_data = self.app.cell_manager.get_cell_data(cell_id)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| class UpdateCellCodesNotification(Notification, tag="update-cell-codes"): | ||
| """Updates cell code contents (kiosk mode). | ||
|
|
||
| Attributes: | ||
| cell_ids: Cells to update. | ||
| codes: New code for each cell. | ||
| code_is_stale: If True, code was not executed on backend (output may not match). | ||
| names: Cell names for each cell (optional, for file reload). | ||
| configs: Cell configs for each cell (optional, for file reload). |
There was a problem hiding this comment.
UpdateCellCodesNotification is no longer kiosk-only (it is now also used to sync edits from --watch reloads), but the class docstring still says “(kiosk mode)”. Please update the description to reflect its broader usage so the schema/docs aren’t misleading.
| strategy = EditModeReloadStrategy(config_manager_autorun) | ||
| changed_cell_ids = {CellId_t("cell1")} | ||
|
|
||
| strategy.handle_reload(mock_session, changed_cell_ids=changed_cell_ids) | ||
|
|
||
| # Should send UpdateCellIdsRequest | ||
| assert mock_session.notify.call_count >= 1 | ||
| # Should send at least UpdateCellIdsNotification and UpdateCellCodesNotification | ||
| assert mock_session.notify.call_count >= 2 |
There was a problem hiding this comment.
In test_edit_mode_reload_strategy_autorun, changed_cell_ids is hard-coded to {CellId_t("cell1")} even though cell IDs are generated (and the lazy test above retrieves the real IDs from app_file_manager.app.cell_manager). This makes the test less representative and can cause the strategy to treat a non-existent cell as deleted; consider using the actual cell IDs from the loaded app (same approach as the lazy test).
When editing a
.mo.pynotebook externally whilemarimo edit --watchisrunning, cell metadata like
hide_code=Trueand cell function names weresilently dropped. The file watcher detected changes and reloaded code, but
only cell codes and IDs were sent to the frontend — names and configs were
discarded. On the next UI save, the frontend's stale state would overwrite
the file without the externally-added metadata.
Changes
Backend:
namesandconfigsfields toUpdateCellCodesNotification(withdefaults for backward compatibility)
EditModeReloadStrategy.handle_reload()to extract and forwardcell names and configs in both lazy and autorun paths
AppFileManager.reload()to detect config-only and name-onlychanges (previously only compared code)
Frontend:
setCellCodesreducer to accept and apply optionalnamesandconfigsfrom the notificationnamesandconfigsfrom the WebSocket message handlerCloses #8421