Skip to content

Commit

Permalink
Review arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
oyvindeide committed Jun 19, 2024
1 parent f57e396 commit 9968991
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 24 deletions.
28 changes: 24 additions & 4 deletions docs/reference/workflows/workflows.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ERT will initialize this class and call the `run` function when the workflow is
either through hooks, or through the gui/cli.

The `run` function can be called with a number of arguments, depending on the context the workflow
is called. User specified arguments from the
is called. There are three distinct ways to call the `run` function:

1. If the `run` function is using `*args` in the `run` function, only the arguments from the user
configuration is passed to the workflow:
Expand All @@ -43,10 +43,22 @@ configuration is passed to the workflow:
def run(self, *args):
print(f"Provided user arguments: {args}")
1. If the `run` function is using `positional arguments in the `run` function. In this case no fixtures
will be added:

.. warning::
This is not recommended, you are adviced to use either option 1 or option 3

.. code-block:: python
class MyJob(ErtScript):
def run(self, my_arg_1, my_arg_2):
print(f"Provided user arguments: {my_arg_1, my_arg_2}")
.. note::
The name of the argument is not required to be `args`, that is just convention.

2. There are a number of specially named arguments the user can call which gives access to internal
3. There are a number of specially named arguments the user can call which gives access to internal
state of the experiment that is running:

.. glossary::
Expand All @@ -63,17 +75,25 @@ state of the experiment that is running:
workflow_args
This gives access to the arguments from the user configuration file

.. note::
The current ensemble will depend on the context. For hooked workflows the ensemble will be:
`PRE_SIMULATION`: parameters and no reponses in ensemble
`POST_SIMULATION`: parameters and responses in ensemble
`PRE_FIRST_UPDATE`/`PRE_UPDATE`: parameters and responses in ensemble
`POST_UPDATE`: parameters and responses in ensemble
The ensemble will switch after the `POST_UPDATE` hook, and will move from prior -> posterior

.. code-block:: python
class MyJob(ErtScript):
def run(
self,
user_arguments: List,
workflow_args: List,
ert_config: ErtConfig,
ensemble: Ensemble,
storage: Storage,
):
print(f"Provided user arguments: {user_arguments}")
print(f"Provided user arguments: {workflow_args}")
For how to load internal workflow jobs into ERT, see: :ref:`installing workflows <legacy_ert_workflow_jobs>`
9 changes: 8 additions & 1 deletion src/ert/config/ert_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,14 @@ def initializeAndRun(
# If the user has specified *args, we skip injecting fixtures, and just
# pass the user configured arguments
if not any([p.kind == p.VAR_POSITIONAL for p in func_args.values()]):
arguments = self.insert_fixtures(func_args, fixtures)
try:
arguments = self.insert_fixtures(func_args, fixtures)
except ValueError as e:
# This is here for backwards compatibility, the user does not have *argv
# but positional arguments. Can not be mixed with using fixtures.
logger.warning(
f"Mixture of fixtures and positional arguments, err: {e}"
)
# Part of deprecation
self._ert = fixtures.get("ert_config")
self._ensemble = fixtures.get("ensemble")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,13 @@ def run(
self,
ert_config,
storage,
output_file,
ensemble_list=None,
design_matrix_path=None,
infer_iteration=True,
drop_const_cols=False,
workflow_args,
):
output_file = workflow_args[0]
ensemble_list = None if len(workflow_args) < 2 else workflow_args[1]
design_matrix_path = None if len(workflow_args) < 3 else workflow_args[2]
_ = True if len(workflow_args) < 4 else workflow_args[3]
drop_const_cols = False if len(workflow_args) < 5 else workflow_args[4]
ensembles = []
facade = LibresFacade(ert_config)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,8 @@ def inferIterationNumber(ensemble_name):

def run(
self,
output_file,
trajectory_path,
storage,
ensemble_list=None,
infer_iteration=True,
drop_const_cols=False,
workflow_args,
):
"""The run method will export the RFT's for all wells and all ensembles.
Expand All @@ -120,6 +116,12 @@ def run(
or $trajectory_path/$WELL_R.txt
"""
output_file = workflow_args[0]
trajectory_path = workflow_args[1]
ensemble_list = None if len(workflow_args) < 3 else workflow_args[2]
_ = True if len(workflow_args) < 4 else workflow_args[3]
drop_const_cols = False if len(workflow_args) < 5 else workflow_args[4]

wells = set()

ensemble_names = []
Expand Down
4 changes: 2 additions & 2 deletions tests/unit_tests/gui/plottery/test_plotting_of_snake_oil.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def plot_figure(qtbot, snake_oil_case_storage, request):

log_handler = GUILogHandler()
with StorageService.init_service(
project=snake_oil_case_storage.ert_config.ens_path,
), open_storage(snake_oil_case_storage.ert_config.ens_path) as storage:
project=snake_oil_case_storage.ens_path,
), open_storage(snake_oil_case_storage.ens_path) as storage:
gui = _setup_main_window(
snake_oil_case_storage, args_mock, log_handler, storage
)
Expand Down
17 changes: 10 additions & 7 deletions tests/unit_tests/job_queue/test_ert_plugin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from unittest.mock import MagicMock

import pytest
Expand Down Expand Up @@ -78,21 +79,23 @@ def run(self, ert_script):
assert plugin.initializeAndRun([], [], {"ert_script": fixture_mock}) == fixture_mock


def test_plugin_with_missing_arguments(capsys):
def test_plugin_with_missing_arguments(caplog):
class FixturePlugin(ErtPlugin):
def run(self, arg_1, ert_script, fixture_2, arg_2="something"):
pass

plugin = FixturePlugin()
fixture_mock = MagicMock()
fixture2_mock = MagicMock()
plugin.initializeAndRun(
[], [1, 2], {"ert_script": fixture_mock, "fixture_2": fixture2_mock}
)
captured = capsys.readouterr()
with caplog.at_level(logging.WARNING):
plugin.initializeAndRun(
[], [1, 2], {"ert_script": fixture_mock, "fixture_2": fixture2_mock}
)

assert plugin.hasFailed()
assert "FixturePlugin misconfigured" in captured.err
assert "['arg_1', 'arg_2'] not found in fixtures" in captured.err
log = "\n".join(caplog.messages)
assert "FixturePlugin misconfigured" in log
assert "['arg_1', 'arg_2'] not found in fixtures" in log


def test_plugin_with_fixtures_and_enough_arguments():
Expand Down

0 comments on commit 9968991

Please sign in to comment.