refactor: extract NotebookWorkspace from AppFileRouter#9448
Open
refactor: extract NotebookWorkspace from AppFileRouter#9448
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
1 issue found across 38 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/_server/workspace/_empty.py">
<violation number="1" location="marimo/_server/workspace/_empty.py:43">
P2: `resolve` returns the raw `key` without normalizing it to an absolute path. The base-class contract specifies "Resolve a key to an absolute path" and the sibling workspaces (`SingleFileWorkspace`, `DirectoryWorkspace`) normalize via `normalize_path`. Returning a relative or non-canonical path here can cause mismatches in downstream comparisons (e.g., session lookups keyed on absolute paths).</violation>
</file>
Architecture diagram
sequenceDiagram
participant CLI as CLI / Start Module
participant SM as SessionManager
participant WS as NotebookWorkspace (Abstract)
participant SWS as Specific Workspace (Dir/Single/Fixed/Empty)
participant AFM as AppFileManager
Note over CLI, SWS: Initialization Flow
CLI->>WS: NEW: infer_workspace(path)
WS-->>CLI: Return Concrete Workspace (e.g., DirectoryWorkspace)
CLI->>SM: Initialize SessionManager(workspace)
Note over SM, SWS: File Listing & Capability Flow (Home API)
SM->>SWS: CHANGED: invalidate() (if stale)
SM->>SWS: NEW: set_include_markdown(bool)
SWS->>SWS: Mutate scanner state in-place
SM->>SWS: get files
SWS-->>SM: Return List[FileInfo]
Note over SM, AFM: Notebook Loading Flow
SM->>WS: CHANGED: load(file_key, defaults)
WS->>SWS: CHANGED: resolve(file_key)
alt key is valid and allowed
SWS-->>WS: Return absolute path
WS->>AFM: Instantiate AppFileManager(resolved_path)
AFM-->>WS: manager
WS-->>SM: manager
else key not in allowlist / directory
SWS-->>WS: Raise HTTPException(404/403)
WS-->>SM: Error
end
Note over SM, SWS: Runtime Allowlist Management (Edit Mode)
opt NEW_FILE or new notebook created
SM->>SWS: NEW: register_allowed_path(path)
SWS->>SWS: Update internal allowlist
end
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors the server’s notebook “file routing” into a new NotebookWorkspace abstraction with focused workspace implementations, removing the legacy AppFileRouter and updating server/CLI codepaths and tests accordingly.
Changes:
- Introduces
marimo._server.workspacewithEmptyWorkspace,SingleFileWorkspace,FixedFilesWorkspace,DirectoryWorkspace, andinfer_workspace(). - Updates
SessionManager, server startup, and API endpoints to depend onworkspacecapabilities (with no-op defaults) instead offile_routerandisinstancebranching. - Migrates and expands test coverage to validate workspace behavior and key security invariants (path traversal, temp-dir allowlisting,
__new__handling).
Reviewed changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/_server/test_workspace.py | Migrates router tests to workspace tests; adds coverage for workspace security and capability no-ops. |
| tests/_server/test_sessions.py | Updates session tests to construct SessionManager with SingleFileWorkspace. |
| tests/_server/test_session_manager.py | Replaces AppFileRouter usage with EmptyWorkspace/infer_workspace/NEW_FILE. |
| tests/_server/test_file_manager_absolute_path.py | Updates absolute/relative directory behavior tests to use DirectoryWorkspace.load(). |
| tests/_server/rtc/test_rtc_doc.py | Moves MarimoFileKey import to workspace module. |
| tests/_server/mocks.py | Renames router-scoped helpers to workspace_scope / with_workspace. |
| tests/_server/api/endpoints/test_ws.py | Uses session_manager.workspace for unique key and patching. |
| tests/_server/api/endpoints/test_ws_rtc.py | Uses session_manager.workspace for RTC file keys. |
| tests/_server/api/endpoints/test_resume_session.py | Switches to workspace.get_single_app_file_manager() / workspace.get_unique_file_key(). |
| tests/_server/api/endpoints/test_home.py | Updates home endpoint integration tests to swap DirectoryWorkspace / FixedFilesWorkspace. |
| tests/_server/api/endpoints/test_files.py | Updates endpoint tests to reference workspace and its directory. |
| tests/_server/api/endpoints/test_file_explorer.py | Updates file explorer test to use workspace.get_unique_file_key(). |
| tests/_server/api/endpoints/test_assets.py | Updates assets/index tests to use workspace_scope and workspace implementations. |
| tests/_cli/test_cli.py | Updates CLI tests for _create_run_workspace() returning workspace implementations. |
| marimo/_session/session_repository.py | Updates typing import to MarimoFileKey from workspace. |
| marimo/_server/workspace/_single.py | Adds SingleFileWorkspace with allowlist + register_allowed_path() support. |
| marimo/_server/workspace/_fixed.py | Adds FixedFilesWorkspace for fixed allowlists (run-mode snapshots / multi-file runs). |
| marimo/_server/workspace/_empty.py | Adds EmptyWorkspace for marimo new semantics with permissive fallback. |
| marimo/_server/workspace/_directory.py | Adds DirectoryWorkspace backed by DirectoryScanner + PathValidator + caching. |
| marimo/_server/workspace/_base.py | Defines NotebookWorkspace API, NEW_FILE, shared helpers, and capability no-ops. |
| marimo/_server/workspace/init.py | Exposes workspace implementations and infer_workspace(). |
| marimo/_server/start.py | Updates server start signature and logic to accept a NotebookWorkspace. |
| marimo/_server/session_manager.py | Replaces file-router usage with workspace and capability dispatch. |
| marimo/_server/rtc/doc.py | Updates typing import to MarimoFileKey from workspace. |
| marimo/_server/resume_strategies.py | Updates typing import to MarimoFileKey from workspace. |
| marimo/_server/file_router.py | Deletes legacy AppFileRouter implementation. |
| marimo/_server/asgi.py | Updates ASGI file-app creation to use SingleFileWorkspace. |
| marimo/_server/api/lifespans.py | Updates startup logging to use workspace and NEW_FILE. |
| marimo/_server/api/endpoints/ws/ws_rtc_handler.py | Updates typing import to MarimoFileKey from workspace. |
| marimo/_server/api/endpoints/ws/ws_kernel_ready.py | Updates typing import to MarimoFileKey from workspace. |
| marimo/_server/api/endpoints/ws/ws_connection_validator.py | Uses workspace.get_unique_file_key() for default file key resolution. |
| marimo/_server/api/endpoints/home.py | Uses workspace helpers; switches markdown toggling to in-place mutation. |
| marimo/_server/api/endpoints/files.py | Resolves relative paths against workspace.directory. |
| marimo/_server/api/endpoints/file_explorer.py | Uses workspace.directory as default root. |
| marimo/_server/api/endpoints/execution.py | Uses workspace.get_unique_file_key() for restart/takeover/shutdown logic. |
| marimo/_server/api/endpoints/assets.py | Uses workspace.resolve() and workspace.directory for thumbnails/index. |
| marimo/_cli/export/_common.py | Imports flatten_files from workspace module. |
| marimo/_cli/cli.py | Switches CLI to infer_workspace() / _create_run_workspace() and passes workspace into start(). |
7ca8788 to
dccae77
Compare
Replaces the conflated AppFileRouter with a NotebookWorkspace abstraction plus four focused subclasses, deleting marimo/_server/file_router.py. - New marimo/_server/workspace/ package: EmptyWorkspace, SingleFileWorkspace, FixedFilesWorkspace, DirectoryWorkspace, plus infer_workspace(). - Renamed methods to a clearer vocabulary: single_file(), resolve(), load(), set_include_markdown() (mutating), invalidate(), register_allowed_path(). - SessionManager.workspace replaces .file_router; capability dispatch via no-op base methods removes isinstance checks in session_manager and home. - home.py no longer reassigns session_manager.workspace; toggling markdown mutates in place.
Match the base-class contract and sibling workspaces — relative keys could otherwise mismatch with absolute paths in downstream session lookups.
dccae77 to
e585c75
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the conflated AppFileRouter with a NotebookWorkspace abstraction
plus four focused subclasses, deleting marimo/_server/file_router.py.
FixedFilesWorkspace, DirectoryWorkspace, plus infer_workspace().
set_include_markdown() (mutating), invalidate(), register_allowed_path().
no-op base methods removes isinstance checks in session_manager and home.
mutates in place.