Have ert show hooked workflows in GUI#13397
Conversation
0095d01 to
4e61524
Compare
|
Changing iteration tabs does not always update the fm_overview table... |
4e61524 to
fd82164
Compare
|
|
||
| from pydantic import BaseModel, ConfigDict, Field, TypeAdapter | ||
|
|
||
| from _ert.hook_runtime import HookRuntime |
There was a problem hiding this comment.
Had to move hook_runtime to _ert to avoid circular import
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #13397 +/- ##
==========================================
- Coverage 90.05% 90.01% -0.04%
==========================================
Files 459 461 +2
Lines 32040 32492 +452
==========================================
+ Hits 28853 29249 +396
- Misses 3187 3243 +56
Flags with carried forward coverage won't be shown. Click here to find out more.
|
9181b64 to
4d0e6b6
Compare
|
|
||
|
|
||
| class _WorkflowEvent(BaseModel): | ||
| hook: HookRuntime | None = None |
There was a problem hiding this comment.
workflow_runner tests required this to be optional
| PRE_EXPERIMENT = "PRE_EXPERIMENT" | ||
| POST_EXPERIMENT = "POST_EXPERIMENT" | ||
|
|
||
| def workflow_tab_title(self) -> str: |
There was a problem hiding this comment.
Not sure about this one. Maybe I should just change the strenum values directly(?)
| from .workflow import WorkflowWidget | ||
|
|
||
|
|
||
| class IterationWidget(QWidget): |
There was a problem hiding this comment.
This is the widget that allows us to group the tabs. Maybe TabGroupingWidget is better? It can contain UpdateWidget, RealizationWidget, and WorkflowWIdget.
| _STATUS_TO_BACKGROUND = { | ||
| WorkflowStatus.PENDING: QColor(*state.COLOR_PENDING), | ||
| WorkflowStatus.RUNNING: QColor(*state.COLOR_RUNNING), | ||
| WorkflowStatus.FINISHED: QColor(*state.COLOR_FINISHED), | ||
| WorkflowStatus.FAILED: QColor(*state.COLOR_FAILED), | ||
| WorkflowStatus.CANCELLED: QColor(*state.COLOR_CANCELLED), | ||
| } |
There was a problem hiding this comment.
This is very similar to the statuses and look we have in evaluator. The tables can probably at some point be combined (if we want to add the duration field for workflows too).
| "Workflow job": 0, | ||
| "Status": 1, |
There was a problem hiding this comment.
Maybe all should be uppercase?
2e60d28 to
d466b09
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces workflow lifecycle events (batch + per-workflow started/finished/cancelled) and wires them through the run model into the GUI so workflow execution can be visualized in dedicated tabs (including per-iteration/update grouping). It also centralizes HookRuntime under _ert and updates affected tests accordingly.
Changes:
- Add new workflow event types (
Workflow*Event,WorkflowStatus) and emit them fromRunModel.run_workflows()andWorkflowRunner.run_blocking(). - Introduce GUI widgets/tabs (
WorkflowWidget,IterationWidget) and updateRunDialogto place workflow hooks before/after iteration/update tabs. - Expand unit/UI test coverage to assert event emission and GUI tab ordering/behavior for workflows.
Reviewed changes
Copilot reviewed 22 out of 24 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/ert/unit_tests/workflow_runner/test_workflow_runner.py | Adds tests asserting per-workflow events include hook/iteration/workflow_name and capture stdout; adds cancellation event assertions. |
| tests/ert/unit_tests/run_models/test_base_run_model.py | Adds test for workflow batch events across multiple workflows, including non-stopping failures. |
| tests/ert/unit_tests/gui/experiments/test_run_dialog.py | Updates GUI unit tests for new IterationWidget structure and adds test for workflow tabs placement around iteration tab. |
| tests/ert/ui_tests/gui/test_workflow_widget.py | New UI test suite validating WorkflowWidget status/label/output rendering and row coloring. |
| tests/ert/ui_tests/gui/test_update_runs.py | Extends UI tests to validate workflow hook tab placement across experiment/iteration/update lifecycle. |
| tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py | Adjusts UI tests to navigate through IterationWidget to reach RealizationWidget. |
| tests/ert/ui_tests/gui/test_docs_screenshots.py | Updates screenshot test navigation for IterationWidget nesting. |
| tests/ert/ui_tests/gui/conftest.py | Updates common GUI test helper to account for IterationWidget tab nesting. |
| src/ert/workflow_runner.py | Emits workflow started/finished/cancelled events and aggregates stdout/stderr across jobs. |
| src/ert/run_models/update_run_model.py | Reorders RunModelUpdateBeginEvent/status emission relative to pre-update workflows. |
| src/ert/run_models/run_model.py | Emits workflow batch started/finished events and passes hook/iteration/name into WorkflowRunner. |
| src/ert/run_models/event.py | Extends run-model event union to include WorkflowEvent. |
| src/ert/gui/experiments/view/workflow.py | New WorkflowWidget displaying workflow status and stdout/stderr in a table with status coloring. |
| src/ert/gui/experiments/view/iteration.py | New IterationWidget to group Run/Update/Workflow sub-tabs per iteration/update. |
| src/ert/gui/experiments/view/init.py | Exports IterationWidget and WorkflowWidget. |
| src/ert/gui/experiments/run_dialog.py | Reworks tab management to use IterationWidget containers and to create/update workflow tabs on workflow events. |
| src/ert/config/workflow_fixtures.py | Switches HookRuntime import to _ert.hook_runtime. |
| src/ert/config/parsing/hook_runtime.py | Removes local HookRuntime definition (moved to _ert). |
| src/ert/config/parsing/config_schema.py | Updates schema typing to use _ert.hook_runtime.HookRuntime. |
| src/ert/config/parsing/init.py | Re-exports _ert.hook_runtime.HookRuntime from parsing package. |
| src/_ert/hook_runtime.py | New home for HookRuntime plus workflow_tab_title() helper for GUI labels. |
| src/_ert/events.py | Adds WorkflowStatus and workflow event models to the shared events module. |
| logger.info(f"Workflow job {jobrunner.name} starting") | ||
| jobrunner.run(args, fixtures=self.fixtures) | ||
| try: | ||
| jobrunner.run(args, fixtures=self.fixtures) | ||
| except Exception as err: | ||
| stdout = "" | ||
| stderr = str(err) |
| try: | ||
| jobrunner.run(args, fixtures=self.fixtures) | ||
| except Exception as err: |
There was a problem hiding this comment.
This will be step 2!
| item.setText("-" if text == "" else text) # noqa: PLC1901 | ||
| item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) | ||
| item.setToolTip(text) |
There was a problem hiding this comment.
Wouldn't passing None be fine?
|
Now it is possible to cancel hooked workflows while they are running. It is very similar to the fm step statuses during evaluation. Screen.Recording.2026-05-05.at.14.59.47.mov |
de417eb to
5f7baed
Compare
5f7baed to
b3a7616
Compare
| iteration=workflow_iteration, | ||
| workflow_names=workflow_names, | ||
| status=WorkflowStatus.CANCELLED, | ||
| ) | ||
| ) |
| item.setText("-" if text == "" else text) # noqa: PLC1901 | ||
| item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) | ||
| item.setToolTip(text) |
| @pytest.mark.usefixtures("use_tmpdir") | ||
| def test_run_workflows_emits_events_for_following_workflow_after_non_stopping_failure(): | ||
| WorkflowCommon.createExternalDumpJob() |
| def test_run_workflows_cancels_active_workflow_and_stops_following_workflows( | ||
| use_tmpdir, | ||
| ): | ||
| WorkflowCommon.createExternalDumpJob() |
| @pytest.mark.filterwarnings( | ||
| "ignore:Use of legacy_ertscript_workflow is deprecated.*:DeprecationWarning" | ||
| ) | ||
| def test_run_dialog_places_all_workflow_hooks_in_expected_tabs(qtbot, tmp_path): |
| def test_esmda_with_all_workflows_produces_expected_final_gui( | ||
| qtbot, tmp_path, source_root, run_experiment | ||
| ): |
|
Found a new bug: #13487 |
b563a68 to
3cac030
Compare
This commit changes the GUI to: * Show iterations and updates in tabs to accommodate showing pre/post run/update workflows * Show pre-experiment and post-experiment workflows on main tab-bar * Pressing terminate experiment during hooked workflows cancels the workflow, and marks it as cancelled by user. Following workflows in the same hook will be marked as cancelled, as to not mislead the user.
3cac030 to
12957a2
Compare
Issue
Resolves #13320
Approach
This commit changes the GUI to:
run/update workflows
workflow, and marks it as cancelled by user. Following workflows in
the same hook will be marked as cancelled, as to not mislead the user.
(Screenshot of new behavior in GUI if applicable)
git rebase -i main --exec 'just rapid-tests')When applicable