diff --git a/CHANGELOG.md b/CHANGELOG.md index de4049c614..9ca7cfb694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## Added - [#3534]((https://github.com/plotly/dash/pull/3534) Adds `playsInline` prop to `html.Video`. Based on [#2338]((https://github.com/plotly/dash/pull/2338) - [#3541](https://github.com/plotly/dash/pull/3541) Add `attributes` dictionary to be be formatted on script/link (_js_dist/_css_dist) tags of the index, allows for `type="module"` or `type="importmap"`. [#3538](https://github.com/plotly/dash/issues/3538) +- [#3564](https://github.com/plotly/dash/pull/3564) Add new parameter `hide_all_callbacks` to `dash.Dash()`. Closes [#3493](https://github.com/plotly/dash/issues/3493) ## Fixed - [#3541](https://github.com/plotly/dash/pull/3541) Remove last reference of deprecated `pkg_resources`. diff --git a/dash/_callback.py b/dash/_callback.py index 9b272895c8..0d51c15d03 100644 --- a/dash/_callback.py +++ b/dash/_callback.py @@ -79,7 +79,7 @@ def callback( on_error: Optional[Callable[[Exception], Any]] = None, api_endpoint: Optional[str] = None, optional: Optional[bool] = False, - hidden: Optional[bool] = False, + hidden: Optional[bool] = None, **_kwargs, ) -> Callable[..., Any]: """ @@ -277,7 +277,7 @@ def insert_callback( dynamic_creator: Optional[bool] = False, no_output=False, optional=False, - hidden=False, + hidden=None, ): if prevent_initial_call is None: prevent_initial_call = config_prevent_initial_callbacks @@ -651,7 +651,7 @@ def register_callback( running=running, no_output=not has_output, optional=_kwargs.get("optional", False), - hidden=_kwargs.get("hidden", False), + hidden=_kwargs.get("hidden", None), ) # pylint: disable=too-many-locals diff --git a/dash/dash.py b/dash/dash.py index 749e38d107..53427a4c2b 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -69,7 +69,12 @@ from . import _watch from . import _get_app -from ._get_app import with_app_context, with_app_context_async, with_app_context_factory +from ._get_app import ( + get_app, + with_app_context, + with_app_context_async, + with_app_context_factory, +) from ._grouping import map_grouping, grouping_len, update_args_group from ._obsolete import ObsoleteChecker @@ -367,6 +372,13 @@ class Dash(ObsoleteChecker): those callbacks you wish to have an initial call. This setting has no effect on triggering callbacks when their inputs change later on. + :param hide_all_callbacks: Default ``False``: Sets the default value of + ``hidden`` for all callbacks added to the app. Normally all callbacks + are visible in the devtools callbacks tab. You can set this for + individual callbacks by setting ``hidden`` in their definitions, or set + it ``True`` here in which case you must explicitly set it ``False`` for + those callbacks you wish to remain visible in the devtools callbacks tab. + :param show_undo_redo: Default ``False``, set to ``True`` to enable undo and redo buttons for stepping through the history of the app state. :type show_undo_redo: boolean @@ -457,6 +469,7 @@ def __init__( # pylint: disable=too-many-statements external_stylesheets: Optional[Sequence[Union[str, Dict[str, Any]]]] = None, suppress_callback_exceptions: Optional[bool] = None, prevent_initial_callbacks: bool = False, + hide_all_callbacks: bool = False, show_undo_redo: bool = False, extra_hot_reload_paths: Optional[Sequence[str]] = None, plugins: Optional[list] = None, @@ -537,6 +550,7 @@ def __init__( # pylint: disable=too-many-statements "suppress_callback_exceptions", suppress_callback_exceptions, False ), prevent_initial_callbacks=prevent_initial_callbacks, + hide_all_callbacks=hide_all_callbacks, show_undo_redo=show_undo_redo, extra_hot_reload_paths=extra_hot_reload_paths or [], title=title, @@ -1645,7 +1659,18 @@ def _setup_server(self): self.callback_map[k] = _callback.GLOBAL_CALLBACK_MAP.pop(k) + # Get config of current app instance + current_app_config = get_app().config + self._callback_list.extend(_callback.GLOBAL_CALLBACK_LIST) + # For each callback function, if the hidden parameter uses the default value None, + # replace it with the actual value of the hide_all_callbacks property of the current application instance. + self._callback_list = [ + {**_callback, "hidden": current_app_config.get("hide_all_callbacks", False)} + if _callback.get("hidden") is None + else _callback + for _callback in self._callback_list + ] _callback.GLOBAL_CALLBACK_LIST.clear() _validate.validate_background_callbacks(self.callback_map)