From 4fe84dea1ba1dcc05efb2e8ea4d848f23d987238 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:24:50 +0100 Subject: [PATCH 01/10] add-startup-route-setup --- dash/dash.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dash/dash.py b/dash/dash.py index 985fb01c4f..7bac20fd3a 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -372,6 +372,7 @@ class Dash: """ _plotlyjs_url: str + STARTUP_ROUTES = [] def __init__( # pylint: disable=too-many-statements self, @@ -556,6 +557,7 @@ def __init__( # pylint: disable=too-many-statements "JupyterDash is deprecated, use Dash instead.\n" "See https://dash.plotly.com/dash-in-jupyter for more details." ) + self.setup_startup_routes() def init_app(self, app=None, **kwargs): """Initialize the parts of Dash that require a flask app.""" @@ -1626,6 +1628,38 @@ def display_content(path): self.config.requests_pathname_prefix, path ) + @staticmethod + def add_startup_route(name, view_func, methods=["POST"]): + """ + Add a route to the app to be initialized at the end of Dash initialization. + Use this if the package requires a route to be added to the app, and you will not need to worry about at what point to add it. + + :param name: The name of the route. eg "my-new-url/path". + :param view_func: The function to call when the route is requested. The function should return a JSON serializable object. + :param methods: The HTTP methods that the route should respond to. eg ["GET", "POST"] or either one. + """ + if not isinstance(name, str) or name.startswith("/"): + raise ValueError("name must be a string and should not start with '/'") + + if not callable(view_func): + raise ValueError("view_func must be callable") + + valid_methods = {"POST", "GET"} + if not set(methods).issubset(valid_methods): + raise ValueError(f"methods should only contain {valid_methods}") + + if any(route[0] == name for route in Dash.STARTUP_ROUTES): + raise ValueError(f"Route name '{name}' is already in use.") + + Dash.STARTUP_ROUTES.append((name, view_func, methods)) + + def setup_startup_routes(self): + """ + Initialize the startup routes stored in STARTUP_ROUTES. + """ + for _name, _view_func, _methods in self.STARTUP_ROUTES: + self._add_url(f"_dash_startup_route/{_name}", _view_func, _methods) + def _setup_dev_tools(self, **kwargs): debug = kwargs.get("debug", False) dev_tools = self._dev_tools = AttributeDict() From 402bd102ec5c6d78b732171aaf9c4fbe6b7689c8 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:30:32 +0100 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=94=8A=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806a9c33a2..8a08239826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## Added +- [#2832](https://github.com/plotly/dash/pull/2832) Add dash startup route setup on Dash init. - [#2819](https://github.com/plotly/dash/pull/2819) Add dash subcomponents receive additional parameters passed by the parent component. Fixes [#2814](https://github.com/plotly/dash/issues/2814). - [#2826](https://github.com/plotly/dash/pull/2826) When using Pages, allows for `app.title` and (new) `app.description` to be used as defaults for the page title and description. Fixes [#2811](https://github.com/plotly/dash/issues/2811). - [#2795](https://github.com/plotly/dash/pull/2795) Allow list of components to be passed as layout. From c69a167211eb44ed42c56ce291ba49238720a8e3 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:38:12 +0100 Subject: [PATCH 03/10] Fix lint STARTUP_ROUTES type annotation in Dash class --- dash/dash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dash/dash.py b/dash/dash.py index 7bac20fd3a..2811e056fb 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -372,7 +372,7 @@ class Dash: """ _plotlyjs_url: str - STARTUP_ROUTES = [] + STARTUP_ROUTES: list = [] def __init__( # pylint: disable=too-many-statements self, @@ -1629,7 +1629,7 @@ def display_content(path): ) @staticmethod - def add_startup_route(name, view_func, methods=["POST"]): + def add_startup_route(name, view_func, methods): """ Add a route to the app to be initialized at the end of Dash initialization. Use this if the package requires a route to be added to the app, and you will not need to worry about at what point to add it. From 51c6a2165cc0d31ffdc9bec801feed0359acc69f Mon Sep 17 00:00:00 2001 From: Liam Connors Date: Tue, 16 Apr 2024 13:17:31 -0400 Subject: [PATCH 04/10] add test --- tests/integration/test_integration.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 4108a33b7b..bac0039e77 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -511,3 +511,22 @@ def on_nested_click(n_clicks): dash_duo.wait_for_element("#nested").click() dash_duo.wait_for_text_to_equal("#nested-output", "Clicked 1 times") + + +def test_inin030_add_startup_route(dash_duo): + url = "my-new-route" + def my_route_f(): + return "hello" + Dash.add_startup_route(url, my_route_f, ["POST"]) + + import requests + + app = Dash(__name__) + Dash.STARTUP_ROUTES = [] + app.layout = html.Div("Hello World") + dash_duo.start_server(app) + + url = f"{dash_duo.server_url}{app.config.requests_pathname_prefix}_dash_startup_route/{url}" + response = requests.post(url) + assert response.status_code == 200 + assert response.text == "hello" \ No newline at end of file From 5db58e80ea02a53744850c605b488d09e06e1d2d Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:41:21 +0100 Subject: [PATCH 05/10] clear STARTUP_ROUTES after setup --- dash/dash.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dash/dash.py b/dash/dash.py index 2811e056fb..9309762c9e 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -1659,6 +1659,7 @@ def setup_startup_routes(self): """ for _name, _view_func, _methods in self.STARTUP_ROUTES: self._add_url(f"_dash_startup_route/{_name}", _view_func, _methods) + self.STARTUP_ROUTES = [] def _setup_dev_tools(self, **kwargs): debug = kwargs.get("debug", False) From 3020467631dcb3284ea33c17ead356347bdf77a9 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:41:53 +0100 Subject: [PATCH 06/10] fix formatting --- tests/integration/test_integration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index bac0039e77..04da24d306 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -529,4 +529,4 @@ def my_route_f(): url = f"{dash_duo.server_url}{app.config.requests_pathname_prefix}_dash_startup_route/{url}" response = requests.post(url) assert response.status_code == 200 - assert response.text == "hello" \ No newline at end of file + assert response.text == "hello" From b9f353a2cf132e22e28b1050dd23950637796d9a Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Thu, 18 Apr 2024 19:30:17 +0100 Subject: [PATCH 07/10] run black formatter --- tests/integration/test_integration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 04da24d306..14bd018027 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -515,8 +515,10 @@ def on_nested_click(n_clicks): def test_inin030_add_startup_route(dash_duo): url = "my-new-route" + def my_route_f(): return "hello" + Dash.add_startup_route(url, my_route_f, ["POST"]) import requests From c29212958305d8c9bc492b83e929ebca760739b0 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Fri, 19 Apr 2024 15:39:18 +0100 Subject: [PATCH 08/10] =?UTF-8?q?=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dash/dash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/dash.py b/dash/dash.py index 9309762c9e..b2913be83a 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -1631,7 +1631,7 @@ def display_content(path): @staticmethod def add_startup_route(name, view_func, methods): """ - Add a route to the app to be initialized at the end of Dash initialization. + Add a route to the app to be initialized at the end of Dash initialization. Use this if the package requires a route to be added to the app, and you will not need to worry about at what point to add it. :param name: The name of the route. eg "my-new-url/path". From 1edf9839817ad7db530a6a91ee17a4c636cec660 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:03:26 +0100 Subject: [PATCH 09/10] =?UTF-8?q?=F0=9F=9A=A8=20run=20linter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dash/dash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash/dash.py b/dash/dash.py index b2913be83a..9309762c9e 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -1631,7 +1631,7 @@ def display_content(path): @staticmethod def add_startup_route(name, view_func, methods): """ - Add a route to the app to be initialized at the end of Dash initialization. + Add a route to the app to be initialized at the end of Dash initialization. Use this if the package requires a route to be added to the app, and you will not need to worry about at what point to add it. :param name: The name of the route. eg "my-new-url/path". From 92f5fab69e352ab5a8d7d056c11d720f0d75bd63 Mon Sep 17 00:00:00 2001 From: admin <51248046+danton267@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:25:00 +0100 Subject: [PATCH 10/10] Trigger build