From 0c8c48a89cae1647cfed1bff4a21bec55155e340 Mon Sep 17 00:00:00 2001 From: Marnik Bercx Date: Fri, 28 Jan 2022 13:20:16 +0100 Subject: [PATCH] apply reviewer suggestions --- .../calculations/namelists.py | 2 ++ .../calculations/pw2gw.py | 2 -- src/aiida_quantumespresso/parsers/base.py | 20 ++++++++++++------- src/aiida_quantumespresso/parsers/dos.py | 2 +- src/aiida_quantumespresso/parsers/matdyn.py | 2 +- src/aiida_quantumespresso/parsers/neb.py | 8 ++++---- src/aiida_quantumespresso/parsers/ph.py | 8 +++++--- src/aiida_quantumespresso/parsers/pp.py | 2 +- src/aiida_quantumespresso/parsers/projwfc.py | 2 +- src/aiida_quantumespresso/parsers/pw2gw.py | 2 +- .../parsers/pw2wannier90.py | 2 +- src/aiida_quantumespresso/parsers/q2r.py | 2 +- tests/parsers/test_dos/test_dos_default.yml | 2 +- .../test_matdyn/test_matdyn_default.yml | 2 +- tests/parsers/test_neb.py | 4 ++-- tests/parsers/test_neb/test_neb_default.yml | 2 +- .../test_ph/test_ph_default_default_.yml | 2 +- .../parsers/test_ph/test_ph_not_converged.yml | 2 +- .../test_ph/test_ph_out_of_walltime.yml | 2 +- .../test_pw2gw/test_pw2gw_default_data.yml | 2 +- .../test_pw2wannier90_default.yml | 2 +- 21 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/aiida_quantumespresso/calculations/namelists.py b/src/aiida_quantumespresso/calculations/namelists.py index c6ac4e286..b3961ed56 100644 --- a/src/aiida_quantumespresso/calculations/namelists.py +++ b/src/aiida_quantumespresso/calculations/namelists.py @@ -62,6 +62,8 @@ def define(cls, spec): message='The retrieved folder did not contain the required stdout output file.') spec.exit_code(310, 'ERROR_OUTPUT_STDOUT_READ', message='The stdout output file could not be read.') + spec.exit_code(311, 'ERROR_OUTPUT_STDOUT_PARSE', + message='The stdout output file could not be parsed.') spec.exit_code(312, 'ERROR_OUTPUT_STDOUT_INCOMPLETE', message='The stdout output file was incomplete probably because the calculation got interrupted.') # yapf: enable diff --git a/src/aiida_quantumespresso/calculations/pw2gw.py b/src/aiida_quantumespresso/calculations/pw2gw.py index b8d21f3b7..fe9cc03cf 100644 --- a/src/aiida_quantumespresso/calculations/pw2gw.py +++ b/src/aiida_quantumespresso/calculations/pw2gw.py @@ -40,8 +40,6 @@ def define(cls, spec): spec.exit_code(305, 'ERROR_OUTPUT_FILES', message='The eps*.dat output files could not be read or parsed.') - spec.exit_code(311, 'ERROR_OUTPUT_STDOUT_PARSE', - message='The stdout output file could not be parsed.') spec.exit_code(330, 'ERROR_OUTPUT_FILES_INVALID_FORMAT', message='The eps*.dat output files do not have the expected shape (N, 2).') spec.exit_code(331, 'ERROR_OUTPUT_FILES_ENERGY_MISMATCH', diff --git a/src/aiida_quantumespresso/parsers/base.py b/src/aiida_quantumespresso/parsers/base.py index bde64dbab..d4e84e124 100644 --- a/src/aiida_quantumespresso/parsers/base.py +++ b/src/aiida_quantumespresso/parsers/base.py @@ -3,6 +3,7 @@ All `Parser` implementations in `aiida-quantumespresso` must use this base class, not `aiida.parsers.Parser`. """ +import abc import re import typing @@ -15,7 +16,7 @@ __all__ = ('BaseParser',) -class BaseParser(Parser): # pylint: disable=abstract-method +class BaseParser(Parser, metaclass=abc.ABCMeta): """Custom ``Parser`` class for ``aiida-quantumespresso`` parser implementations.""" class_error_map = {} @@ -38,12 +39,12 @@ def get_error_map(cls): @classmethod def get_warning_map(cls): - """The full error map of the parser class.""" + """The full warning map of the parser class.""" warning_map = cls.base_warning_map.copy() warning_map.update(cls.class_warning_map) return warning_map - def _retrieve_parse_stdout(self, **kwargs) -> typing.Tuple[str, dict, AttributeDict]: + def _parse_stdout_from_retrieved(self, **kwargs) -> typing.Tuple[str, dict, AttributeDict]: """Retrieve and parse the ``stdout`` content of a Quantum ESPRESSO calculation. :returns: size 3 tuple with the stdout content, parsed data and log messages @@ -63,10 +64,15 @@ def _retrieve_parse_stdout(self, **kwargs) -> typing.Tuple[str, dict, AttributeD logs.error.append('ERROR_OUTPUT_STDOUT_READ') return {}, logs - parsed_data, stdout_logs = self.parse_stdout(stdout, **kwargs) + try: + parsed_data, stdout_logs = self.parse_stdout(stdout, **kwargs) + except Exception as exception: + logs.error.append('ERROR_OUTPUT_STDOUT_PARSE') + logs.error.append(exception) + return {}, logs - for log_type, log_items in stdout_logs.items(): - logs[log_type].extend(log_items) + for log_level, log_items in stdout_logs.items(): + logs[log_level].extend(log_items) return parsed_data, logs @@ -85,7 +91,7 @@ def parse_stdout(cls, stdout: str) -> typing.Tuple[dict, AttributeDict]: if not re.search(r'JOB DONE', stdout): logs.error.append('ERROR_OUTPUT_STDOUT_INCOMPLETE') - code_match = re.search(r'Program\s(?P[A-Z|\_|\d]+)\sv\.(?P[\d\.|a-z|A-Z]+)\s', stdout) + code_match = re.search(r'Program\s(?P[A-Z|\_|\d]+)\s(?Pv\.[\d\.|a-z|A-Z]+)\s', stdout) if code_match: diff --git a/src/aiida_quantumespresso/parsers/dos.py b/src/aiida_quantumespresso/parsers/dos.py index 09cefabb4..211a36acb 100644 --- a/src/aiida_quantumespresso/parsers/dos.py +++ b/src/aiida_quantumespresso/parsers/dos.py @@ -18,7 +18,7 @@ class DosParser(BaseParser): def parse(self, **kwargs): """Parse the retrieved files of a ``DosCalculation`` into output nodes.""" - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) self.out('output_parameters', Dict(dict=parsed_stdout)) diff --git a/src/aiida_quantumespresso/parsers/matdyn.py b/src/aiida_quantumespresso/parsers/matdyn.py index 07857efeb..120d0b35f 100644 --- a/src/aiida_quantumespresso/parsers/matdyn.py +++ b/src/aiida_quantumespresso/parsers/matdyn.py @@ -13,7 +13,7 @@ class MatdynParser(BaseParser): def parse(self, **kwargs): """Parse the retrieved files from a ``MatdynCalculation`` into output nodes.""" - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) self.out('output_parameters', orm.Dict(parsed_stdout)) diff --git a/src/aiida_quantumespresso/parsers/neb.py b/src/aiida_quantumespresso/parsers/neb.py index f91987450..4e294096f 100644 --- a/src/aiida_quantumespresso/parsers/neb.py +++ b/src/aiida_quantumespresso/parsers/neb.py @@ -61,7 +61,7 @@ def parse(self, **kwargs): pw_input_dict = self.node.inputs.pw.parameters.get_dict() # First parse the Neb output - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) iteration_data = parsed_stdout.pop('iteration_data') @@ -147,9 +147,9 @@ def parse(self, **kwargs): cells.append(structure_data.cell) # Add also PW warnings and errors to the neb output data, avoiding repetitions. - for log_type in ['warning', 'error']: - for message in logs_stdout[log_type]: - formatted_message = f'{log_type}: {message}' + for log_level in ['warning', 'error']: + for message in logs_stdout[log_level]: + formatted_message = f'{log_level}: {message}' if formatted_message not in parsed_stdout['warnings']: parsed_stdout['warnings'].append(formatted_message) diff --git a/src/aiida_quantumespresso/parsers/ph.py b/src/aiida_quantumespresso/parsers/ph.py index 2625f396b..3e4d758c5 100644 --- a/src/aiida_quantumespresso/parsers/ph.py +++ b/src/aiida_quantumespresso/parsers/ph.py @@ -43,7 +43,9 @@ def parse(self, **kwargs): dynmat_files.append(self.retrieved.base.repository.get_object_content(os.path.join(dynmat_folder, filename))) - parsed_stdout, logs_stdout = self._retrieve_parse_stdout(tensor_file=tensor_file, dynmat_files=dynmat_files) + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved( + tensor_file=tensor_file, dynmat_files=dynmat_files + ) self._emit_logs(logs_stdout) self.out('output_parameters', orm.Dict(dict=parsed_stdout)) @@ -71,7 +73,7 @@ def parse_stdout(cls, stdout: str, tensor_file: str, dynmat_files: list) -> tupl parsed_data, logs = parse_stdout(stdout, tensor_file, dynmat_files) parsed_data.update(parsed_base) - for log_type, log_items in logs_base.items(): - logs[log_type].extend(log_items) + for log_level, log_items in logs_base.items(): + logs[log_level].extend(log_items) return parsed_data, logs diff --git a/src/aiida_quantumespresso/parsers/pp.py b/src/aiida_quantumespresso/parsers/pp.py index 54ccca9c5..e62cd3a56 100644 --- a/src/aiida_quantumespresso/parsers/pp.py +++ b/src/aiida_quantumespresso/parsers/pp.py @@ -49,7 +49,7 @@ class PpParser(BaseParser): def parse(self, **kwargs): """Parse the retrieved files of a ``PpCalculation`` into output nodes.""" - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) self.out('output_parameters', orm.Dict(dict=parsed_stdout)) diff --git a/src/aiida_quantumespresso/parsers/projwfc.py b/src/aiida_quantumespresso/parsers/projwfc.py index 47b4e59f5..8e02aa6e1 100644 --- a/src/aiida_quantumespresso/parsers/projwfc.py +++ b/src/aiida_quantumespresso/parsers/projwfc.py @@ -286,7 +286,7 @@ def parse(self, **kwargs): # we create a dictionary the progressively accumulates more info out_info_dict = {} - parsed_stdout, logs_stdout = self._retrieve_parse_stdout(out_info_dict=out_info_dict) + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved(out_info_dict=out_info_dict) self._emit_logs(logs_stdout) self.out('output_parameters', Dict(dict=parsed_stdout)) diff --git a/src/aiida_quantumespresso/parsers/pw2gw.py b/src/aiida_quantumespresso/parsers/pw2gw.py index c726ffa9e..c75730aa3 100644 --- a/src/aiida_quantumespresso/parsers/pw2gw.py +++ b/src/aiida_quantumespresso/parsers/pw2gw.py @@ -24,7 +24,7 @@ def parse(self, **kwargs): permanently in the repository. The second required node is a filepath under the key ``retrieved_temporary_files`` which should contain the temporary retrieved files. """ - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) self.out('output_parameters', Dict(dict=parsed_stdout)) diff --git a/src/aiida_quantumespresso/parsers/pw2wannier90.py b/src/aiida_quantumespresso/parsers/pw2wannier90.py index eaeecd0b6..8f3f59677 100644 --- a/src/aiida_quantumespresso/parsers/pw2wannier90.py +++ b/src/aiida_quantumespresso/parsers/pw2wannier90.py @@ -16,7 +16,7 @@ def parse(self, **kwargs): Two nodes that are expected are the default 'retrieved' ``FolderData`` node which will store the retrieved files permanently in the repository. """ - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) self.out('output_parameters', Dict(parsed_stdout)) diff --git a/src/aiida_quantumespresso/parsers/q2r.py b/src/aiida_quantumespresso/parsers/q2r.py index cd238f9ac..9d4d32ed3 100644 --- a/src/aiida_quantumespresso/parsers/q2r.py +++ b/src/aiida_quantumespresso/parsers/q2r.py @@ -12,7 +12,7 @@ class Q2rParser(BaseParser): def parse(self, **kwargs): """Parse the retrieved files of a ``Q2rCalculation`` into output nodes.""" - parsed_stdout, logs_stdout = self._retrieve_parse_stdout() + parsed_stdout, logs_stdout = self._parse_stdout_from_retrieved() self._emit_logs(logs_stdout) self.out('output_parameters', Dict(parsed_stdout)) diff --git a/tests/parsers/test_dos/test_dos_default.yml b/tests/parsers/test_dos/test_dos_default.yml index 587ce2337..fa7576bec 100644 --- a/tests/parsers/test_dos/test_dos_default.yml +++ b/tests/parsers/test_dos/test_dos_default.yml @@ -10,6 +10,6 @@ dos: - states/eV - states/eV parameters: - code_version: 6.4.1 + code_version: v.6.4.1 wall_time: 0.41s wall_time_seconds: 0.41 diff --git a/tests/parsers/test_matdyn/test_matdyn_default.yml b/tests/parsers/test_matdyn/test_matdyn_default.yml index 41ed8d9aa..2ac0a6bcb 100644 --- a/tests/parsers/test_matdyn/test_matdyn_default.yml +++ b/tests/parsers/test_matdyn/test_matdyn_default.yml @@ -1,5 +1,5 @@ output_parameters: - code_version: '6.1' + code_version: v.6.1 wall_time: 0.00s wall_time_seconds: 0.0 output_phonon_bands: diff --git a/tests/parsers/test_neb.py b/tests/parsers/test_neb.py index 320dce0a3..4053a4c55 100644 --- a/tests/parsers/test_neb.py +++ b/tests/parsers/test_neb.py @@ -57,7 +57,7 @@ def test_neb_default(fixture_localhost, generate_calc_job_node, generate_parser, assert calcfunction.is_finished, calcfunction.exception assert calcfunction.is_finished_ok, calcfunction.exit_message - assert not orm.Log.collection.get_logs_for(node) + assert not [log for log in orm.Log.objects.get_logs_for(node) if log.levelname == 'ERROR'] assert 'output_parameters' in results assert 'output_mep' in results assert 'output_trajectory' in results @@ -89,7 +89,7 @@ def test_neb_all_iterations( assert calcfunction.is_finished, calcfunction.exception assert calcfunction.is_finished_ok, calcfunction.exit_message - assert not orm.Log.collection.get_logs_for(node) + assert not [log for log in orm.Log.objects.get_logs_for(node) if log.levelname == 'ERROR'] assert 'output_parameters' in results assert 'output_mep' in results assert 'output_trajectory' in results diff --git a/tests/parsers/test_neb/test_neb_default.yml b/tests/parsers/test_neb/test_neb_default.yml index 32a688b85..4d75720c5 100644 --- a/tests/parsers/test_neb/test_neb_default.yml +++ b/tests/parsers/test_neb/test_neb_default.yml @@ -25,7 +25,7 @@ parameters: ci_scheme: auto climbing_image_auto: - 1 - code_version: 6.4.1 + code_version: v.6.4.1 converged: - true - 13 diff --git a/tests/parsers/test_ph/test_ph_default_default_.yml b/tests/parsers/test_ph/test_ph_default_default_.yml index 4797a063f..c63bf9fe0 100644 --- a/tests/parsers/test_ph/test_ph_default_default_.yml +++ b/tests/parsers/test_ph/test_ph_default_default_.yml @@ -1,4 +1,4 @@ -code_version: '6.1' +code_version: v.6.1 dielectric_constant: - - 57.36256076907993 - -2.842170943040401e-14 diff --git a/tests/parsers/test_ph/test_ph_not_converged.yml b/tests/parsers/test_ph/test_ph_not_converged.yml index 01ed77d4d..2b77ae523 100644 --- a/tests/parsers/test_ph/test_ph_not_converged.yml +++ b/tests/parsers/test_ph/test_ph_not_converged.yml @@ -1,4 +1,4 @@ -code_version: '6.1' +code_version: v.6.1 number_of_atoms: 2 number_of_irr_representations_for_each_q: - 2 diff --git a/tests/parsers/test_ph/test_ph_out_of_walltime.yml b/tests/parsers/test_ph/test_ph_out_of_walltime.yml index fa5fe52f6..9d42e4b8f 100644 --- a/tests/parsers/test_ph/test_ph_out_of_walltime.yml +++ b/tests/parsers/test_ph/test_ph_out_of_walltime.yml @@ -1,4 +1,4 @@ -code_version: 6.3MaX +code_version: v.6.3MaX number_of_atoms: 2 number_of_irr_representations_for_each_q: - 2 diff --git a/tests/parsers/test_pw2gw/test_pw2gw_default_data.yml b/tests/parsers/test_pw2gw/test_pw2gw_default_data.yml index 64636d951..655b02f0e 100644 --- a/tests/parsers/test_pw2gw/test_pw2gw_default_data.yml +++ b/tests/parsers/test_pw2gw/test_pw2gw_default_data.yml @@ -1,4 +1,4 @@ output_parameters: - code_version: '6.2' + code_version: v.6.2 wall_time: 1m26.21s wall_time_seconds: 86.21000000000001 diff --git a/tests/parsers/test_pw2wannier90/test_pw2wannier90_default.yml b/tests/parsers/test_pw2wannier90/test_pw2wannier90_default.yml index 4746d9d82..e4fbf1f8e 100644 --- a/tests/parsers/test_pw2wannier90/test_pw2wannier90_default.yml +++ b/tests/parsers/test_pw2wannier90/test_pw2wannier90_default.yml @@ -1,4 +1,4 @@ parameters: - code_version: 6.4.1 + code_version: v.6.4.1 wall_time: 2.18s wall_time_seconds: 2.18