Skip to content

Commit

Permalink
Remove job validation from everest config code
Browse files Browse the repository at this point in the history
  • Loading branch information
verveerpj committed Jan 7, 2025
1 parent 2f81dd1 commit 00b015f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 141 deletions.
67 changes: 0 additions & 67 deletions src/everest/config/everest_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import os
import shutil
from argparse import ArgumentParser
from io import StringIO
from itertools import chain
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
108 changes: 55 additions & 53 deletions tests/everest/test_config_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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(
Expand All @@ -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(
Expand Down Expand Up @@ -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={
Expand All @@ -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
Expand Down
21 changes: 0 additions & 21 deletions tests/everest/test_everlint.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 00b015f

Please sign in to comment.