emilhe / dash-extensions

The dash-extensions package is a collection of utility functions, syntax extensions, and Dash components that aim to improve the Dash development experience
https://www.dash-extensions.com/
MIT License
417 stars 59 forks source link

`BlockingCallbackTransform` leading to `SchemaTypeValidationError` when using flexible callback signatures #331

Open manu418 opened 4 months ago

manu418 commented 4 months ago

Following the example from here (https://www.dash-extensions.com/transforms/blocking_callback_transform) but swapping the callback's function signature with a more flexible one (as used and required within the actual project I would love to integrate the BlockingCallbackTransform into) as described here (https://dash.plotly.com/flexible-callback-signatures#dictionary-grouping), we arrive with the following code:

import time
from dash.exceptions import PreventUpdate
from dash_extensions.enrich import DashProxy, dcc, html, Output, Input, BlockingCallbackTransform

app = DashProxy(transforms=[BlockingCallbackTransform(timeout=10)])
app.layout = html.Div([html.Div(id="output"), dcc.Interval(id="trigger")])   # default interval is 1s

@app.callback(
    inputs=dict(input_kwargs=dict(trig=Input("trigger", "n_intervals"))),
    output=dict(b=Output("output", "children")),
    blocking=True,
)
def update(input_kwargs, **kwargs):
    print("Expected inputs:", input_kwargs)
    print("Unexpected inputs:", kwargs)
    if not input_kwargs["trig"]:
        raise PreventUpdate
    time.sleep(2)  # emulate slow database
    return dict(b=f"Hello! (n_intervals is {input_kwargs['trig']})")

if __name__ == '__main__':
    app.run_server()

Sadly, this code does not work. It gives (beneath others, considered irrelevant here) the traceback

ERROR:root:Exception raised in blocking callback [update]
Traceback (most recent call last):
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/dash_extensions/enrich.py", line 685, in decorated_function
    outputs = f(*args, **kwargs)
  File "/home/me/.config/JetBrains/PyCharm2023.3/scratches/scratch_5.py", line 32, in update
    raise PreventUpdate
dash.exceptions.PreventUpdate
[2024-06-04 15:44:06,415] ERROR in app: Exception on /_dash-update-component [POST]
Traceback (most recent call last):
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/flask/app.py", line 1473, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/flask/app.py", line 882, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/flask/app.py", line 880, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/flask/app.py", line 865, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/dash/dash.py", line 1373, in dispatch
    ctx.run(
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/dash/_callback.py", line 483, in add_context
    flat_output_values = flatten_grouping(output_value, output)
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/dash/_grouping.py", line 35, in flatten_grouping
    validate_grouping(grouping, schema)
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/dash/_grouping.py", line 216, in validate_grouping
    SchemaTypeValidationError.check(grouping, full_schema, path, dict)
  File "/home/me/python_virtual_environments/venv_general/lib/python3.10/site-packages/dash/_grouping.py", line 162, in check
    raise SchemaTypeValidationError(value, full_schema, path, expected_type)
dash._grouping.SchemaTypeValidationError: Schema: {'b': <Output `output.children`>, 'dash_extensions_1': <Output `e3dbfba0-9d54-43f9-988b-de6e50207200_end_server.data`>}
Path: ()
Expected type: <class 'dict'>
Received value of type <class 'list'>:
    [<dash._callback.NoUpdate object at 0x7ca714724040>, 1717501446.414798]

It seems to me that dash-extensions does not support flexible callback signatures. I'm afraid this is due to on of the limitations of flexible callback signatures as stated here (https://dash.plotly.com/flexible-callback-signatures#limitations)

Clientside callbacks are not supported.

My question is: Is my worry correct? And if no, how could I achieve a blocking callback behavior on a callback function with flexible signature like the one above?

Utilized versions (Python 3.10):

dash==2.17.0
dash-extensions==1.0.16

Perhaps related to https://github.com/emilhe/dash-extensions/issues/202.