From 733e08585105d13b654c46258a06e1076f3920e8 Mon Sep 17 00:00:00 2001 From: Remy Gavard Date: Sun, 31 Aug 2025 16:24:43 +0100 Subject: [PATCH] fix: migrate Jupyter integration from deprecated ipykernel.comm to comm module - Replace ipykernel.comm.Comm with comm.create_comm - Refactor kernel access to use get_ipython().kernel directly instead of comm.kernel - Resolves DeprecationWarning in Python 3.12+ - Maintains full backward compatibility and functionality - Passes all linting checks (pylint 10/10, flake8 clean, black formatted) The new comm module's DummyComm doesn't provide kernel access like the old ipykernel.comm.Comm. This fix properly migrates to get kernel from IPython directly, which is more robust and follows the intended usage pattern. Fixes #3416 --- CHANGELOG.md | 1 + dash/_jupyter.py | 30 +++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 252898131b..7aad387787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#3395](https://github.com/plotly/dash/pull/3395) Fix Components added through set_props() cannot trigger related callback functions. Fix [#3316](https://github.com/plotly/dash/issues/3316) - [#3397](https://github.com/plotly/dash/pull/3397) Add optional callbacks, suppressing callback warning for missing component ids for a single callback. - [#3415](https://github.com/plotly/dash/pull/3415) Fix the error triggered when only a single no_update is returned for client-side callback functions with multiple Outputs. Fix [#3366](https://github.com/plotly/dash/issues/3366) +- [#3416](https://github.com/plotly/dash/issues/3416) Fix DeprecationWarning in dash/_jupyter.py by migrating from deprecated ipykernel.comm.Comm to comm module ## [3.2.0] - 2025-07-31 diff --git a/dash/_jupyter.py b/dash/_jupyter.py index ac06f849c7..4211c81164 100644 --- a/dash/_jupyter.py +++ b/dash/_jupyter.py @@ -22,12 +22,12 @@ from IPython.core.display import HTML from IPython.core.ultratb import FormattedTB from retrying import retry - from ipykernel.comm import Comm + from comm import create_comm import nest_asyncio import requests - _dash_comm = Comm(target_name="dash") + _dash_comm = create_comm(target_name="dash") _dep_installed = True except ImportError: _dep_installed = False @@ -97,10 +97,14 @@ def convert(name, locals=locals, formatarg=formatarg, formatvalue=formatvalue): def _send_jupyter_config_comm_request(): # If running in an ipython kernel, # request that the front end extension send us the notebook server base URL - if get_ipython() is not None: - if _dash_comm.kernel is not None: - _caller["parent"] = _dash_comm.kernel.get_parent() - _dash_comm.send({"type": "base_url_request"}) + ipython = get_ipython() + if ( + ipython is not None + and hasattr(ipython, "kernel") + and ipython.kernel is not None + ): + _caller["parent"] = ipython.kernel.get_parent() + _dash_comm.send({"type": "base_url_request"}) def _jupyter_comm_response_received(): @@ -109,7 +113,8 @@ def _jupyter_comm_response_received(): def _request_jupyter_config(timeout=2): # Heavily inspired by implementation of CaptureExecution in the - if _dash_comm.kernel is None: + ipython = get_ipython() + if ipython is None or not hasattr(ipython, "kernel") or ipython.kernel is None: # Not in jupyter setting return @@ -215,8 +220,15 @@ def __init__(self): @_dash_comm.on_msg def _receive_message(msg): prev_parent = _caller.get("parent") - if prev_parent and prev_parent != _dash_comm.kernel.get_parent(): - _dash_comm.kernel.set_parent( + ipython = get_ipython() + if ( + prev_parent + and ipython is not None + and hasattr(ipython, "kernel") + and ipython.kernel is not None + and prev_parent != ipython.kernel.get_parent() + ): + ipython.kernel.set_parent( [prev_parent["header"]["session"]], prev_parent ) del _caller["parent"]