diff --git a/CHANGELOG.md b/CHANGELOG.md index d883464f6d..791b88c910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to `dash` will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [UNRELEASED] + +## Fixed + +- [#2491](https://github.com/plotly/dash/pull/2491) Fix clientside inline function name not found, fix [#2488](https://github.com/plotly/dash/issues/2488) + ## [2.9.2] - 2023-03-29 ## Fixed diff --git a/dash/_callback.py b/dash/_callback.py index 879d16f43b..82102aac95 100644 --- a/dash/_callback.py +++ b/dash/_callback.py @@ -1,5 +1,5 @@ import collections -import uuid +import hashlib from functools import wraps import flask @@ -534,8 +534,8 @@ def register_clientside_callback( # name, then inject the code. if isinstance(clientside_function, str): namespace = "_dashprivate_clientside_funcs" - # Just make sure every function has a different name if not provided. - function_name = uuid.uuid4().hex + # Create a hash from the function, it will be the same always + function_name = hashlib.md5(clientside_function.encode("utf-8")).hexdigest() inline_scripts.append( _inline_clientside_template.format( diff --git a/tests/integration/clientside/test_clientside_restarts.py b/tests/integration/clientside/test_clientside_restarts.py new file mode 100644 index 0000000000..b1b165f856 --- /dev/null +++ b/tests/integration/clientside/test_clientside_restarts.py @@ -0,0 +1,55 @@ +import pytest +from dash import Dash, html, Output, Input + + +@pytest.mark.skip(reason="Hot-reload & clientside callbacks doesn't work properly") +def test_clrs001_clientside_inline_restarts(dash_duo_mp): + # FIXME find another way to test clientside callbacks restarts + reloads = 0 + + def create_app(): + nonlocal reloads + + app = Dash(__name__) + + app.layout = html.Div([ + html.Button("Click", id="click"), + html.Div(id="output"), + html.Div(reloads, id="reload") + ]) + + app.clientside_callback( + "(n_clicks) => `clicked ${n_clicks}`", + Output("output", "children"), + Input("click", "n_clicks"), + prevent_initial_call=True + ) + reloads += 1 + return app + + hot_reload_settings = dict( + dev_tools_hot_reload=True, + dev_tools_ui=True, + dev_tools_serve_dev_bundles=True, + dev_tools_hot_reload_interval=0.1, + dev_tools_hot_reload_max_retry=100, + ) + + dash_duo_mp.start_server( + create_app(), + **hot_reload_settings + ) + dash_duo_mp.find_element("#click").click() + dash_duo_mp.wait_for_text_to_equal("#output", "clicked 1") + + dash_duo_mp.server.stop() + + dash_duo_mp.start_server( + create_app(), + navigate=False, + **hot_reload_settings + ) + dash_duo_mp.wait_for_text_to_equal("#reload", "1") + dash_duo_mp.find_element("#click").click() + # reloaded so 1 again. + dash_duo_mp.wait_for_text_to_equal("#output", "clicked 1")