Improve the class hierachy, and add an extra ExpertApp test.
This commit is contained in:
parent
ce4e886e54
commit
ffbe9baba6
2 changed files with 51 additions and 11 deletions
|
|
@ -33,6 +33,28 @@ ScenarioType = typing.Tuple[str, state.DataclassState]
|
|||
|
||||
|
||||
class View:
|
||||
"""
|
||||
A thing which exposes a ``.widget`` attribute which is a view on some
|
||||
data. This view is essentially a complex combination of widgets, along with
|
||||
some event handling capabilities, which may or may not be sent back up to
|
||||
the underlying controller.
|
||||
|
||||
We strive hard to keep "Model" data out of the View (and try to avoid
|
||||
storing it at all on the View itself), instead relying on being able
|
||||
to notify, and receive notifications, of important events from the Controller.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Controller:
|
||||
"""
|
||||
The singleton thing which is the top-level Application.
|
||||
|
||||
It is responsible for owning the Model data and the Views, and
|
||||
orchestrating event messages to each if the Model/View change.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -98,8 +120,13 @@ class ExposureModelResult(View):
|
|||
lines.append(f'Probability of infection: {np.round(P, 0)}%')
|
||||
|
||||
lines.append(f'Number of exposed: {model.exposed.number}')
|
||||
R0 = np.round(model.reproduction_rate(), 1)
|
||||
lines.append(f'Number of expected new cases (R0): {R0}')
|
||||
|
||||
new_cases = np.round(model.expected_new_cases(), 1)
|
||||
lines.append(f'Number of expected new cases: {new_cases}')
|
||||
|
||||
R0 = np.round(model.reproduction_number(), 1)
|
||||
lines.append(f'Reproduction number (R0): {R0}')
|
||||
|
||||
self.html_output.value = '<br>\n'.join(lines)
|
||||
|
||||
|
||||
|
|
@ -435,7 +462,7 @@ class CARAStateBuilder(state.StateBuilder):
|
|||
return s
|
||||
|
||||
|
||||
class ExpertApplication:
|
||||
class ExpertApplication(Controller):
|
||||
def __init__(self):
|
||||
self._debug_output = widgets.Output()
|
||||
|
||||
|
|
@ -479,7 +506,7 @@ class ExpertApplication:
|
|||
self._model_scenarios.append((name, model))
|
||||
self._active_scenario = len(self._model_scenarios) - 1
|
||||
model.dcs_observe(self.notify_model_values_changed)
|
||||
self.notify_model_scenario_changed()
|
||||
self.notify_scenarios_changed()
|
||||
|
||||
def _find_model_id(self, model_id):
|
||||
for index, (name, model) in enumerate(list(self._model_scenarios)):
|
||||
|
|
@ -491,22 +518,22 @@ class ExpertApplication:
|
|||
def rename_scenario(self, model_id, new_name):
|
||||
index, _, model = self._find_model_id(model_id)
|
||||
self._model_scenarios[index] = (new_name, model)
|
||||
self.notify_model_scenario_changed()
|
||||
self.notify_scenarios_changed()
|
||||
|
||||
def remove_scenario(self, model_id):
|
||||
index, _, model = self._find_model_id(model_id)
|
||||
self._model_scenarios.pop(index)
|
||||
if self._active_scenario >= index:
|
||||
self._active_scenario = max(self._active_scenario - 1, 0)
|
||||
self.notify_model_scenario_changed()
|
||||
self.notify_scenarios_changed()
|
||||
|
||||
def set_active_scenario(self, model_id):
|
||||
index, _, model = self._find_model_id(model_id)
|
||||
self._active_scenario = index
|
||||
self.notify_model_scenario_changed()
|
||||
self.notify_scenarios_changed()
|
||||
self.notify_model_values_changed()
|
||||
|
||||
def notify_model_scenario_changed(self):
|
||||
def notify_scenarios_changed(self):
|
||||
"""
|
||||
Occurs when the set of scenarios has been modified, but not if the values of the scenario has changed.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
import pytest
|
||||
|
||||
import cara.apps
|
||||
|
||||
|
||||
def test_app():
|
||||
@pytest.fixture
|
||||
def expert_app():
|
||||
return cara.apps.ExpertApplication()
|
||||
|
||||
|
||||
def test_app(expert_app):
|
||||
# To start with, let's just test that the application runs. We don't try to
|
||||
# do anything fancy to verify how it looks etc., we leave that for manual
|
||||
# testing.
|
||||
expert_app = cara.apps.ExpertApplication()
|
||||
assert expert_app.multi_model_view.scenario_names[0] == "Scenario 1"
|
||||
assert expert_app._model_scenarios[0][0] == "Scenario 1"
|
||||
|
||||
|
||||
def test_new_scenario_changes_tab(expert_app):
|
||||
# Adding a new scenario should change the tab index of the multi-model view.
|
||||
assert expert_app.multi_model_view.widget.selected_index == 0
|
||||
expert_app.add_scenario("Another scenario")
|
||||
assert expert_app.multi_model_view.widget.selected_index == 1
|
||||
|
|
|
|||
Loading…
Reference in a new issue