diff --git a/src/semeio/forward_models/__init__.py b/src/semeio/forward_models/__init__.py index 979795b5c..a795e1ee7 100644 --- a/src/semeio/forward_models/__init__.py +++ b/src/semeio/forward_models/__init__.py @@ -4,10 +4,13 @@ ForwardModelStepDocumentation, ForwardModelStepJSON, ForwardModelStepPlugin, + ForwardModelStepValidationError, + ForwardModelStepValidationWarning, ) from .scripts.design2params import description as design2params_description from .scripts.design_kw import description as design_kw_description +from .scripts.design_kw import design_kw as DesignKWScript class Design2Params(ForwardModelStepPlugin): @@ -45,7 +48,8 @@ class DesignKW(ForwardModelStepPlugin): def __init__(self): super().__init__( name="DESIGN_KW", - command=["design_kw", "", ""], + command=["design_kw", "", "", ""], + default_mapping={"": "false"}, ) def validate_pre_realization_run( @@ -54,7 +58,15 @@ def validate_pre_realization_run( return fm_step_json def validate_pre_experiment(self, fm_step_json: ForwardModelStepJSON) -> None: - pass + errors = DesignKWScript.validate_configuration(fm_step_json.get("argList")[0]) + should_fail_on_validation_error = ( + fm_step_json.get("argList")[2].lower() == "true" + ) + error_message = f"DESIGN_KW configuration validation failed:\n{errors}" + if errors and should_fail_on_validation_error: + raise ForwardModelStepValidationError(error_message) + if errors: + raise ForwardModelStepValidationWarning(error_message) @staticmethod def documentation() -> Optional[ForwardModelStepDocumentation]: diff --git a/src/semeio/forward_models/design_kw/design_kw.py b/src/semeio/forward_models/design_kw/design_kw.py index 0557c6304..432a761ae 100644 --- a/src/semeio/forward_models/design_kw/design_kw.py +++ b/src/semeio/forward_models/design_kw/design_kw.py @@ -1,4 +1,5 @@ import logging +import os import re import shlex from typing import List @@ -6,6 +7,7 @@ _STATUS_FILE_NAME = "DESIGN_KW.OK" _logger = logging.getLogger(__name__) +errors = [] def run( @@ -65,7 +67,9 @@ def all_matched(line, template_file_name, template): f"but this is probably an xml file" ) else: - _logger.error(f"{unmatched} not found in design matrix") + error_msg = f"{unmatched} not found in design matrix" + _logger.error(error_msg) + errors.append(error_msg) valid = False return valid @@ -178,3 +182,39 @@ def rm_genkw_prefix(paramsdict, ignoreprefixes="LOG10_"): for keyvalue in keyvalues if keys.count(keyvalue[0]) == 1 } + + +def validate_configuration( + template_file_name: str, parameters_file_name: str = "parameters.txt" +) -> List[str]: + try: + if not os.path.exists(template_file_name): + raise ValueError( + f"Argument template_file: '{template_file_name}' is not an existing file" + ) + + if not os.path.exists(parameters_file_name): + raise ValueError( + f"Could not find required parameters file from DESIGN2PARAMS: '{parameters_file_name}'" + ) + with open(parameters_file_name, encoding="utf-8") as parameters_file: + parameters = parameters_file.readlines() + + key_vals = extract_key_value(parameters) + + key_vals.update(rm_genkw_prefix(key_vals)) + + with open(template_file_name, encoding="utf-8") as template_file: + template = template_file.readlines() + + for line in template: + if not is_comment(line): + for key, value in key_vals.items(): + line = line.replace(f"<{key}>", str(value)) + + all_matched(line, template_file_name, template) + + except ValueError as e: + errors.append(str(e)) + + return errors diff --git a/src/semeio/forward_models/scripts/design_kw.py b/src/semeio/forward_models/scripts/design_kw.py index 84669e31a..a249473c6 100755 --- a/src/semeio/forward_models/scripts/design_kw.py +++ b/src/semeio/forward_models/scripts/design_kw.py @@ -20,6 +20,8 @@ Example: If ``parameters.txt`` has the line ``MULTFLT:FLT_A10_B18 0.001``, both of the templates ```` and ```` will expand to ``0.001``. + +Configuration validation pre experiment can be disabled by explicitly setting ``=false`` """ @@ -44,7 +46,7 @@ def create_parser(): default="WARNING", type=logging.getLevelName, ) - + parser.add_argument("--validate", required=False, type=bool, default=True) return parser