From 735326498418c58697f8dc05457263ef9528d2c0 Mon Sep 17 00:00:00 2001 From: Edan Bainglass <45081142+edan-bainglass@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:23:11 +0100 Subject: [PATCH] Fix resource setup widget bugs (#661) - Add additional guards for missing code setup input - Disable quick setup button if missing any requisites - Apply uniqueness to missing template variables warning - Make `ResourceSetupBaseWidget` "public" - Fix code full label uniqueness check Note that the fix in the query that looks for existing codes is a hack due to a potential bug in aiida-core. See https://github.com/aiidateam/aiida-core/issues/6687. --- .../computational_resources.py | 28 ++++++++++++++++--- aiidalab_widgets_base/databases.py | 10 +++++++ aiidalab_widgets_base/utils/__init__.py | 2 +- tests/test_computational_resources.py | 12 ++++---- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/aiidalab_widgets_base/computational_resources.py b/aiidalab_widgets_base/computational_resources.py index 393a61a19..f1dd6e00e 100644 --- a/aiidalab_widgets_base/computational_resources.py +++ b/aiidalab_widgets_base/computational_resources.py @@ -119,7 +119,7 @@ def __init__( children.append(self._setup_new_code_output) # Computer/code setup - self.resource_setup = _ResourceSetupBaseWidget( + self.resource_setup = ResourceSetupBaseWidget( default_calc_job_plugin=self.default_calc_job_plugin, enable_quick_setup=enable_quick_setup, enable_detailed_setup=enable_detailed_setup, @@ -1193,6 +1193,13 @@ def on_setup_code(self, _=None): with self.setup_code_out: clear_output() + if not self.label.value: + self.message = wrap_message( + "Please provide a code label.", + MessageLevel.WARNING, + ) + return False + if not self.computer.value: self.message = wrap_message( "Please select an existing computer.", @@ -1229,7 +1236,7 @@ def on_setup_code(self, _=None): qb = orm.QueryBuilder() qb.append(orm.Computer, filters={"uuid": computer.uuid}, tag="computer") qb.append( - orm.AbstractCode, + orm.Code, with_computer="computer", filters={"label": kwargs["label"]}, ) @@ -1612,7 +1619,7 @@ def _on_template_variable_filled(self, _): self.fill() -class _ResourceSetupBaseWidget(ipw.VBox): +class ResourceSetupBaseWidget(ipw.VBox): """The widget that allows to setup a computer and code. This is the building block of the `ComputationalResourcesDatabaseWidget` which will be directly used by the user. @@ -1659,6 +1666,11 @@ def __init__( default_calc_job_plugin=default_calc_job_plugin, show_reset_button=False, ) + ipw.dlink( + (self.comp_resources_database, "configured"), + (self.quick_setup_button, "disabled"), + lambda configured: not configured, + ) # All templates self.template_computer_setup = TemplateVariablesWidget() @@ -1877,6 +1889,14 @@ def _on_quick_setup(self, _=None): ) return + # Raise error if the code is not selected. + if not self.comp_resources_database.code_selector.value: + self.message = wrap_message( + "Please select a code from the database.", + MessageLevel.ERROR, + ) + return + # Check if all the template variables are filled. # If not raise a warning and return (skip the setup). if ( @@ -1884,7 +1904,7 @@ def _on_quick_setup(self, _=None): + self.template_computer_configure.unfilled_variables + self.template_code.unfilled_variables ): - var_warn_message = ", ".join([f"{v}" for v in unfilled_variables]) + var_warn_message = ", ".join({f"{v}" for v in unfilled_variables}) self.message = wrap_message( f"Please fill the template variables: {var_warn_message}", MessageLevel.WARNING, diff --git a/aiidalab_widgets_base/databases.py b/aiidalab_widgets_base/databases.py index e3cf14bfd..48f1b9021 100644 --- a/aiidalab_widgets_base/databases.py +++ b/aiidalab_widgets_base/databases.py @@ -234,6 +234,8 @@ class ComputationalResourcesDatabaseWidget(ipw.VBox): computer_configure = tl.Dict() code_setup = tl.Dict() + configured = tl.Bool(False) + STYLE = {"description_width": "180px"} LAYOUT = {"width": "400px"} @@ -413,6 +415,8 @@ def _computer_changed(self, change=None): self.computer_setup = computer_setup self.computer_configure = computer_configure + self._set_configured() + def _code_changed(self, change=None): """Update code settings.""" if change["new"] is None: @@ -430,3 +434,9 @@ def _code_changed(self, change=None): .get("codes", {}) .get(selected_code, {}) ) + + self._set_configured() + + def _set_configured(self): + """Update state of the widget.""" + self.configured = all((self.computer_setup, self.code_setup)) diff --git a/aiidalab_widgets_base/utils/__init__.py b/aiidalab_widgets_base/utils/__init__.py index 8a6f53304..bea0e08f0 100644 --- a/aiidalab_widgets_base/utils/__init__.py +++ b/aiidalab_widgets_base/utils/__init__.py @@ -213,7 +213,7 @@ def wrap_message(message, level=MessageLevel.INFO): # The message is wrapped into a div with the class "alert" and the icon of the given level return f"""