19
19
from typing import Any , Callable , Dict , Optional , Union , List
20
20
21
21
import flask
22
+ import asyncio
22
23
23
24
from importlib_metadata import version as _get_distribution_version
24
25
@@ -191,6 +192,14 @@ def _do_skip(error):
191
192
# Singleton signal to not update an output, alternative to PreventUpdate
192
193
no_update = _callback .NoUpdate () # pylint: disable=protected-access
193
194
195
+ async def execute_async_function (func , * args , ** kwargs ):
196
+ # Check if the function is a coroutine function
197
+ if asyncio .iscoroutinefunction (func ):
198
+ return await func (* args , ** kwargs )
199
+ else :
200
+ # If the function is not a coroutine, call it directly
201
+ return func (* args , ** kwargs )
202
+
194
203
195
204
# pylint: disable=too-many-instance-attributes
196
205
# pylint: disable=too-many-arguments, too-many-locals
@@ -1267,7 +1276,7 @@ def long_callback(
1267
1276
)
1268
1277
1269
1278
# pylint: disable=R0915
1270
- def dispatch (self ):
1279
+ async def dispatch (self ):
1271
1280
body = flask .request .get_json ()
1272
1281
1273
1282
g = AttributeDict ({})
@@ -1371,19 +1380,27 @@ def dispatch(self):
1371
1380
raise KeyError (msg ) from missing_callback_function
1372
1381
1373
1382
ctx = copy_context ()
1383
+ # Create a partial function with the necessary arguments
1374
1384
# noinspection PyArgumentList
1385
+ partial_func = functools .partial (
1386
+ execute_async_function ,
1387
+ func ,
1388
+ * args ,
1389
+ outputs_list = outputs_list ,
1390
+ long_callback_manager = self ._background_manager ,
1391
+ callback_context = g ,
1392
+ app = self ,
1393
+ app_on_error = self ._on_error ,
1394
+ )
1395
+
1396
+ response_data = await ctx .run (partial_func )
1397
+
1398
+ # Check if the response is a coroutine
1399
+ if asyncio .iscoroutine (response_data ):
1400
+ response_data = await response_data
1401
+
1375
1402
response .set_data (
1376
- ctx .run (
1377
- functools .partial (
1378
- func ,
1379
- * args ,
1380
- outputs_list = outputs_list ,
1381
- long_callback_manager = self ._background_manager ,
1382
- callback_context = g ,
1383
- app = self ,
1384
- app_on_error = self ._on_error ,
1385
- )
1386
- )
1403
+ response_data
1387
1404
)
1388
1405
return response
1389
1406
@@ -2206,7 +2223,7 @@ def router():
2206
2223
inputs = inputs ,
2207
2224
prevent_initial_call = True ,
2208
2225
)
2209
- def update (pathname_ , search_ , ** states ):
2226
+ async def update (pathname_ , search_ , ** states ):
2210
2227
"""
2211
2228
Updates dash.page_container layout on page navigation.
2212
2229
Updates the stored page title which will trigger the clientside callback to update the app title
@@ -2231,27 +2248,28 @@ def update(pathname_, search_, **states):
2231
2248
layout = page .get ("layout" , "" )
2232
2249
title = page ["title" ]
2233
2250
2234
- if callable (layout ):
2235
- layout = (
2236
- layout (** path_variables , ** query_parameters , ** states )
2237
- if path_variables
2238
- else layout (** query_parameters , ** states )
2239
- )
2240
- if callable (title ):
2241
- title = title (** path_variables ) if path_variables else title ()
2242
-
2243
- return layout , {"title" : title }
2244
-
2245
- _validate .check_for_duplicate_pathnames (_pages .PAGE_REGISTRY )
2246
- _validate .validate_registry (_pages .PAGE_REGISTRY )
2247
-
2248
- # Set validation_layout
2249
- if not self .config .suppress_callback_exceptions :
2250
- self .validation_layout = html .Div (
2251
- [
2252
- page ["layout" ]() if callable (page ["layout" ]) else page ["layout" ]
2253
- for page in _pages .PAGE_REGISTRY .values ()
2254
- ]
2251
+ if callable (layout ):
2252
+ layout = await execute_async_function (layout ,
2253
+ ** {** (path_variables or {}), ** query_parameters , ** states }
2254
+ )
2255
+ if callable (title ):
2256
+ title = await execute_async_function (title ,
2257
+ ** (path_variables or {})
2258
+ )
2259
+
2260
+ return layout , {"title" : title }
2261
+
2262
+ _validate .check_for_duplicate_pathnames (_pages .PAGE_REGISTRY )
2263
+ _validate .validate_registry (_pages .PAGE_REGISTRY )
2264
+
2265
+ # Set validation_layout
2266
+ if not self .config .suppress_callback_exceptions :
2267
+ self .validation_layout = html .Div (
2268
+ [
2269
+ asyncio .run (execute_async_function (page ["layout" ])) if callable (page ["layout" ]) else page [
2270
+ "layout" ]
2271
+ for page in _pages .PAGE_REGISTRY .values ()
2272
+ ]
2255
2273
+ [
2256
2274
# pylint: disable=not-callable
2257
2275
self .layout ()
0 commit comments