You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR addresses the state drift between the console and the GUI that occurs during interactive analysis. Previously, state synchronization was only triggered by explicit variable reassignments, leaving in-place modifications (e.g., EEG.data[0] = ...) or direct attribute edits undetected. Furthermore, because plotting functions often trigger UI repaints before the standard post_run_cell hook, users frequently encountered "visual drift" where plot windows displayed stale data.
Key Changes
1. Expanded AST Analysis for In-Place Edits
The _workspace_assignment_targets logic in console.py has been overhauled. It no longer just looks for ast.Assign nodes.
Attribute & Index Tracking: The analyzer now detects assignments to object attributes and array indices specifically for EEG and ALLEEG identifiers.
Mutation Detection: Intercepts ast.Call nodes for common mutating methods (e.g., .pop(), .append(), .update()) and ast.Delete operations.
Rationale: This ensures that fine-grained modifications to the EEG data structure trigger the synchronization engine without requiring the user to manually reassign the variable.
2. Pre-Plotting Synchronization Guardrails
To eliminate visual inconsistencies when plotting, I implemented a new IPython AST transformer, _PlotSyncInjector.
Automatic Injection: This transformer scans for calls to visualization or dialog functions (e.g., eegplot, eeg_browser, pop_...).
Just-in-Time Sync: It injects a call to the state synchronization routine immediately before these functions execute.
Rationale: This guarantees that the GUI backend is aware of the most recent console changes before the UI window is rendered, solving the race condition between cell execution and UI event processing.
3. Manual Synchronization Hook (refresh)
A new refresh() command has been exported to the IPython namespace.
Functionality: It forces a push of the current workspace context to the session, triggers a deep check via eeg_store, and mandates a GUI redraw.
Rationale: While the AST automation covers most cases, refresh() provides a safety valve for edge-case recovery or complex scripts where static analysis might fail.
Performance & Constraints
Lazy Synchronization: We maintain a "lazy" sync approach. While detection is more robust, the heavy lifting of deep-copying large datasets is only performed when a modification is actually detected or a plot is requested.
Compatibility: These changes are non-breaking for existing post_run_cell hooks and do not impact the performance of non-EEG variable assignments (e.g., standard math operations remain fast).
Validation
Verified that EEG.setname = 'test' updates the GUI title immediately.
Confirmed eegplot(EEG) displays updated data even if modified in the same cell.
Performance profiling shows negligible overhead for standard analysis commands.
🤖 Closing in favor of the focused mutation-detection work in #252. This branch injects a global refresh() call into user AST before every top-level pop_*/plot call, adds that name to the interactive namespace, and synchronizes only EEG; it can clobber a user's refresh binding and overwrite direct ALLEEG/STUDY edits when it pulls state back. There are no tests for the transformer or those state interactions. Pre-plot synchronization should use the existing wrapper/session boundary, not rewrite arbitrary user code.
I have completely removed the brittle AST-based _PlotSyncInjector and the global refresh function to avoid rewriting user code and clobbering interactive bindings. Instead, pre-plot synchronization is now handled cleanly through the existing ConsolePopFunction wrapper boundary by intercepting calls natively. I also updated the pre-plot sync logic (push_state_to_session) to save ALLEEG, STUDY, CURRENTSTUDY, and CURRENTSET alongside EEG before any top-level plotting or UI call, ensuring that direct console modifications to those objects are preserved and not overwritten when pulling the session state back.
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
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.
Overview
This PR addresses the state drift between the console and the GUI that occurs during interactive analysis. Previously, state synchronization was only triggered by explicit variable reassignments, leaving in-place modifications (e.g.,
EEG.data[0] = ...) or direct attribute edits undetected. Furthermore, because plotting functions often trigger UI repaints before the standardpost_run_cellhook, users frequently encountered "visual drift" where plot windows displayed stale data.Key Changes
1. Expanded AST Analysis for In-Place Edits
The
_workspace_assignment_targetslogic inconsole.pyhas been overhauled. It no longer just looks forast.Assignnodes.EEGandALLEEGidentifiers.ast.Callnodes for common mutating methods (e.g.,.pop(),.append(),.update()) andast.Deleteoperations.2. Pre-Plotting Synchronization Guardrails
To eliminate visual inconsistencies when plotting, I implemented a new IPython AST transformer,
_PlotSyncInjector.eegplot,eeg_browser,pop_...).3. Manual Synchronization Hook (
refresh)A new
refresh()command has been exported to the IPython namespace.eeg_store, and mandates a GUI redraw.refresh()provides a safety valve for edge-case recovery or complex scripts where static analysis might fail.Performance & Constraints
post_run_cellhooks and do not impact the performance of non-EEG variable assignments (e.g., standard math operations remain fast).Validation
EEG.setname = 'test'updates the GUI title immediately.eegplot(EEG)displays updated data even if modified in the same cell.