Skip to content

Commit

Permalink
Remove _action_loop_utils.py
Browse files Browse the repository at this point in the history
  • Loading branch information
antonymilne committed Nov 28, 2024
1 parent 8481e1a commit cb8a779
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 56 deletions.
13 changes: 10 additions & 3 deletions vizro-core/src/vizro/actions/_action_loop/_action_loop.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""The action loop creates all the required action callbacks and its components."""

from collections.abc import Iterable
from typing import cast

from dash import html

from vizro.actions._action_loop._action_loop_utils import _get_actions_on_registered_pages
from vizro.actions._action_loop._build_action_loop_callbacks import _build_action_loop_callbacks
from vizro.actions._action_loop._get_action_loop_components import _get_action_loop_components
from vizro.managers import model_manager
from vizro.models import Action


class ActionLoop:
Expand Down Expand Up @@ -37,5 +41,8 @@ def _build_actions_models():
List of required components for each `Action` in the `Dashboard` e.g. list[dcc.Download]
"""
actions = _get_actions_on_registered_pages()
return html.Div([action.build() for action in actions], id="app_action_models_components_div", hidden=True)
return html.Div(
[action.build() for action in cast(Iterable[Action], model_manager._get_models(Action))],
id="app_action_models_components_div",
hidden=True,
)
37 changes: 0 additions & 37 deletions vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@

from dash import ClientsideFunction, Input, Output, State, clientside_callback

from vizro.actions._action_loop._action_loop_utils import (
_get_actions_chains_on_all_pages,
_get_actions_on_registered_pages,
)
from vizro.managers import model_manager
from vizro.managers._model_manager import ModelID
from vizro.models import Action
from vizro.models._action._actions_chain import ActionsChain

logger = logging.getLogger(__name__)


def _build_action_loop_callbacks() -> None:
"""Creates all required dash callbacks for the action loop."""
actions_chains = _get_actions_chains_on_all_pages()
actions = _get_actions_on_registered_pages()
# actions_chain and actions are not iterated over multiple times so conversion to list is not technically needed,
# but it prevents future bugs and matches _get_action_loop_components.
actions_chains: list[ActionsChain] = list(model_manager._get_models(ActionsChain))
actions: list[Action] = list(model_manager._get_models(Action))

if not actions_chains:
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from dash import dcc, html

from vizro.actions._action_loop._action_loop_utils import (
_get_actions_chains_on_all_pages,
_get_actions_on_registered_pages,
)
from vizro.managers import model_manager
from vizro.models import Action
from vizro.models._action._actions_chain import ActionsChain


def _get_action_loop_components() -> html.Div:
Expand All @@ -15,8 +14,9 @@ def _get_action_loop_components() -> html.Div:
List of dcc or html components.
"""
actions_chains = _get_actions_chains_on_all_pages()
actions = _get_actions_on_registered_pages()
# actions_chain and actions are iterated over multiple times so must be realized into a list.
actions_chains: list[ActionsChain] = list(model_manager._get_models(ActionsChain))
actions: list[Action] = list(model_manager._get_models(Action))

if not actions_chains:
return html.Div(id="action_loop_components_div")
Expand Down
2 changes: 2 additions & 0 deletions vizro-core/src/vizro/actions/_actions_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def _apply_filter_controls(


def _get_parent_model(_underlying_callable_object_id: str) -> VizroBaseModel:
from vizro.models import VizroBaseModel

for model in cast(Iterable[VizroBaseModel], model_manager._get_models()):
if hasattr(model, "_input_component_id") and model._input_component_id == _underlying_callable_object_id:
return model
Expand Down
7 changes: 3 additions & 4 deletions vizro-core/src/vizro/managers/_model_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,14 @@ def _get_models(
) -> Generator[Model, None, None]:
"""Iterates through all models of type `model_type` (including subclasses).
If `model_type` not given then look at all models. If `page_id` specified then only give models from that page.
If `model_type` not given then look at all models. If `page` specified then only give models from that page.
"""
models = self._get_model_children(page) if page is not None else self.__models.values()

for model in models:
if model_type is None or isinstance(model, model_type):
yield model

# TODO: Consider returning with yield
# TODO NOW: Make brief comments on how in future it should work to use Page (or maybe Dashboard) as key primitive.
def _get_model_children(self, model: Model) -> Generator[Model, None, None]:
from vizro.models import VizroBaseModel

Expand All @@ -91,7 +89,8 @@ def _get_model_children(self, model: Model) -> Generator[Model, None, None]:

# TODO: Add navigation, accordions and other page objects. Won't be needed once have made whole model
# manager work better recursively and have better ways to navigate the hierarchy. In pydantic v2 this would use
# model_fields.
# model_fields. Maybe we'd also use Page (or sometimes Dashboard) as the central model for navigating the
# hierarchy rather than it being so generic.

def _get_model_page(self, model: Model) -> Page: # type: ignore[return]
"""Gets the id of the page containing the model with "model_id"."""
Expand Down
4 changes: 4 additions & 0 deletions vizro-core/tests/unit/vizro/models/_controls/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ def test_categorical_options_specific(self, selector, managers_one_page_two_grap
filter.pre_build()
assert filter.selector.options == ["Africa", "Europe"]

# Use lambda to create test_selector only in the test itself rather than in the parameters, so that it's in the
# model_manager for the test.
@pytest.mark.parametrize(
"filtered_column, selector, filter_function",
[
Expand Down Expand Up @@ -504,6 +506,8 @@ def build(self):
class TestFilterBuild:
"""Tests filter build method."""

# Use lambda to create test_selector only in the test itself rather than in the parameters, so that it's in the
# model_manager for the test.
@pytest.mark.parametrize(
"test_column,test_selector",
[
Expand Down

0 comments on commit cb8a779

Please sign in to comment.