Refactor session extensions to use EventAwareExtension base class#8678
Refactor session extensions to use EventAwareExtension base class#8678
Conversation
- Updated various session extensions (e.g., ScratchCellListener, RecentsTrackerListener, CachingExtension) to inherit from EventAwareExtension, enabling automatic subscription to the event bus. - Introduced ExtensionRegistry for managing session extensions, replacing direct list manipulations. - Refactored event emission methods in SessionEventBus for improved clarity and error handling. - Adjusted related tests to ensure compatibility with the new extension structure. This change enhances the modularity and maintainability of session extensions.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Refactors Marimo session extensions to reduce boilerplate and improve safety by centralizing event-bus subscription logic and introducing a small extensions registry abstraction.
Changes:
- Introduce
EventAwareExtension(auto subscribe/unsubscribe) andExtensionRegistry(typed lookup + snapshot iteration). - Refactor
SessionEventBusemission to use shared_emit/_emit_asynchelpers with listener-list snapshotting. - Update multiple extensions and tests to align with the new base class/registry behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/_session/extensions/test_extensions.py | Updates lifecycle assertions and adds coverage for EventAwareExtension, ExtensionRegistry, and emit snapshot safety. |
| marimo/_session/session.py | Switches extensions storage to ExtensionRegistry and simplifies notification flush via typed lookup. |
| marimo/_session/file_watcher_integration.py | Migrates file watcher extension to EventAwareExtension and simplifies attach/detach logic. |
| marimo/_session/extensions/types.py | Adds EventAwareExtension + ExtensionRegistry definitions. |
| marimo/_session/extensions/extensions.py | Migrates core session extensions to EventAwareExtension; adds NotificationListenerExtension.flush(). |
| marimo/_session/events.py | Refactors event dispatch with snapshot iteration and shared error handling. |
| marimo/_server/session/listeners.py | Migrates RecentsTrackerListener to EventAwareExtension. |
| marimo/_server/scratchpad.py | Migrates ScratchCellListener to EventAwareExtension. |
| marimo/_internal/session/extensions.py | Re-exports new extension types in the internal API. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add EventAwareExtension and ExtensionRegistry to the snapshot.
Use _canonicalize_path in on_attach to match on_detach and on_session_notebook_renamed, preventing potential watcher leaks when the raw path string differs from the normalized one.
manzt
left a comment
There was a problem hiding this comment.
Some good DRY-ness! Nice.
marimo/_session/extensions/types.py
Outdated
| from marimo._session.events import SessionEventBus | ||
| from marimo._session.session import Session | ||
|
|
||
| _T = TypeVar("_T") |
There was a problem hiding this comment.
I think this is bounded by being a SessionExtension:
| _T = TypeVar("_T") | |
| _T = TypeVar("_T", bound=SessionExtension) |
marimo/_session/extensions/types.py
Outdated
|
|
||
| @property | ||
| def session(self) -> Session: | ||
| assert self._session is not None |
There was a problem hiding this comment.
| assert self._session is not None | |
| if self._session is None: | |
| raise RuntimeError("Extension is not attached to a session") |
marimo/_session/extensions/types.py
Outdated
|
|
||
| @property | ||
| def event_bus(self) -> SessionEventBus: | ||
| assert self._event_bus is not None |
There was a problem hiding this comment.
| assert self._event_bus is not None | |
| if self._event_bus is None: | |
| raise RuntimeError("Extension is not attached to a session") |
| with pytest.raises(AssertionError): | ||
| ext.session # noqa: B018 | ||
| with pytest.raises(AssertionError): | ||
| ext.event_bus # noqa: B018 |
There was a problem hiding this comment.
If changes above are accepted:
| with pytest.raises(AssertionError): | |
| ext.session # noqa: B018 | |
| with pytest.raises(AssertionError): | |
| ext.event_bus # noqa: B018 | |
| with pytest.raises(RuntimeError): | |
| ext.session # noqa: B018 | |
| with pytest.raises(RuntimeError): | |
| ext.event_bus # noqa: B018 |
- Bound _T TypeVar to SessionExtension - Use RuntimeError instead of assert for detached property access
This change enhances the modularity and maintainability of session extensions.