diff --git a/aiidalab_widgets_base/computational_resources.py b/aiidalab_widgets_base/computational_resources.py index 201df5a8d..d9f667040 100644 --- a/aiidalab_widgets_base/computational_resources.py +++ b/aiidalab_widgets_base/computational_resources.py @@ -19,7 +19,6 @@ from humanfriendly import InvalidSize, parse_size from IPython.display import clear_output, display from jinja2 import Environment, meta -from jinja2.nodes import Filter from .databases import NewComputationalResourcesDatabaseWidget from .utils import StatusHTML @@ -594,9 +593,6 @@ def _handle_ssh_password(self): if self._ssh_password.value == "": self.ssh_connection_state = SshConnectionState.waiting_for_input else: - # XXX: After I(unkcpz) move disable the hidden of the password box, user can - # input the password directly and start the password send session immediately. - # It will by-pass the waiting_for_input state and cause the error of "_ssh_connection_process" is not attribute of SshComputerSetup object. self._send_password() def _on_verification_mode_change(self, change): @@ -1220,6 +1216,7 @@ def _observe_code_setup(self, _=None): try: getattr(self, key).label = value except traitlets.TraitError: + # XXX: need to conform with template variable self.message = f"Input plugin {value} is not installed." elif key == "computer": # check if the computer is set by load the label. @@ -1351,7 +1348,7 @@ def __init__(self): # the key is the variable name, and the value is a tuple of (template value and widget). self._template_variables = {} self._help_text = ipw.HTML( - """
Please fill in the template variables below.
""" + """
Please fill the template variables below.
""" ) self._help_text.layout.display = "none" @@ -1390,22 +1387,17 @@ def _templates_changed(self, _=None): def _render(self): """Render the template variables widget.""" metadata = self.templates.get("metadata", {}) + tooptip = metadata.get("tooltip", None) + + if tooptip: + self._help_text.value = f"""
{tooptip}
""" for line_key, line_str in self.templates.items(): env = Environment() parsed_content = env.parse(line_str) - # vars is a set of variables in the template, while filters is a list of all filters in the template - # For example, {{ label | default('daint-mc') }} will have vars = {'label'} and filters = [] - # not all variables have filter. + # vars is a set of variables in the template line_vars = meta.find_undeclared_variables(parsed_content) - filters = list(parsed_content.find_all(Filter)) - - default_value = { - fltr.node.name: fltr.args[0].value - for fltr in filters - if fltr.name == "default" - } # Create a widget for each variable. # The var is the name in a template string @@ -1428,7 +1420,7 @@ def _render(self): if widget_type == "text": w = ipw.Text( description=description, - value=default_value.get(var, ""), + value=var_meta.get("default", ""), # delay notifying the observers until the user stops typing continuous_update=False, layout=LAYOUT, @@ -1438,7 +1430,7 @@ def _render(self): w = ipw.Dropdown( description=description, options=var_meta.get("options", ()), - value=default_value.get(var, None), + value=var_meta.get("default", None), layout=LAYOUT, style=STYLE, ) @@ -1651,34 +1643,32 @@ def _on_quick_setup(self, _=None): """Go through all the setup steps automatically.""" # Use default values for the template variables if not set. # and the same time check if all templates are filled. - # Becareful there are same key in both template_variables_computer and template_variables_code, e.g. label. + # Be careful there are same key in both template_variables_computer and template_variables_code, e.g. label. # So can not combine them by {**a, **b} for w_tmp in [self.template_variables_computer, self.template_variables_code]: + metadata = w_tmp.templates.get("metadata", {}) filled_templates = deepcopy(w_tmp.filled_templates) for k, v in w_tmp.filled_templates.items(): env = Environment() parsed_content = env.parse(v) vs = meta.find_undeclared_variables(parsed_content) - filters = list(parsed_content.find_all(Filter)) # No variables in the template, all filled. if len(vs) == 0: continue - # We only has default filter for now, so when filter number is less than variable number, it means some variables are not filled. - if len(filters) < len(vs): - self.message = f"Please fill all the variables. Missing: {vs}" - return - else: - # Update filled template with default value. - - default_value = { - fltr.node.name: fltr.args[0].value - for fltr in filters - if fltr.name == "default" - } - filled_templates[k] = env.from_string(v).render(**default_value) + default_values = {} + for var in vs: + # check if the default value is exist for this variable. + default = metadata.get(var, {}).get("default", None) + if default is None: + self.message = f"Please fill missing variable: {var}" + return + else: + default_values[var] = default + + filled_templates[k] = env.from_string(v).render(**default_values) # Update the filled template to trigger the trait change. w_tmp.filled_templates = filled_templates diff --git a/aiidalab_widgets_base/databases.py b/aiidalab_widgets_base/databases.py index 1406f30d1..f292e6fa9 100644 --- a/aiidalab_widgets_base/databases.py +++ b/aiidalab_widgets_base/databases.py @@ -386,7 +386,9 @@ class NewComputationalResourcesDatabaseWidget(ipw.VBox): """Extract the setup of a known computer from the AiiDA code registry.""" _default_database_source = ( - "https://aiidateam.github.io/aiida-resource-registry/database.json" + # because of issue https://github.com/orgs/community/discussions/67961 + "https://raw.githubusercontent.com/aiidateam/aiida-resource-registry/gh-pages/database.json" + # "https://aiidateam.github.io/aiida-resource-registry/database.json" ) database_source = tl.Unicode(allow_none=True) diff --git a/tests/test_computational_resources.py b/tests/test_computational_resources.py index 4fb9dcbc3..57b1db6b8 100644 --- a/tests/test_computational_resources.py +++ b/tests/test_computational_resources.py @@ -221,7 +221,7 @@ def test_template_variables_widget(): w = computational_resources.TemplateVariablesWidget() w.templates = { - "label": "{{ label | default('daint-mc') }}", + "label": "{{ label }}", "hostname": "daint.cscs.ch", "description": "Piz Daint supercomputer at CSCS Lugano, Switzerland, multicore partition.", "transport": "core.ssh", @@ -230,9 +230,10 @@ def test_template_variables_widget(): "shebang": "#!/bin/bash", "mpirun_command": "srun -n {tot_num_mpiprocs}", "mpiprocs_per_machine": 36, - "prepend_text": "#SBATCH --partition={{ slurm_partition | default('normal') }}\n#SBATCH --account={{ slurm_account }}\n#SBATCH --constraint=mc\n#SBATCH --cpus-per-task=1\n\nexport OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK\nsource $MODULESHOME/init/bash\nulimit -s unlimited", + "prepend_text": "#SBATCH --partition={{ slurm_partition }}\n#SBATCH --account={{ slurm_account }}\n#SBATCH --constraint=mc\n#SBATCH --cpus-per-task=1\n\nexport OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK\nsource $MODULESHOME/init/bash\nulimit -s unlimited", "metadata": { "slurm_partition": { + "type": "text", "key_display": "Slurm partition", }, }, @@ -253,7 +254,7 @@ def test_template_variables_widget(): sub_widget = value.widget sub_widget.value = "normal-test" - # check the value can be re-input + # check the value can be changed after filled # this test somehow has unexpected behavior, disable it for the moment. # sub_widget.value = "another-test" @@ -273,10 +274,11 @@ def test_template_variables_widget_metadata(): w = computational_resources.TemplateVariablesWidget() w.templates = { - "prepend_text": "#SBATCH --partition={{ slurm_partition | default('normal') }}\n#SBATCH --account={{ slurm_account }}\n#SBATCH --constraint=mc\n#SBATCH --cpus-per-task=1\n\nexport OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK\nsource $MODULESHOME/init/bash\nulimit -s unlimited", + "prepend_text": "#SBATCH --partition={{ slurm_partition }}\n#SBATCH --account={{ slurm_account }}\n#SBATCH --constraint=mc\n#SBATCH --cpus-per-task=1\n\nexport OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK\nsource $MODULESHOME/init/bash\nulimit -s unlimited", "metadata": { "slurm_partition": { "type": "list", + "default": "normal", "options": ["normal", "normal-test", "debug"], "key_display": "Slurm partition", }, @@ -403,7 +405,7 @@ def test_quick_setup_widget(): # the message should be updated. w._on_quick_setup() - assert "Please fill all the variables" in w.message + assert "Please fill missing variable" in w.message # Fill in the computer name and trigger the setup button again, the message should be updated. for (