Open audetto opened 4 years ago
👍 Can confirm this issue. Current setup involves using a hidden div to store data to feed into several child components (where the hidden div is the only input).
The callback correctly calls the update function, the update function correctly returns the value to store in it's div. However, the UI does not update.
Looks like this is still an issue in 1.10.
Ah sorry, #1103 did not get merged yet but will soon, so let's check again in 1.11. That shouldn't be more than a week or so 😄
Tried 1.11 and things have changed
1) GOOD: all callbacks seem to be called after GUI interaction 2) GOOD: dcc.Loading() show the loading indicator even in the initialisation phase 3) BAD: not all initial callbacks are triggered
As usual I do not have an example but I seem to have found a pattern
UI, an input A has some value property B set to something in the layout A callback X triggered from a button C has output Output(A, B) Another callback Y has this input Input(A, B)
So the logic is that either the user enters the value directly in the UI or clicks some button which populates it.
Now callback X is called, but because n_clicks is 0 it returns PreventUpdate. Callback Y is never called.
If I do not register X, then Y is called.
Am I doing the right thing? Not sure, before it worked. How is the initialisation phase supposed to work?
Now callback X is called, but because n_clicks is 0 it returns PreventUpdate. Callback Y is never called.
@audetto yes, that's actually as intended - all callbacks get an initial call, except if all the inputs to the callback are themselves outputs of some other callback and all of those outputs get prevented. Prior to v1.11 this was not handled entirely consistently, but that is how it has been handled since before v1.0: https://github.com/plotly/dash/blob/3ec55b5a97fdd34ed8384085df884d86730b1a9c/tests/integration/test_integration.py#L158-L160
So knowing that, you can either have your callback X not PreventUpdate
(give it the current value as State
and just return it, perhaps), or give callback Y another input that's unused except to provide an initial trigger.
I have added the dummy Input to trigger it, but it feels a weak solution which could break at any time when I add another callback in a different place.
Dash could very well simulate the dummy input by ensuring all callbacks are triggered initially, exactly as if they all depended on the dummy input.
What I think would help me a lot is the exact rule used by dash to traverse the dependencies, which I guess is a lot less trivial that I originally thought, with so many more corner cases (for dash) to consider.
Dash could very well simulate the dummy input by ensuring all callbacks are triggered initially, exactly as if they all depended on the dummy input.
Apologies for any confusion this has generated! In fact as I was refactoring the callback pipeline for #1103 initially it worked as you were hoping. But seeing that the above test failed, this was a corner case I had to add a fix for explicitly. Our goal was to ensure backward compatibility with every known expected case, while fixing cases we considered bugs.
I agree that this one has arguments either way, but since we already had an explicit test this seems pretty clearly the expected interpretation. The main argument in its favor is I think a variant of your worry about adding more callbacks: if you have one callback that's calling PreventUpdate
and only later add another one that flows directly from it, it's reasonable to expect that the PreventUpdate
would halt the whole callback chain initially since that's what it does later on.
What I think would help me a lot is the exact rule used by dash to traverse the dependencies
That's a good idea - we should describe these details in the docs. Here's a start - probably needs a bit of elaboration to be at level we need but I think it's complete in the logic:
children
with new components, none of the inputs are considered to have "changed" unless (1) they're outputs of another callback, or (2) the callback is updating something outside the new children
(not possible for initial load)That's a good idea - we should describe these details in the docs
(Good idea - Here's an issue: https://github.com/plotly/dash-docs/issues/852. I'll work on adding this in the coming weeks when I make my way over to the callback docs.)
Describe your context
Python 3.6.6 on Windows 7
Describe the bug
The Output of a callback is not fed as input to the next one
Callback 1: Some input -> Outputs A B C D Callback 2: Input B C -> Output E Callback 3: Input A B C D E -> Output F
B: dbc.Select C: dcc.Slider E: dbc.Input
The problem is that Callback 3 never sees the updated E output of 2, even though it is definitely computed. Moreover, the GUI (E) is not updated either. But if I trigger manually C, then all works correctly again.
I added full logging and I see Callback 2 called multiple times with different triggers and the correct calculation is performed, but just it never used. I thought at the begin that Callback 2 was called with stale input, but it is not the case. It is called correctly, but its results seems to be discarded.
Expected behavior
At some point Callback 3 should be called with the new output of E. In my example it is triggered multiple times, but never with the new output E.
Screenshots
This happens at work. Cant take anything out of it.