Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).

## Fixed
- [#3395](https://github.com/plotly/dash/pull/3395) Fix Components added through set_props() cannot trigger related callback functions. Fix [#3316](https://github.com/plotly/dash/issues/3316)
- [#3397](https://github.com/plotly/dash/pull/3397) Add optional callbacks, suppressing callback warning for missing component ids for a single callback.

## [3.2.0] - 2025-07-31

Expand Down
7 changes: 7 additions & 0 deletions dash/_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def callback(
cache_args_to_ignore: Optional[list] = None,
cache_ignore_triggered=True,
on_error: Optional[Callable[[Exception], Any]] = None,
optional: Optional[bool] = False,
**_kwargs,
) -> Callable[..., Any]:
"""
Expand Down Expand Up @@ -159,6 +160,8 @@ def callback(
Function to call when the callback raises an exception. Receives the
exception object as first argument. The callback_context can be used
to access the original callback inputs, states and output.
:param optional:
Mark all dependencies as not required on the initial layout checks.
"""

background_spec = None
Expand Down Expand Up @@ -213,6 +216,7 @@ def callback(
manager=manager,
running=running,
on_error=on_error,
optional=optional,
)


Expand Down Expand Up @@ -258,6 +262,7 @@ def insert_callback(
running=None,
dynamic_creator: Optional[bool] = False,
no_output=False,
optional=False,
):
if prevent_initial_call is None:
prevent_initial_call = config_prevent_initial_callbacks
Expand All @@ -281,6 +286,7 @@ def insert_callback(
},
"dynamic_creator": dynamic_creator,
"no_output": no_output,
"optional": optional,
}
if running:
callback_spec["running"] = running
Expand Down Expand Up @@ -624,6 +630,7 @@ def register_callback(
dynamic_creator=allow_dynamic_callbacks,
running=running,
no_output=not has_output,
optional=_kwargs.get("optional", False),
)

# pylint: disable=too-many-locals
Expand Down
18 changes: 12 additions & 6 deletions dash/dash-renderer/src/actions/dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -570,12 +570,18 @@ export function validateCallbacksToLayout(state_, dispatchError) {
for (const id in map) {
const idProps = map[id];
const fcb = flatten(values(idProps));
const optional = all(
({allow_optional}) => allow_optional,
flatten(
fcb.map(cb => concat(cb.outputs, cb.inputs, cb.states))
).filter(dep => dep.id === id)
);
const optional = fcb.reduce((acc, cb) => {
if (acc === false || cb.optional) {
return acc;
}
const deps = concat(cb.outputs, cb.inputs, cb.states).filter(
dep => dep.id === id
);
return (
!deps.length ||
all(({allow_optional}) => allow_optional, deps)
);
}, true);
if (optional) {
continue;
}
Expand Down