Black Lives Matter. Please consider donating to Black Girls Code today.

How to leave callback Output unchanged

Hi.

I want to not change the Output of a callback when certain conditions are met. If I just do return, the output is left blank.
How can I do that?

You can achieve this by raising an exception at the desired point in your callback I believe.

This was discussed just recently in this thread.

1 Like

Is that the only solution? a bit dirty, isn’t it?

1 Like

This is the recommended solution - the exception denotes that the state transition in the app should not happen.
Another way to do this would be to pass in the existing state of the output into the callback and return that, like:

@app.callback(Output('my-div', 'children'),
                     [Input('my-input', 'value')],
                     [State('my-div', 'children')])
def update_div(value, existing_state):
    if some_condition:
         return existing_state

Again, this will result in the same behaviour as throwing an exception. Also, this will make your network requests larger as the requests and responses have to include the State. Not a big deal for small data, could make things a little larger if your dealing with huge figure objects.

Is there a way to not have the Exception print a stack trace, when we do this? Some sort of code to set or type that’s ignored by dash code that’s passing it through? Because now its normal flow control so don’t want to clutter log with many normal flow stack traces.

I’ve figured out the passing in the existing state when no change, but like you mention its slow to pass back and forth figures with large #of data points for no reason. Also it will still trigger other callbacks to fire that depend on this figure right? Even as the figure is still same as existing_state.

Yeah, that’s correct.

For now, there might be a way to set this on the flask side of things or by overriding python’s exception handler in some way.

In the future, perhaps we’ll provide an explicit exception class that users can raise and that Dash will catch and return a 500 without printing the exception.

2 Likes

Seems like instead of raising an exception:

if this_callback_shoud_not_return():
    raise NotReturningException()

You can probably get away with pass:

if this_callback_shoud_not_return():
    pass

I’m currently doing this to controls that I’ve hidden so I can’t guarantee, but I’m not seeing any exceptions in the JS console, and functionality Still Works

@rad - If you don’t return anything in a callback, you are technically returning None which will get transformed into null and Dash should update the output property as null, which is valid for some cases (e.g. None as a dcc.Dropdown.value is OK - it means nothing is selected and None as a children property is OK too, it means no element) but not valid for other properties (e.g. options of a Dropdown can’t be None, as you saw here: Debug something not updating on particular callback, inscrutable JS “promise” error).
In some cases, it will clear the output, rather than leave the output to be unchanged.

@chriddyp thanks for the warning.

I’m a little confused, though, because I can confirm that return None and pass do not have the same effect. I just changed pass in one callback to return None and got the issue you referenced. Not so with pass :man_shrugging:

They should have the same effect. If you look under the hood, Python generates the same bytecode for them:

def foo():
    pass

def bar():
    return None
>>> import dis
>>> dis.dis(foo)
  2           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE        
>>> dis.dis(bar)
  2           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE
1 Like

@nedned has IMO a great solution for this in Improving handling of aborted callbacks. If you have any feedback, please comment on that thread :slight_smile:

Again, the answers are incomplete. Where do you get NotReturningException from??

This is now officially documented in https://dash.plot.ly/state. You can either raise PreventUpdate or return dash.no_update. The latter is what you’d need to use for certain multiple outputs scenarios.

1 Like