diff --git a/src/everest/config/everest_config.py b/src/everest/config/everest_config.py index db776a52ed9..2c352b9e384 100644 --- a/src/everest/config/everest_config.py +++ b/src/everest/config/everest_config.py @@ -1,6 +1,5 @@ import logging import os -import shutil from argparse import ArgumentParser from io import StringIO from itertools import chain @@ -32,7 +31,6 @@ from everest.config.server_config import ServerConfig from everest.config.validation_utils import ( InstallDataContext, - as_abs_path, check_for_duplicate_names, check_path_exists, check_writeable_path, @@ -252,71 +250,6 @@ class EverestConfig(BaseModelWithPropertySupport): # type: ignore config_path: Path = Field() model_config = ConfigDict(extra="forbid") - @model_validator(mode="after") - def validate_install_job_sources(self) -> Self: # pylint: disable=E0213 - model = self.model - config_path = self.config_path - if not model or not config_path: - return self - - errors = [] - config_dir = Path(config_path).parent - realizations = model.realizations - - for install_jobs in (self.install_jobs, self.install_workflow_jobs): - if not install_jobs: - continue - - sources = [job.source for job in install_jobs] - for source in sources: - try: - check_path_exists( - path_source=source, - config_path=config_path, - realizations=realizations, - ) - except ValueError as e: - errors.append(str(e)) - abs_config_path = as_abs_path(source, str(config_dir)) - if not os.path.isfile(abs_config_path): - errors.append(f"Is not a file {abs_config_path}") - continue - exec_path = None - valid_jobfile = True - with open(abs_config_path, encoding="utf-8") as jobfile: - for line in jobfile: - if not line.startswith("EXECUTABLE"): - continue - data = line.strip().split() - if len(data) != 2: - valid_jobfile = False - continue - exec_path = data[1] - break - - if not valid_jobfile: - errors.append(f"malformed EXECUTABLE in {source}") - continue - if exec_path is None: - errors.append(f"missing EXECUTABLE in {source}") - continue - - exec_relpath = os.path.join(os.path.dirname(abs_config_path), exec_path) - if os.path.isfile(exec_relpath): - if os.access(exec_relpath, os.X_OK): - continue - # exec_relpath is a file, but not executable; flag and return False - errors.append(f"{exec_relpath} is not executable") - continue - - if not shutil.which(exec_path): - errors.append(f"No such executable {exec_path}") - - if len(errors) > 0: - raise ValueError(errors) - - return self - @model_validator(mode="after") def validate_forward_model_job_name_installed(self) -> Self: # pylint: disable=E0213 install_jobs = self.install_jobs diff --git a/tests/everest/test_config_validation.py b/tests/everest/test_config_validation.py index de5f6e33204..4b348075399 100644 --- a/tests/everest/test_config_validation.py +++ b/tests/everest/test_config_validation.py @@ -10,9 +10,11 @@ from pydantic import ValidationError from ert.config import ConfigWarning +from ert.config.parsing import ConfigValidationError from everest.config import EverestConfig, ModelConfig from everest.config.control_variable_config import ControlVariableConfig from everest.config.sampler_config import SamplerConfig +from everest.simulator.everest_to_ert import everest_to_ert_config from tests.everest.utils import skipif_no_everest_models @@ -656,16 +658,16 @@ def test_that_non_existing_install_job_errors(install_keyword, change_to_tmpdir) os.makedirs("config_dir") with open("config_dir/test.yml", "w", encoding="utf-8") as f: f.write(" ") - with pytest.raises(ValueError) as e: - EverestConfig.with_defaults( - model={ - "realizations": [1, 2, 3], - }, - config_path=Path("config_dir/test.yml"), - **{install_keyword: [{"name": "test", "source": "non_existing"}]}, - ) + config = EverestConfig.with_defaults( + model={ + "realizations": [1, 2, 3], + }, + config_path=Path("config_dir/test.yml"), + **{install_keyword: [{"name": "test", "source": "non_existing"}]}, + ) - assert has_error(e.value, "No such file or directory") + with pytest.raises(ConfigValidationError, match="No such file or directory:"): + everest_to_ert_config(config) @pytest.mark.parametrize( @@ -690,22 +692,23 @@ def test_that_existing_install_job_with_malformed_executable_errors( """ ) - with pytest.raises(ValueError) as e: - EverestConfig.with_defaults( - model={ - "realizations": [1, 2, 3], - }, - config_path=Path("."), - **{ - install_keyword: [ - {"name": "test", "source": "malformed.ert"}, - {"name": "test2", "source": "malformed2.ert"}, - ] - }, - ) + config = EverestConfig.with_defaults( + model={ + "realizations": [1, 2, 3], + }, + config_path=Path("."), + **{ + install_keyword: [ + {"name": "test", "source": "malformed.ert"}, + {"name": "test2", "source": "malformed2.ert"}, + ] + }, + ) - assert has_error(e.value, "malformed EXECUTABLE in malformed.ert") - assert has_error(e.value, "malformed EXECUTABLE in malformed2.ert") + with pytest.raises( + ConfigValidationError, match="EXECUTABLE must have at least 1 arguments" + ): + everest_to_ert_config(config) @pytest.mark.parametrize( @@ -730,20 +733,20 @@ def test_that_existing_install_job_with_non_executable_executable_errors( os.chmod("non_executable", os.stat("non_executable").st_mode & ~0o111) assert not os.access("non_executable", os.X_OK) - with pytest.raises(ValueError) as e: - EverestConfig.with_defaults( - model={ - "realizations": [1, 2, 3], - }, - config_path=Path("."), - **{ - install_keyword: [ - {"name": "test", "source": "exec.ert"}, - ] - }, - ) + config = EverestConfig.with_defaults( + model={ + "realizations": [1, 2, 3], + }, + config_path=Path("."), + **{ + install_keyword: [ + {"name": "test", "source": "exec.ert"}, + ] + }, + ) - assert has_error(e.value, ".*non_executable is not executable") + with pytest.raises(ConfigValidationError, match="File not executable"): + everest_to_ert_config(config) @pytest.mark.parametrize( @@ -764,20 +767,20 @@ def test_that_existing_install_job_with_non_existing_executable_errors( assert not os.access("non_executable", os.X_OK) - with pytest.raises(ValueError) as e: - EverestConfig.with_defaults( - model={ - "realizations": [1, 2, 3], - }, - config_path=Path("."), - **{ - install_keyword: [ - {"name": "test", "source": "exec.ert"}, - ] - }, - ) + config = EverestConfig.with_defaults( + model={ + "realizations": [1, 2, 3], + }, + config_path=Path("."), + **{ + install_keyword: [ + {"name": "test", "source": "exec.ert"}, + ] + }, + ) - assert has_error(e.value, "No such executable non_existing") + with pytest.raises(ConfigValidationError, match="Could not find executable"): + everest_to_ert_config(config) @pytest.mark.parametrize( @@ -911,9 +914,7 @@ def test_that_missing_required_fields_cause_error(): def test_that_non_existing_workflow_jobs_cause_error(): - with pytest.raises( - ValidationError, match=r"No such file or directory (.*)jobs/JOB" - ): + with pytest.raises(ValidationError) as e: EverestConfig.with_defaults( install_workflow_jobs=[{"name": "job0", "source": "jobs/JOB"}], workflows={ @@ -923,6 +924,7 @@ def test_that_non_existing_workflow_jobs_cause_error(): ] }, ) + assert has_error(e.value, "unknown workflow job job1") @skipif_no_everest_models diff --git a/tests/everest/test_everlint.py b/tests/everest/test_everlint.py index 894e8715630..4aa2bb4c729 100644 --- a/tests/everest/test_everlint.py +++ b/tests/everest/test_everlint.py @@ -119,10 +119,6 @@ def test_extra_key(min_config): {"install_data": [{"source": "not a file", "target": "not_relevant"}]}, "No such file or directory", ), - ( - {"install_jobs": [{"source": "does_not_exist", "name": "not_relevant"}]}, - "Is not a file .*/does_not_exist", - ), ( {"install_jobs": [{"source": None, "name": "not_relevant"}]}, "source\n.* should be a valid string", @@ -223,23 +219,6 @@ def test_export_filepath_validation(min_config, tmp_path, monkeypatch, path_val, EverestConfig(**min_config) -@pytest.mark.parametrize( - "content, error", - [ - ("ARGUMENT 1\n", "missing EXECUTABLE (.*)"), - ("EXECUTABLE /no/such/path\n", "No such executable (.*)"), - ("EXECUTABLE my_file\n", "(.*)my_file is not executable"), - ], -) -def test_ert_job_file(tmp_path, monkeypatch, min_config, content, error): - monkeypatch.chdir(tmp_path) - Path("my_file").touch() - Path("ert_job_file").write_text(content, encoding="utf-8") - min_config["install_jobs"] = [{"source": "ert_job_file", "name": "irrelephant"}] - with pytest.raises(ValidationError, match=error): - EverestConfig(**min_config) - - def test_invalid_wells(tmp_path, monkeypatch): monkeypatch.chdir(tmp_path) Path("my_file").touch()