Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new hook designated for additions to PATH for forward models. #8981

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/ert/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def inner(*args: P.args, **kwargs: P.kwargs) -> Any:
"installable_workflow_jobs",
"help_links",
"installable_forward_model_steps",
"forward_model_paths",
"ecl100_config_path",
"ecl300_config_path",
"flow_config_path",
Expand Down
5 changes: 2 additions & 3 deletions src/ert/plugins/hook_specifications/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
ecl300_config_path,
flow_config_path,
)
from .forward_model_steps import (
installable_forward_model_steps,
)
from .forward_model_steps import forward_model_paths, installable_forward_model_steps
from .help_resources import help_links
from .jobs import (
installable_jobs,
Expand All @@ -21,6 +19,7 @@
"ecl100_config_path",
"ecl300_config_path",
"flow_config_path",
"forward_model_paths",
"help_links",
"installable_forward_model_steps",
"installable_jobs",
Expand Down
8 changes: 8 additions & 0 deletions src/ert/plugins/hook_specifications/forward_model_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ def installable_forward_model_steps() -> (
:return: List of forward model step plugins in the form of subclasses of the
ForwardModelStepPlugin class
"""


@no_type_check
@hook_specification
def forward_model_paths() -> PluginResponse[List[str]]:
"""
:return: List of paths that can be used by forward model steps to locate executables
"""
19 changes: 19 additions & 0 deletions src/ert/plugins/plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,25 @@ def _evaluate_job_doc_hook(

return response.data

def get_forward_model_paths(self) -> List[str]:
response: List[PluginResponse[List[str]]] = self.hook.forward_model_paths()
if response == []:
return []

paths = []
for res in response:
if not isinstance(res.data, List):
raise TypeError(
f"{res.plugin_metadata.plugin_name} did not provide list[str]"
)
for element in res.data:
if not isinstance(element, str):
raise TypeError(
f"{res.plugin_metadata.plugin_name} gave a list of nonstrings"
)
paths.extend(res.data)
return paths

def get_ecl100_config_path(self) -> Optional[str]:
return ErtPluginManager._evaluate_config_hook(
hook=self.hook.ecl100_config_path, config_name="ecl100"
Expand Down
5 changes: 5 additions & 0 deletions tests/ert/unit_tests/plugins/dummy_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ def help_links():
return {"test": "test", "test2": "test"}


@plugin(name="dummy")
def forward_model_paths():
return ["/foo/bin", "/bar/bin"]


@plugin(name="dummy")
def ecl100_config_path():
return "/dummy/path/ecl100_config.yml"
Expand Down
68 changes: 68 additions & 0 deletions tests/ert/unit_tests/plugins/test_plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import tempfile
from unittest.mock import Mock

import pytest

import ert.plugins.hook_implementations
from ert import plugin
from ert.plugins import ErtPluginManager
from tests.ert.unit_tests.plugins import dummy_plugins
from tests.ert.unit_tests.plugins.dummy_plugins import (
Expand All @@ -13,6 +16,7 @@
def test_no_plugins():
pm = ErtPluginManager(plugins=[ert.plugins.hook_implementations])
assert pm.get_help_links() == {"GitHub page": "https://github.com/equinor/ert"}
assert pm.get_forward_model_paths() == []
assert pm.get_flow_config_path() is None
assert pm.get_ecl100_config_path() is None
assert pm.get_ecl300_config_path() is None
Expand All @@ -35,6 +39,7 @@ def test_with_plugins():
"test": "test",
"test2": "test",
}
assert pm.get_forward_model_paths() == ["/foo/bin", "/bar/bin"]
assert pm.get_flow_config_path() == "/dummy/path/flow_config.yml"
assert pm.get_ecl100_config_path() == "/dummy/path/ecl100_config.yml"
assert pm.get_ecl300_config_path() == "/dummy/path/ecl300_config.yml"
Expand All @@ -55,6 +60,69 @@ def test_with_plugins():
]


def test_plugin_with_removed_hook_is_pass():
class LegacyPlugin:
@plugin(name="dummy2")
def legacy_hook_that_is_now_removed():
return "my name is legacy"

# no error, no effect.
ErtPluginManager(plugins=[LegacyPlugin])


def test_lifo_path_order_for_forward_model_paths():
class OtherPlugin:
@plugin(name="dummy2")
def forward_model_paths():
return ["firstinpath", "secondinpath"]

assert ErtPluginManager(
plugins=[dummy_plugins, OtherPlugin]
).get_forward_model_paths() == [
"firstinpath",
"secondinpath",
"/foo/bin",
"/bar/bin",
]
assert ErtPluginManager(
plugins=[OtherPlugin, dummy_plugins]
).get_forward_model_paths() == [
"/foo/bin",
"/bar/bin",
"firstinpath",
"secondinpath",
]


def test_path_plugin_returning_empty_pathlist():
class OtherPlugin:
@plugin(name="dummy2")
def forward_model_paths():
return []

assert ErtPluginManager(plugins=[OtherPlugin]).get_forward_model_paths() == []


def test_path_plugin_returning_nonstrings():
class OtherPlugin:
@plugin(name="dummy2")
def forward_model_paths():
return [0]

with pytest.raises(TypeError, match="str"):
ErtPluginManager(plugins=[OtherPlugin]).get_forward_model_paths()


def test_path_plugin_returning_nonlist():
class OtherPlugin:
@plugin(name="dummy2")
def forward_model_paths():
return "firstinpath"

with pytest.raises(TypeError, match="list"):
ErtPluginManager(plugins=[dummy_plugins, OtherPlugin]).get_forward_model_paths()


def test_job_documentation():
pm = ErtPluginManager(plugins=[dummy_plugins])
expected = {
Expand Down