Skip to content

Commit c5f2c3c

Browse files
Merge pull request #360 from CodeForPhilly/dash_callbacks_refactor
[Dash] Initial rework of how we use Dash callbacks
2 parents 526c95a + 1b00503 commit c5f2c3c

File tree

18 files changed

+473
-413
lines changed

18 files changed

+473
-413
lines changed

src/__init__.py

Whitespace-only changes.
Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
1-
"""Combines all components
2-
3-
The `sidebar` component combines all the inputs while other components potentially
4-
have callbacks.
5-
6-
To add or remove components, adjust the `setup`.
7-
If callbacks are present, also adjust `CALLBACK_INPUTS`, `CALLBACK_OUTPUTS` and
8-
`callback_body`.
1+
"""Builds the root component
92
"""
103
from collections import OrderedDict
114

12-
import dash_html_components as dhc
13-
from chime_dash.app.components.base import Component, HTMLComponentError
5+
from dash_bootstrap_components import Container, Row
146
from dash_bootstrap_components.themes import BOOTSTRAP
7+
from dash_html_components import Div
8+
9+
from chime_dash.app.components.base import Component
1510
from chime_dash.app.components.navbar import Navbar
16-
from chime_dash.app.components.container import Container
11+
from chime_dash.app.pages.index import Index
12+
from chime_dash.app.pages.sidebar import Sidebar
13+
14+
15+
def singleton(class_):
16+
instances = {}
17+
18+
def get_instance(*args, **kwargs):
19+
if class_ not in instances:
20+
instances[class_] = class_(*args, **kwargs)
21+
return instances[class_]
22+
return get_instance
1723

1824

25+
@singleton
1926
class Body(Component):
2027
"""
2128
"""
22-
2329
external_stylesheets = [
2430
BOOTSTRAP,
2531
]
@@ -30,29 +36,21 @@ def __init__(self, language, defaults):
3036
super().__init__(language, defaults)
3137
self.components = OrderedDict(
3238
navbar=Navbar(language, defaults),
33-
container=Container(language, defaults),
39+
sidebar=Sidebar(language, defaults),
40+
# todo subscribe to changes to URL and select page appropriately
41+
index=Index(language, defaults),
3442
)
35-
self.callback_outputs = []
36-
self.callback_inputs = OrderedDict()
37-
for component in self.components.values():
38-
self.callback_outputs += component.callback_outputs
39-
self.callback_inputs.update(component.callback_inputs)
4043

4144
def get_html(self):
4245
"""Glues individual setup components together
4346
"""
44-
return dhc.Div(self.components["navbar"].html + self.components["container"].html)
45-
46-
def callback(self, *args, **kwargs):
47-
"""
48-
"""
49-
kwargs = dict(zip(self.callback_inputs, args))
50-
51-
callback_returns = []
52-
for component in self.components.values():
53-
try:
54-
callback_returns += component.callback(**kwargs)
55-
except Exception as error:
56-
raise HTMLComponentError(component, error)
57-
58-
return callback_returns
47+
return Div(children=
48+
self.components["navbar"].html
49+
+ [Container(
50+
children=Row(self.components["sidebar"].html + [Div(
51+
id="page-wrapper",
52+
children=self.components["index"].html
53+
)]),
54+
fluid=True,
55+
className="mt-5",
56+
)])

src/chime_dash/app/components/base.py

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,72 +8,43 @@
88

99
from abc import ABC
1010

11-
from dash.dependencies import Output, Input
11+
from dash import Dash
1212
from dash.development.base_component import ComponentMeta
1313
from dash_html_components import Div
1414

1515
from penn_chime.parameters import Parameters
1616
from penn_chime.settings import DEFAULTS
1717

18-
from chime_dash.app.utils.templates import read_localization_yml
19-
from chime_dash.app.utils.templates import read_localization_markdown
18+
from chime_dash.app.utils.templates import read_localization_yml, read_localization_markdown
19+
from chime_dash.app.utils.callbacks import ChimeCallback, register_callbacks
2020

2121

2222
class Component(ABC):
23-
"""Base component for rendering dash html objects and callbacks
23+
"""Base component for rendering dash html objects and registering callbacks
2424
2525
Attributes:
2626
localization_file: File name for rendering localized strings
27-
callback_outputs: List of callback outputs needed for rendering html.
28-
Must be used together with `callback()` which provides callback data.
29-
callback_inputs: Ordered dictionary for element id's and input types.
30-
Must be used if component contains widgets.
3127
external_stylesheets: External stylesheets. Just a storage container.
3228
external_scripts: External scripts. Just a storage container.
3329
"""
3430

3531
localization_file: str = None
36-
37-
callback_outputs: List[Output] = [] # must be same length as callback return
38-
callback_inputs: Dict[str, Input] = {} # Must be ordered!
39-
4032
external_stylesheets: List[str] = []
4133
external_scripts: List[str] = []
4234

43-
def __init__(self, language: str = "en", defaults: Parameters = DEFAULTS):
35+
def __init__(
36+
self,
37+
language: str = "en",
38+
defaults: Parameters = DEFAULTS,
39+
callbacks: List[ChimeCallback] = None
40+
):
4441
"""Initializes the component
4542
"""
4643
self.language = language
4744
self.defaults = defaults
4845
self._content = None
4946
self._html = None
50-
51-
def callback( # pylint: disable=W0613, R0201
52-
self, *args, **kwargs
53-
) -> List[Dict[str, Any]]:
54-
"""Function which is called whenever a web-input element is triggered.
55-
56-
Overwrite this function for custom actions.
57-
To render arguments, add (or modify)
58-
```
59-
@app.callback(component.callback_outputs, component.callback_inputs.values()):
60-
def callback_body(*args):
61-
return component.callback(*args)
62-
```
63-
Args come from the specified forms in order as `callback_outputs`.
64-
65-
Arguments:
66-
args: Form parameters specified in `callback_outputs` order
67-
kwargs: Additional arguments supplied by the user when modifying the
68-
decorated `callback_body`.
69-
70-
Result should be the data (usually dictionaries) passed to the Dash element
71-
of given id. The number of arguments and order must match the elements in
72-
`callback_outputs`.
73-
74-
See also https://dash.plotly.com/getting-started-part-2
75-
"""
76-
return []
47+
register_callbacks(callbacks)
7748

7849
def get_html(self) -> List[ComponentMeta]: # pylint: disable=R0201
7950
"""Function which is called to render html elements.

src/chime_dash/app/components/container.py

Lines changed: 0 additions & 56 deletions
This file was deleted.

src/chime_dash/app/components/content.py

Lines changed: 0 additions & 59 deletions
This file was deleted.

src/chime_dash/app/components/header.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
"""
44
from typing import List
55

6+
from chime_dash.app.components.base import Component
67
from dash.development.base_component import ComponentMeta
7-
from dash_html_components import Div, H1
88
from dash_core_components import Markdown
9-
10-
from chime_dash.app.components.base import Component
9+
from dash_html_components import Div, H1
1110

1211

1312
class Header(Component):

0 commit comments

Comments
 (0)