JupyterLab实现.ipynb链接点击触发文档分栏打开
Fixing Comm Communication Between Jupyter Notebook and Custom Plugin
Key Issues in Current Implementation
- Mismatched Comm Channels: Python creates an independent Comm object instead of using the one established when the plugin initiates the connection.
- Unreliable Kernel Retrieval: Plugin code uses a non-deterministic way to get the kernel, which may fail if multiple sessions exist.
- Missing Widget Import: Original Python code lacks the import for
Buttonfromipywidgets, causing runtime errors.
Corrected Implementation
1. Python Notebook Code
Store the comm instance received from the plugin's connection, then use it to send messages on button click:
from ipykernel.comm import Comm from IPython import get_ipython from ipywidgets import Button # Global variable to hold the active comm connection active_comm = None def comm_target(comm, open_msg): global active_comm active_comm = comm print("Comm connection established with plugin") @comm.on_msg def _recv(msg): print("Message from plugin:", msg) # Register the comm target get_ipython().kernel.comm_manager.register_target('schedule_reference_link', comm_target) # Button click handler def on_schedule_reference_clicked(b): print('Button clicked') if active_comm is not None: active_comm.send(data={'event': 'schedule_ref_event', 'data': 'https://example.com'}) else: print("No active comm connection to plugin") # Create and display the button schedule_reference = Button(description="Schedule Reference") schedule_reference.on_click(on_schedule_reference_clicked) schedule_reference
2. JupyterLab Plugin Code
Properly retrieve the kernel, handle session activation, and listen for Comm messages:
import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; import { ISessionContext, SessionManager } from '@jupyterlab/apputils'; const plugin: JupyterFrontEndPlugin<void> = { id: 'schedule-reference-plugin:plugin', autoStart: true, requires: [SessionManager], activate: (app: JupyterFrontEnd, sessionManager: SessionManager) => { let comm: any = null; // Setup comm connection when a session is active const setupComm = (sessionContext: ISessionContext) => { if (!sessionContext.session?.kernel) return; const kernel = sessionContext.session.kernel; // Create comm connection to the Python target kernel.createComm('schedule_reference_link').then((newComm) => { comm = newComm; console.log("Comm connection established with kernel"); comm.onMsg = (msg: { content: { data: any; }; }) => { const eventData = msg.content.data; if (eventData.event === 'schedule_ref_event') { console.log('Event received:', eventData.data); // Trigger split-panel opening logic openInSplitPanel(eventData.data); } }; // Handle comm closure comm.onClose = () => { console.log("Comm connection closed"); comm = null; }; }).catch(err => { console.error("Failed to create comm connection:", err); }); }; // Listen for active session changes app.serviceManager.sessions.currentChanged.connect((_, session) => { if (session) { setupComm(session); } else { comm?.close(); comm = null; } }); // Initialize comm if a session is already active app.serviceManager.sessions.currentSession && setupComm(app.serviceManager.sessions.currentSession); // Open document in split panel const openInSplitPanel = (url: string) => { const widget = app.commands.execute('docmanager:open', { path: url }) as any; if (widget) { const mainArea = app.shell.mainArea; mainArea.splitRight(widget); } }; } }; export default plugin;
Explanation of Fixes
- Shared Comm Channel: Python now uses the comm instance established by the plugin, ensuring messages are sent through the same channel the plugin listens to.
- Reliable Session Handling: Plugin listens for active session changes and initializes the comm only when a valid kernel exists, avoiding non-deterministic kernel retrieval.
- Proper Comm Lifecycle: Handles comm closure and reconnection when sessions change.
- Split Panel Logic: Added
openInSplitPanelto implement the required split-view document opening feature.
Additional Notes
- Ensure your plugin is properly packaged and installed via
jupyter labextension install. - Test by running the notebook code first, then confirming the plugin is active before clicking the button.
- Use browser dev tools (F12) for plugin logs and Jupyter server logs for Python-side debugging.
内容的提问来源于stack exchange,提问作者Sathiyanarayanan Marimuthu
相关产品推荐
相关产品推荐

