Skip to content

Warn when a post job action cannot run on a step with no job - #23334

Draft
jmchilton wants to merge 5 commits into
galaxyproject:devfrom
jmchilton:pja_warn_unsupported_mapped_over
Draft

Warn when a post job action cannot run on a step with no job#23334
jmchilton wants to merge 5 commits into
galaxyproject:devfrom
jmchilton:pja_warn_unsupported_mapped_over

Conversation

@jmchilton

Copy link
Copy Markdown
Member

A pick_value step has no job to hang a post job action off, so PickValueModule._apply_post_job_actions dispatches through ActionBox.execute_on_mapped_over instead. That dispatches every action on the step with no allowlist, and any action that does not implement execute_on_mapped_over inherits the DefaultJobAction base, which is pass. Today that is exactly EmailAction and DeleteIntermediatesAction: both are configurable on a pick_value step, both silently do nothing, and nothing anywhere says so.

Add a supports_mapped_over class attribute recording whether an action actually implements the method, and have ActionBox.execute_on_mapped_over warn — naming the step and output — rather than dispatching into a no-op. A unit test asserts the flag agrees with what each class overrides, so it cannot go stale, and a second asserts every action in mapped_over_output_actions supports it. This is the first unit coverage ActionBox has had.

The second commit is the editor half, so the two toggles cannot be configured in the first place. FormSection renders "Email notification" and "Output cleanup" for every step; it now takes a supportsJobBasedActions prop defaulting to true, and FormPickValue passes false. FormTool, the only other consumer, is untouched.

One consequence worth knowing: a workflow that already has one of these actions on a pick_value step keeps it — FormSection still round-trips the hidden keys, so nothing is dropped on save — but it is no longer visible or clearable in the editor, while the backend now logs a warning naming that step. Clearing it means editing the workflow outside the editor.

Part of #22200.

How to test the changes?

test/unit/job_execution/test_action_box.py covers the dispatch: an unsupported action warns instead of running, a supported one still reaches the output, and an unknown action type is ignored silently. It builds real PostJobAction and HistoryDatasetAssociation objects rather than mocks — both construct without a session — and passes None for trans and sa_session, since nothing on this path reads them.

On the client, FormSection.test.ts covers the two render paths and FormPickValue.test.ts covers the prop being passed. test_workflow_editor.py::test_pick_value_hides_actions_needing_a_job covers it end to end: both toggles absent on a pick_value step, both present on a tool step. It waits on the output card first, so the absence assertions cannot pass against a form that simply had not rendered.

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

jmchilton and others added 4 commits August 19, 2026 11:53
pick_value steps produce outputs with no job to hang an action off of, so
PickValueModule dispatches every post job action through
ActionBox.execute_on_mapped_over. Actions that never implemented
execute_on_mapped_over inherit the base no-op, so EmailAction and
DeleteIntermediatesAction can be configured in the editor, are saved to the
database, and are then silently dropped at runtime.

Make the capability explicit as DefaultJobAction.supports_mapped_over and have
ActionBox log a warning naming the step and output rather than dispatching into
a no-op. The other caller, ToolModule, filters through mapped_over_output_actions
first, so it never reaches the warning.

This is the backend half only. The editor still offers the two toggles on a
pick_value step - FormSection renders them for every step - so the workflow
author still gets no feedback at configuration time. Suppressing them there is a
separate change.

Adds test/unit/job_execution/test_action_box.py - the first unit coverage of
ActionBox - pinning supports_mapped_over to what each class actually overrides
so the two cannot drift, and pinning that a supported action still reaches its
output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
test_pick_value_hides_actions_needing_a_job asserts Email notification and Output
cleanup are absent on a pick_value step and still present on a tool step. It also
waits on the output card, so the absence assertions cannot pass against a form
that simply had not rendered.

The pick_value step is selected first - the panel a selected node opens covers
the nodes to its right, so selecting the tool step first makes the pick node
unclickable.

Red without the v-if in FormSection: "Expected DOM elements [...] to be empty for
selector target XPATH selector [//div[@data-label='Email notification']".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PostJobAction and HistoryDatasetAssociation both construct without a session, so
the two Mocks were standing in for objects that are cheaper to just build.

trans and sa_session become None rather than Mocks. Nothing on this path reads
them - a rename only touches the output it is handed, and unsupported or unknown
actions never dispatch - so None turns that into something the test enforces
instead of something a Mock would quietly absorb.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mypy sees a classmethod read off the class as a plain Callable, which has no
__func__, so `make mypy` and the packages job both failed on it. inspect
.getattr_static hands back the classmethod object instead, so __func__ reaches
the underlying function.

Same identity comparison as before - RemoveTagDatasetAction still reads as
implementing it via TagDatasetAction.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant