Closed jonnyrobbie closed 2 years ago
I haven't had the time to try out the long callback with the new syntax, so I am not sure. But I don't see any immediate blockers.
Yes, you should be able to use the syntax without the app reference, i.e. something like,
from dash_extensions.enrich import callback
@callback(...)
Ok, I may need to investigate a bit more (create a MWE), but it seems like it may be incompatible with dash.callback(progress=...) argument. When you pass in that argument, the callback function expects another argument at the front of the callback function signature and that may be throwing enrich off:
Traceback (most recent call last):
File "/usr/local/anaconda3/envs/soe/lib/python3.7/site-packages/dash/long_callback/managers/diskcache_manager.py", line 163, in job_fn
user_callback_output = fn(*maybe_progress, *user_callback_args)
File "/usr/local/anaconda3/envs/soe/lib/python3.7/site-packages/dash_extensions/enrich.py", line 1172, in decorated_function
filtered_args = [arg for i, arg in enumerate(args) if not is_trigger[i]]
File "/usr/local/anaconda3/envs/soe/lib/python3.7/site-packages/dash_extensions/enrich.py", line 1172, in <listcomp>
filtered_args = [arg for i, arg in enumerate(args) if not is_trigger[i]]
IndexError: list index out of range
Ok, here's a MWE (slightly altered mwe from your repo):
import time
import plotly.express as px
import diskcache
from dash_extensions.enrich import DashProxy, Output, Input, State, ServersideOutput, html, dcc, \
ServersideOutputTransform
from dash import DiskcacheManager
cache = diskcache.Cache(".")
background_callback_manager = DiskcacheManager(cache)
app = DashProxy(transforms=[ServersideOutputTransform()])
app.layout = html.Div(
[
html.Button("Query data", id="btn"),
html.Div("", id="progress"),
dcc.Dropdown(id="dd"),
dcc.Graph(id="graph"),
dcc.Loading(dcc.Store(id="store"), fullscreen=True, type="dot"),
]
)
@app.callback(ServersideOutput("store", "data"), Input("btn", "n_clicks"), prevent_initial_call=True, background=True, progress=[Output("progress", "children")], manager=background_callback_manager)
def query_data(set_progress, n_clicks):
set_progress(("0%"))
time.sleep(1)
set_progress(("50%"))
time.sleep(1) # emulate slow database operation
set_progress(("100%"))
return px.data.gapminder() # no JSON serialization here
@app.callback(Output("dd", "options"), Output("dd", "value"), Input("store", "data"), prevent_initial_call=True)
def update_dd(df):
options = [{"label": column, "value": column} for column in df["year"]] # no JSON de-serialization here
return options, options[0]['value']
@app.callback(Output("graph", "figure"), [Input("dd", "value"), State("store", "data")], prevent_initial_call=True)
def update_graph(value, df):
df = df.query("year == {}".format(value)) # no JSON de-serialization here
return px.sunburst(df, path=["continent", "country"], values="pop", color="lifeExp", hover_data=["iso_alpha"])
if __name__ == "__main__":
app.run_server()
@jonnyrobbie Thanks for the example, and the PR. That helped my understand the root cause of the issue. I have just pushed a 0.1.6rc4
pre release to pypi, which includes a possible fix. Could you check if it works as intended for your use case?
Yep, 0.1.6rc4 seems to be working fine, thanks.
I noticed that somewhere in the documentation, it is mentioned that long_callback is not supported with serverside output. But long_callback has been deprecated by plotly in favour of background callback, which is part of built in @app.callback decorator. Is background callback thus supported as well thanks to that?
Also, there's a new syntax where you don't have to reference created app object with callback, but can rererence the dash module itself like @dash.callback(...). Is that also supported with ServersideOutput and ServersiteOutputTransform?