Skip to content

Commit

Permalink
Elevate common features up to PanelModel and Panel root classes
Browse files Browse the repository at this point in the history
  • Loading branch information
edan-bainglass committed Dec 23, 2024
1 parent 9951c64 commit 2bc1a3f
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 83 deletions.
7 changes: 2 additions & 5 deletions src/aiidalab_qe/app/configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ def _fetch_plugin_calculation_settings(self):
if key not in configuration:
raise ValueError(f"Entry {identifier} is missing the '{key}' key")

panel = configuration["panel"]
model: ConfigurationSettingsModel = configuration["model"]()
self._model.add_model(identifier, model)

Expand Down Expand Up @@ -280,7 +279,5 @@ def toggle_plugin(change, identifier=identifier, model=model, info=info):
)
)

self.settings[identifier] = panel(
identifier=identifier,
model=model,
)
panel: ConfigurationSettingsPanel = configuration["panel"](model=model)
self.settings[identifier] = panel
13 changes: 7 additions & 6 deletions src/aiidalab_qe/app/submission/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
from aiidalab_qe.app.utils import get_entry_items
from aiidalab_qe.common.code import PluginCodes, PwCodeModel
from aiidalab_qe.common.infobox import InAppGuide
from aiidalab_qe.common.panel import PluginResourceSettingsModel, ResourceSettingsPanel
from aiidalab_qe.common.panel import (
PluginResourceSettingsModel,
PluginResourceSettingsPanel,
ResourceSettingsPanel,
)
from aiidalab_qe.common.setup_codes import QESetupWidget
from aiidalab_qe.common.setup_pseudos import PseudosInstallWidget
from aiidalab_widgets_base import WizardAppWidgetStep
Expand Down Expand Up @@ -338,7 +342,6 @@ def _fetch_plugin_resource_settings(self):
if key not in resources:
raise ValueError(f"Entry {identifier} is missing the '{key}' key")

panel = resources["panel"]
model: PluginResourceSettingsModel = resources["model"]()
model.observe(
self._on_plugin_overrides_change,
Expand All @@ -354,10 +357,8 @@ def _fetch_plugin_resource_settings(self):
)
self._model.add_model(identifier, model)

self.settings[identifier] = panel(
identifier=identifier,
model=model,
)
panel: PluginResourceSettingsPanel = resources["panel"](model=model)
self.settings[identifier] = panel

codes[identifier] = dict(model.get_models())

Expand Down
108 changes: 46 additions & 62 deletions src/aiidalab_qe/common/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,39 @@
DEFAULT: dict = DEFAULT_PARAMETERS # type: ignore


class Panel(ipw.VBox):
"""Base class for all the panels.
class PanelModel(Model):
"""Base class for all panel models.
Attributes
----------
`title` : `str`
The title to be shown in the GUI.
`identifier` : `str`
Which plugin this panel belong to.
"""

The base class has a method to return the value of all the widgets in
the panel as a dictionary. The dictionary is used to construct the
input file for the calculation. The class also has a method to load a dictionary to set the value of the widgets in the panel.
title = ""
identifier = ""

title: the title to be shown in the GUI
identifier: which plugin this panel belong to.

"""
PM = t.TypeVar("PM", bound=PanelModel)

title = "Panel"

# TODO remove `identifier` (and `parent`) from signature
# TODO add `model` parameter
# TODO add `identifier` property to route to model.identifier
def __init__(self, parent=None, identifier=None, **kwargs):
"""Initialize the panel.
class Panel(ipw.VBox, t.Generic[PM]):
"""Base class for all panels."""

:param kwargs: keyword arguments to pass to the ipw.VBox constructor.
"""
self.parent = parent
self.identifier = identifier or getattr(self, "identifier", "plugin")
super().__init__(
children=kwargs.pop("children", []),
**kwargs,
)
rendered = False
loading_message = "Loading {identifier} panel"

def __init__(self, model: PM, **kwargs):
loading_message = self.loading_message.format(identifier=model.identifier)
loading_message = loading_message.replace("_", " ")
self.loading_message = LoadingWidget(loading_message)
super().__init__(children=[self.loading_message], **kwargs)
self._model = model

def render(self):
raise NotImplementedError()


class PluginOutline(ipw.HBox):
Expand All @@ -82,15 +87,17 @@ def __init__(self, **kwargs):
)


class SettingsModel(Model):
title = ""
identifier = ""
class SettingsModel(PanelModel):
"""Base model for settings models."""

dependencies: list[str] = []

include = tl.Bool(False)
loaded_from_process = tl.Bool(False)

_defaults = {}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._defaults = {}

def update(self):
"""Updates the model."""
Expand All @@ -112,25 +119,15 @@ def reset(self):
SM = t.TypeVar("SM", bound=SettingsModel)


class SettingsPanel(Panel, t.Generic[SM]):
def __init__(self, model: SM, **kwargs):
self.loading_message = LoadingWidget(f"Loading {model.identifier} settings")
class SettingsPanel(Panel[SM]):
"""Base model for settings panels."""

super().__init__(
children=[self.loading_message],
**kwargs,
)

self._model = model

self.rendered = False
self.updated = False
updated = False

def __init__(self, model: SM, **kwargs):
super().__init__(model=model, **kwargs)
self.links = []

def render(self):
raise NotImplementedError()


class ConfigurationSettingsModel(SettingsModel, Confirmable):
"""Base model for configuration settings models."""
Expand All @@ -149,7 +146,7 @@ def update(self, specific=""):
CSM = t.TypeVar("CSM", bound=ConfigurationSettingsModel)


class ConfigurationSettingsPanel(SettingsPanel[CSM], t.Generic[CSM]):
class ConfigurationSettingsPanel(SettingsPanel[CSM]):
"""Base class for configuration settings panels."""

def refresh(self, specific=""):
Expand Down Expand Up @@ -203,8 +200,6 @@ def _reset(self):
class ResourceSettingsModel(SettingsModel, HasModels[CodeModel]):
"""Base model for resource setting models."""

dependencies = []

global_codes = tl.Dict(
key_trait=tl.Unicode(),
value_trait=tl.Dict(),
Expand Down Expand Up @@ -256,12 +251,11 @@ def _check_submission_blockers(self):
RSM = t.TypeVar("RSM", bound=ResourceSettingsModel)


class ResourceSettingsPanel(SettingsPanel[RSM], t.Generic[RSM]):
class ResourceSettingsPanel(SettingsPanel[RSM]):
"""Base class for resource setting panels."""

def __init__(self, model, **kwargs):
super().__init__(model, **kwargs)

self.code_widgets = {}

def _on_code_resource_change(self, _):
Expand Down Expand Up @@ -400,7 +394,7 @@ def _link_model(self, model: CodeModel):
PRSM = t.TypeVar("PRSM", bound=PluginResourceSettingsModel)


class PluginResourceSettingsPanel(ResourceSettingsPanel[PRSM], t.Generic[PRSM]):
class PluginResourceSettingsPanel(ResourceSettingsPanel[PRSM]):
"""Base class for plugin resource setting panels."""

def __init__(self, model, **kwargs):
Expand Down Expand Up @@ -506,10 +500,7 @@ def _link_override_to_widget_disable(self, code_model, code_widget):
)


class ResultsModel(Model, HasProcess):
title = "Model"
identifier = "model"

class ResultsModel(PanelModel, HasProcess):
process_status_notification = tl.Unicode("")

_this_process_label = ""
Expand Down Expand Up @@ -593,24 +584,20 @@ def _fetch_child_process_node(self, child="this") -> orm.ProcessNode | None:
RM = t.TypeVar("RM", bound=ResultsModel)


class ResultsPanel(Panel, t.Generic[RM]):
class ResultsPanel(Panel[RM]):
"""Base class for all the result panels.
The base class has a method to load the result of the calculation.
And a show method to display it in the panel.
It has a update method to update the result in the panel.
"""

# To specify which plugins (outputs) are needed
# for this result panel.
workchain_labels = []
has_controls = False
loading_message = "Loading {identifier} results"

def __init__(self, model: RM, **kwargs):
self.loading_message = LoadingWidget(f"Loading {model.title.lower()} results")
super().__init__(model=model, **kwargs)

super().__init__(**kwargs)

self._model = model
self._model.observe(
self._on_process_change,
"process_uuid",
Expand All @@ -620,9 +607,6 @@ def __init__(self, model: RM, **kwargs):
"monitor_counter",
)

self.rendered = False
self.has_controls = False

self.links = []

def render(self):
Expand Down
2 changes: 0 additions & 2 deletions src/aiidalab_qe/plugins/bands/result/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@


class BandsResultsPanel(ResultsPanel[BandsResultsModel]):
workchain_labels = ["bands"]

def _render(self):
bands_node = self._model.get_bands_node()
model = BandsPdosModel()
Expand Down
2 changes: 0 additions & 2 deletions src/aiidalab_qe/plugins/electronic_structure/result/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@


class ElectronicStructureResultsPanel(ResultsPanel[ElectronicStructureResultsModel]):
workchain_labels = ["bands", "pdos"]

def _render(self):
bands_node = self._model.get_bands_node()
pdos_node = self._model.get_pdos_node()
Expand Down
2 changes: 0 additions & 2 deletions src/aiidalab_qe/plugins/pdos/result/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@


class PdosResultsPanel(ResultsPanel[PdosResultsModel]):
workchain_labels = ["pdos"]

def _render(self):
pdos_node = self._model.get_pdos_node()
model = BandsPdosModel()
Expand Down
2 changes: 0 additions & 2 deletions src/aiidalab_qe/plugins/xas/result/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@


class XasResultsPanel(ResultsPanel[XasResultsModel]):
workchain_labels = ["xas"]

def _render(self):
variable_broad_select = ipw.Checkbox(
description="Use variable energy broadening.",
Expand Down
2 changes: 0 additions & 2 deletions src/aiidalab_qe/plugins/xps/result/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@


class XpsResultsPanel(ResultsPanel[XpsResultsModel]):
workchain_labels = ["xps"]

experimental_data = None # Placeholder for experimental data

def _on_file_upload(self, change):
Expand Down

0 comments on commit 2bc1a3f

Please sign in to comment.