Skip to content

Commit a157deb

Browse files
committed
fixing issue with side-updates from background callbacks
1 parent b34673a commit a157deb

File tree

4 files changed

+103
-45
lines changed

4 files changed

+103
-45
lines changed

dash/dash-renderer/src/actions/callbacks.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,9 @@ function handleServerside(
623623
}
624624

625625
if (data.sideUpdate) {
626-
dispatch(sideUpdate(data.sideUpdate, payload));
626+
setTimeout(() =>
627+
dispatch(sideUpdate(data.sideUpdate, payload))
628+
); // always force side-updates
627629
}
628630

629631
if (data.progress) {
@@ -831,9 +833,20 @@ export function executeCallback(
831833
const outputPath = getPath(paths, out.id);
832834
const dataPath = [stringifyId(out.id), propName];
833835
const outputValue = path(dataPath, data);
834-
const oldProps = path(outputPath.concat(['props']), currentLayout) || {};
835-
const newProps = parsePatchProps({ [propName]: outputValue }, oldProps);
836-
data = assocPath(dataPath, newProps[propName], data);
836+
const oldProps =
837+
path(
838+
outputPath.concat(['props']),
839+
currentLayout
840+
) || {};
841+
const newProps = parsePatchProps(
842+
{[propName]: outputValue},
843+
oldProps
844+
);
845+
data = assocPath(
846+
dataPath,
847+
newProps[propName],
848+
data
849+
);
837850
});
838851
return {data, payload};
839852
} catch (error: any) {
@@ -900,9 +913,20 @@ export function executeCallback(
900913
const outputPath = getPath(paths, out.id);
901914
const dataPath = [stringifyId(out.id), propName];
902915
const outputValue = path(dataPath, data);
903-
const oldProps = path(outputPath.concat(['props']), currentLayout) || {};
904-
const newProps = parsePatchProps({ [propName]: outputValue }, oldProps);
905-
data = assocPath(dataPath, newProps[propName], data);
916+
const oldProps =
917+
path(
918+
outputPath.concat(['props']),
919+
currentLayout
920+
) || {};
921+
const newProps = parsePatchProps(
922+
{[propName]: outputValue},
923+
oldProps
924+
);
925+
data = assocPath(
926+
dataPath,
927+
newProps[propName],
928+
data
929+
);
906930
});
907931

908932
if (dynamic_creator) {

dash/dash-renderer/src/actions/patch.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export class PatchBuilder {
175175

176176
build() {
177177
return {
178-
__dash_patch_update: "__dash_patch_update",
178+
__dash_patch_update: '__dash_patch_update',
179179
operations: this.operations
180180
};
181181
}
@@ -304,7 +304,10 @@ export function handlePatch<T>(previousValue: T, patchValue: any): T {
304304
return reducedValue;
305305
}
306306

307-
export function parsePatchProps(props: any, previousProps: any): Record<string, any> {
307+
export function parsePatchProps(
308+
props: any,
309+
previousProps: any
310+
): Record<string, any> {
308311
if (!is(Object, props)) {
309312
return props;
310313
}

tests/integration/test_clientside_patch.py

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,28 @@ def test_pch_cs001_patch_operations_clientside(dash_duo):
1515
app.layout = html.Div(
1616
[
1717
html.Div([dcc.Input(id="set-value"), html.Button("Set", id="set-btn")]),
18-
html.Div([dcc.Input(id="append-value"), html.Button("Append", id="append-btn")]),
19-
html.Div([dcc.Input(id="prepend-value"), html.Button("prepend", id="prepend-btn")]),
20-
html.Div([
21-
dcc.Input(id="insert-value"),
22-
dcc.Input(id="insert-index", type="number", value=1),
23-
html.Button("insert", id="insert-btn"),
24-
]),
25-
html.Div([dcc.Input(id="extend-value"), html.Button("extend", id="extend-btn")]),
26-
html.Div([dcc.Input(id="merge-value"), html.Button("Merge", id="merge-btn")]),
18+
html.Div(
19+
[dcc.Input(id="append-value"), html.Button("Append", id="append-btn")]
20+
),
21+
html.Div(
22+
[
23+
dcc.Input(id="prepend-value"),
24+
html.Button("prepend", id="prepend-btn"),
25+
]
26+
),
27+
html.Div(
28+
[
29+
dcc.Input(id="insert-value"),
30+
dcc.Input(id="insert-index", type="number", value=1),
31+
html.Button("insert", id="insert-btn"),
32+
]
33+
),
34+
html.Div(
35+
[dcc.Input(id="extend-value"), html.Button("extend", id="extend-btn")]
36+
),
37+
html.Div(
38+
[dcc.Input(id="merge-value"), html.Button("Merge", id="merge-btn")]
39+
),
2740
html.Button("Delete", id="delete-btn"),
2841
html.Button("Delete index", id="delete-index"),
2942
html.Button("Clear", id="clear-btn"),
@@ -227,7 +240,7 @@ def get_output():
227240
_input.send_keys("Set Value")
228241
dash_duo.find_element("#set-btn").click()
229242

230-
until(lambda: get_output().get('value') == "Set Value", 2)
243+
until(lambda: get_output().get("value") == "Set Value", 2)
231244

232245
_input = dash_duo.find_element("#append-value")
233246
_input.send_keys("Append")
@@ -246,7 +259,8 @@ def get_output():
246259
dash_duo.find_element("#extend-btn").click()
247260

248261
until(
249-
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"], 2
262+
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"],
263+
2,
250264
)
251265

252266
undef = object()
@@ -337,22 +351,36 @@ def get_output():
337351
dash_duo.find_element("#clear-btn").click()
338352
until(lambda: get_output()["array"] == [], 2)
339353

354+
340355
@flaky.flaky(max_runs=3)
341356
def test_pch_cs002_patch_operations_set_props(dash_duo):
342357
app = Dash(__name__)
343358

344359
app.layout = html.Div(
345360
[
346361
html.Div([dcc.Input(id="set-value"), html.Button("Set", id="set-btn")]),
347-
html.Div([dcc.Input(id="append-value"), html.Button("Append", id="append-btn")]),
348-
html.Div([dcc.Input(id="prepend-value"), html.Button("prepend", id="prepend-btn")]),
349-
html.Div([
350-
dcc.Input(id="insert-value"),
351-
dcc.Input(id="insert-index", type="number", value=1),
352-
html.Button("insert", id="insert-btn"),
353-
]),
354-
html.Div([dcc.Input(id="extend-value"), html.Button("extend", id="extend-btn")]),
355-
html.Div([dcc.Input(id="merge-value"), html.Button("Merge", id="merge-btn")]),
362+
html.Div(
363+
[dcc.Input(id="append-value"), html.Button("Append", id="append-btn")]
364+
),
365+
html.Div(
366+
[
367+
dcc.Input(id="prepend-value"),
368+
html.Button("prepend", id="prepend-btn"),
369+
]
370+
),
371+
html.Div(
372+
[
373+
dcc.Input(id="insert-value"),
374+
dcc.Input(id="insert-index", type="number", value=1),
375+
html.Button("insert", id="insert-btn"),
376+
]
377+
),
378+
html.Div(
379+
[dcc.Input(id="extend-value"), html.Button("extend", id="extend-btn")]
380+
),
381+
html.Div(
382+
[dcc.Input(id="merge-value"), html.Button("Merge", id="merge-btn")]
383+
),
356384
html.Button("Delete", id="delete-btn"),
357385
html.Button("Delete index", id="delete-index"),
358386
html.Button("Clear", id="clear-btn"),
@@ -545,7 +573,7 @@ def get_output():
545573
_input.send_keys("Set Value")
546574
dash_duo.find_element("#set-btn").click()
547575

548-
until(lambda: get_output().get('value') == "Set Value", 2)
576+
until(lambda: get_output().get("value") == "Set Value", 2)
549577

550578
_input = dash_duo.find_element("#append-value")
551579
_input.send_keys("Append")
@@ -564,7 +592,8 @@ def get_output():
564592
dash_duo.find_element("#extend-btn").click()
565593

566594
until(
567-
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"], 2
595+
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"],
596+
2,
568597
)
569598

570599
undef = object()

tests/integration/test_patch.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ def get_output():
239239
dash_duo.find_element("#extend-btn").click()
240240

241241
until(
242-
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"], 2
242+
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"],
243+
2,
243244
)
244245

245246
undef = object()
@@ -571,6 +572,7 @@ def on_merge(_):
571572
"#dict-store-output", '{"initial":"initial","merged":"merged"}'
572573
)
573574

575+
574576
@flaky.flaky(max_runs=3)
575577
def test_pch007_patch_operations_side_updates(dash_duo):
576578

@@ -640,7 +642,6 @@ def test_pch007_patch_operations_side_updates(dash_duo):
640642
)
641643

642644
@app.callback(
643-
644645
Input("set-btn", "n_clicks"),
645646
State("set-value", "value"),
646647
prevent_initial_call=True,
@@ -650,7 +651,7 @@ def on_click(_, value):
650651
p.value = value
651652
p.n_clicks += 1
652653

653-
set_props('store', {'data': p})
654+
set_props("store", {"data": p})
654655

655656
@app.callback(
656657
Input("append-btn", "n_clicks"),
@@ -662,7 +663,7 @@ def on_click(_, value):
662663
p.array.append(value)
663664
p.n_clicks += 1
664665

665-
set_props('store', {'data': p})
666+
set_props("store", {"data": p})
666667

667668
@app.callback(
668669
Input("prepend-btn", "n_clicks"),
@@ -674,7 +675,7 @@ def on_click(_, value):
674675
p.array.prepend(value)
675676
p.n_clicks += 1
676677

677-
set_props('store', {'data': p})
678+
set_props("store", {"data": p})
678679

679680
@app.callback(
680681
Input("extend-btn", "n_clicks"),
@@ -686,7 +687,7 @@ def on_click(_, value):
686687
p.array.extend([value])
687688
p.n_clicks += 1
688689

689-
set_props('store', {'data': p})
690+
set_props("store", {"data": p})
690691

691692
@app.callback(
692693
Input("merge-btn", "n_clicks"),
@@ -698,7 +699,7 @@ def on_click(_, value):
698699
p.update({"merged": value})
699700
p.n_clicks += 1
700701

701-
set_props('store', {'data': p})
702+
set_props("store", {"data": p})
702703

703704
@app.callback(
704705
Input("delete-btn", "n_clicks"),
@@ -707,7 +708,7 @@ def on_click(_, value):
707708
def on_click(_):
708709
p = Patch()
709710
del p.delete
710-
set_props('store', {'data': p})
711+
set_props("store", {"data": p})
711712

712713
@app.callback(
713714
Input("insert-btn", "n_clicks"),
@@ -719,7 +720,7 @@ def on_insert(_, value, index):
719720
p = Patch()
720721
p.array.insert(index, value)
721722

722-
set_props('store', {'data': p})
723+
set_props("store", {"data": p})
723724

724725
@app.callback(
725726
Input("delete-index", "n_clicks"),
@@ -730,7 +731,7 @@ def on_click(_):
730731
del p.array[1]
731732
del p.array[-2]
732733

733-
set_props('store', {'data': p})
734+
set_props("store", {"data": p})
734735

735736
@app.callback(
736737
Input("clear-btn", "n_clicks"),
@@ -740,7 +741,7 @@ def on_clear(_):
740741
p = Patch()
741742
p.array.clear()
742743

743-
set_props('store', {'data': p})
744+
set_props("store", {"data": p})
744745

745746
@app.callback(
746747
Input("reverse-btn", "n_clicks"),
@@ -750,7 +751,7 @@ def on_reverse(_):
750751
p = Patch()
751752
p.array.reverse()
752753

753-
set_props('store', {'data': p})
754+
set_props("store", {"data": p})
754755

755756
@app.callback(
756757
Input("remove-btn", "n_clicks"),
@@ -759,7 +760,7 @@ def on_reverse(_):
759760
def on_remove(_):
760761
p = Patch()
761762
p.array.remove("initial")
762-
set_props('store', {'data': p})
763+
set_props("store", {"data": p})
763764

764765
dash_duo.start_server(app)
765766

@@ -792,7 +793,8 @@ def get_output():
792793
dash_duo.find_element("#extend-btn").click()
793794

794795
until(
795-
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"], 2
796+
lambda: get_output().get("array") == ["Prepend", "initial", "Append", "Extend"],
797+
2,
796798
)
797799

798800
undef = object()

0 commit comments

Comments
 (0)