Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multioutput requiring same number of no_update. #2987

Merged
merged 4 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).

## [UNRELEASED]

## Fixed

- [#2987](https://github.com/plotly/dash/pull/2987) Fix multioutput requiring same number of no_update. Fixes [#2986](https://github.com/plotly/dash/issues/2986)

## Deprecated

- [#2985](https://github.com/plotly/dash/pull/2985) Deprecate dynamic component loader.
Expand Down
14 changes: 9 additions & 5 deletions dash/_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,12 +528,16 @@ def add_context(*args, **kwargs):
# list or tuple
output_value = list(output_value)

# Flatten grouping and validate grouping structure
flat_output_values = flatten_grouping(output_value, output)
if NoUpdate.is_no_update(output_value):
flat_output_values = [output_value]
else:
# Flatten grouping and validate grouping structure
flat_output_values = flatten_grouping(output_value, output)

_validate.validate_multi_return(
output_spec, flat_output_values, callback_id
)
if not NoUpdate.is_no_update(output_value):
_validate.validate_multi_return(
output_spec, flat_output_values, callback_id
)

for val, spec in zip(flat_output_values, output_spec):
if NoUpdate.is_no_update(val):
Expand Down
35 changes: 34 additions & 1 deletion tests/integration/callbacks/test_missing_outputs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import time

import pytest
from multiprocessing import Lock, Value

import dash
from dash import Dash, Input, Output, ALL, MATCH, html, dcc
from dash import Dash, Input, Output, ALL, MATCH, html, dcc, no_update

from dash.testing.wait import until

Expand Down Expand Up @@ -336,3 +338,34 @@ def chapter2_assertions():
dash_duo._wait_for_callbacks()
chapter2_assertions()
assert not dash_duo.get_logs()


def test_cbmo005_no_update_single_to_multi(dash_duo):
# Bugfix for #2986
app = dash.Dash(__name__)

app.layout = html.Div(
[
dcc.Input(id="input-box", type="text", value=""),
html.Button("Submit", id="button"),
html.Div(id="output-1", children="Output 1 will be displayed here"),
html.Div(id="output-2", children="Output 2 will be displayed here"),
]
)

@app.callback(
Output("output-1", "children"),
Output("output-2", "children"),
Input("button", "n_clicks"),
Input("input-box", "value"),
)
def update_outputs(n_clicks, value):
if n_clicks is None:
return no_update
return "Hello", "world!"

dash_duo.start_server(app)

# just wait to make sure the error get logged.
time.sleep(1)
assert dash_duo.get_logs() == []
3 changes: 3 additions & 0 deletions tests/integration/renderer/test_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

from dash import Dash, html, dcc, Input, Output

from flaky import flaky


@flaky(max_runs=3)
def test_rddp001_dependencies_on_components_that_dont_exist(dash_duo):
app = Dash(__name__, suppress_callback_exceptions=True)
app.layout = html.Div(
Expand Down