Skip to content

Commit 36217de

Browse files
authored
Merge pull request #521 from martenson/clean-refactor
Refactor rerun_invocation to use /request as the source of arguments.
2 parents 90b509e + ff15d6c commit 36217de

File tree

3 files changed

+203
-14
lines changed

3 files changed

+203
-14
lines changed

bioblend/_tests/TestGalaxyInvocations.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
class TestGalaxyInvocations(GalaxyTestBase.GalaxyTestBase):
1515
workflow_id: str
1616
pause_workflow_id: str
17+
x_random_lines_workflow_id: str
1718

1819
@classmethod
1920
def setUpClass(cls) -> None:
@@ -22,6 +23,8 @@ def setUpClass(cls) -> None:
2223
cls.workflow_id = cls.gi.workflows.import_workflow_from_local_path(path)["id"]
2324
path = test_util.get_abspath(os.path.join("data", "test_workflow_pause.ga"))
2425
cls.pause_workflow_id = cls.gi.workflows.import_workflow_from_local_path(path)["id"]
26+
path = test_util.get_abspath(os.path.join("data", "select_x_random_lines.ga"))
27+
cls.x_random_lines_workflow_id = cls.gi.workflows.import_workflow_from_local_path(path)["id"]
2528

2629
def setUp(self):
2730
super().setUp()
@@ -172,6 +175,27 @@ def test_rerun_invocation(self):
172175
history = self.gi.histories.show_history(rerun_invocation["history_id"], contents=True)
173176
assert len(history) == 3
174177

178+
@test_util.skip_unless_galaxy("release_21.01")
179+
def test_rerun_invocation_with_input_params(self):
180+
threeline_dataset_id = self._test_dataset(self.history_id, contents="A\nB\nC")
181+
invocation = self._invoke_x_random_lines_workflow(threeline_dataset_id)
182+
self.gi.invocations.wait_for_invocation(invocation["id"])
183+
rerun_invocation = self.gi.invocations.rerun_invocation(invocation["id"], history_id=self.history_id)
184+
self.gi.invocations.wait_for_invocation(rerun_invocation["id"])
185+
186+
@test_util.skip_unless_galaxy("release_24.2")
187+
def test_rerun_invocation_with_input_params_changed(self):
188+
threeline_dataset_id = self._test_dataset(self.history_id, contents="A\nB\nC")
189+
invocation = self._invoke_x_random_lines_workflow(threeline_dataset_id)
190+
self.gi.invocations.wait_for_invocation(invocation["id"])
191+
inputs_update = {"how_many": 1}
192+
rerun_invocation = self.gi.invocations.rerun_invocation(
193+
invocation["id"], inputs_update=inputs_update, history_id=self.history_id
194+
)
195+
self.gi.invocations.wait_for_invocation(rerun_invocation["id"])
196+
rerun_request = self.gi.invocations.get_invocation_request(rerun_invocation["id"])
197+
assert rerun_request["inputs"]["how_many"] == 1
198+
175199
def _invoke_workflow(self) -> dict[str, Any]:
176200
dataset = {"src": "hda", "id": self.dataset_id}
177201

@@ -188,3 +212,11 @@ def _invoke_pause_workflow(self) -> dict[str, Any]:
188212
inputs={"0": {"src": "hda", "id": self.dataset_id}},
189213
history_id=self.history_id,
190214
)
215+
216+
def _invoke_x_random_lines_workflow(self, dataset_id: str) -> dict[str, Any]:
217+
return self.gi.workflows.invoke_workflow(
218+
self.x_random_lines_workflow_id,
219+
inputs={"from_what": {"src": "hda", "id": dataset_id}, "how_many": 2},
220+
history_id=self.history_id,
221+
inputs_by="name",
222+
)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
{
2+
"a_galaxy_workflow": "true",
3+
"annotation": "",
4+
"comments": [],
5+
"format-version": "0.1",
6+
"name": "select X random lines",
7+
"report": {
8+
"markdown": "\n# Workflow Execution Report\n\n## Workflow Inputs\n```galaxy\ninvocation_inputs()\n```\n\n## Workflow Outputs\n```galaxy\ninvocation_outputs()\n```\n\n## Workflow\n```galaxy\nworkflow_display()\n```\n"
9+
},
10+
"steps": {
11+
"0": {
12+
"annotation": "",
13+
"content_id": null,
14+
"errors": null,
15+
"id": 0,
16+
"input_connections": {},
17+
"inputs": [
18+
{
19+
"description": "",
20+
"name": "how_many"
21+
}
22+
],
23+
"label": "how_many",
24+
"name": "Input parameter",
25+
"outputs": [],
26+
"position": {
27+
"left": 0.5625,
28+
"top": 0
29+
},
30+
"tool_id": null,
31+
"tool_state": "{\"validators\": [{\"min\": null, \"max\": null, \"negate\": false, \"type\": \"in_range\"}], \"parameter_type\": \"integer\", \"optional\": false}",
32+
"tool_version": null,
33+
"type": "parameter_input",
34+
"uuid": "b609b67d-5101-4162-9307-51c0b7c48b51",
35+
"when": null,
36+
"workflow_outputs": []
37+
},
38+
"1": {
39+
"annotation": "",
40+
"content_id": null,
41+
"errors": null,
42+
"id": 1,
43+
"input_connections": {},
44+
"inputs": [
45+
{
46+
"description": "",
47+
"name": "from_what"
48+
}
49+
],
50+
"label": "from_what",
51+
"name": "Input dataset",
52+
"outputs": [],
53+
"position": {
54+
"left": 0,
55+
"top": 100.85546875
56+
},
57+
"tool_id": null,
58+
"tool_state": "{\"optional\": false, \"tag\": null}",
59+
"tool_version": null,
60+
"type": "data_input",
61+
"uuid": "0c3e99d4-8da2-4188-8aa9-cf9982561659",
62+
"when": null,
63+
"workflow_outputs": []
64+
},
65+
"2": {
66+
"annotation": "",
67+
"content_id": "random_lines1",
68+
"errors": null,
69+
"id": 2,
70+
"input_connections": {
71+
"input": {
72+
"id": 1,
73+
"output_name": "output"
74+
},
75+
"num_lines": {
76+
"id": 0,
77+
"output_name": "output"
78+
}
79+
},
80+
"inputs": [],
81+
"label": "random_lines",
82+
"name": "Select random lines",
83+
"outputs": [
84+
{
85+
"name": "out_file1",
86+
"type": "input"
87+
}
88+
],
89+
"position": {
90+
"left": 302.984375,
91+
"top": 19.515625
92+
},
93+
"post_job_actions": {},
94+
"tool_id": "random_lines1",
95+
"tool_state": "{\"input\": {\"__class__\": \"ConnectedValue\"}, \"num_lines\": {\"__class__\": \"ConnectedValue\"}, \"seed_source\": {\"seed_source_selector\": \"no_seed\", \"__current_case__\": 0}, \"__page__\": 0, \"__rerun_remap_job_id__\": null}",
96+
"tool_uuid": null,
97+
"tool_version": "2.0.2",
98+
"type": "tool",
99+
"uuid": "6182ab34-7b61-49b1-9827-e1b1f81c57cc",
100+
"when": null,
101+
"workflow_outputs": []
102+
}
103+
},
104+
"tags": [],
105+
"uuid": "6b2bd605-08e4-467f-a854-e4681e7b62d0",
106+
"version": 2
107+
}

bioblend/galaxy/invocations/__init__.py

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ def rerun_invocation(
172172
allow_tool_state_corrections: bool = False,
173173
inputs_by: Optional[InputsBy] = None,
174174
parameters_normalized: bool = False,
175+
resource_params: Optional[dict[str, Any]] = None,
176+
use_cached_job: bool = True,
175177
) -> dict[str, Any]:
176178
"""
177179
Rerun a workflow invocation. For more extensive documentation of all
@@ -181,9 +183,10 @@ def rerun_invocation(
181183
:param invocation_id: Encoded workflow invocation ID to be rerun
182184
183185
:type inputs_update: dict
184-
:param inputs_update: If different datasets should be used to the original
186+
:param inputs_update: If different inputs should be used to the original
185187
invocation, this should contain a mapping of workflow inputs to the new
186-
datasets and dataset collections.
188+
datasets and dataset collections. Watch out for conflict with the
189+
legacy params_update.
187190
188191
:type params_update: dict
189192
:param params_update: If different non-dataset tool parameters should be
@@ -226,24 +229,53 @@ def rerun_invocation(
226229
Default is ``False``, but when setting parameters for a subworkflow,
227230
``True`` is required.
228231
232+
:type resource_params: dict
233+
:param resource_params: A dictionary containing the resource parameters
234+
to be used for this workflow run.
235+
236+
:type use_cached_job: bool
237+
:param use_cached_job: Whether to use cached jobs for the workflow
238+
invocation.
239+
229240
:rtype: dict
230241
:return: A dict describing the new workflow invocation.
231242
232243
.. note::
233244
This method works only on Galaxy 21.01 or later.
234245
"""
235-
invocation_details = self.show_invocation(invocation_id)
236-
workflow_id = invocation_details["workflow_id"]
237-
inputs = invocation_details["inputs"]
238-
wf_params = invocation_details["input_step_parameters"]
246+
try:
247+
payload = self.get_invocation_request(invocation_id)
248+
except ConnectionError as e:
249+
if e.status_code != 404:
250+
raise
251+
# Galaxy release_24.1 or earlier
252+
invocation = self.show_invocation(invocation_id)
253+
workflow_step_id_to_index = {
254+
step["workflow_step_id"]: index for index, step in enumerate(invocation["steps"])
255+
}
256+
# Merge input_step_parameters (indexed by label) into inputs (indexed by step index)
257+
inputs = invocation["inputs"]
258+
for param_input_dict in invocation["input_step_parameters"].values():
259+
workflow_step_id = param_input_dict["workflow_step_id"]
260+
workflow_step_index = workflow_step_id_to_index[workflow_step_id]
261+
inputs[str(workflow_step_index)] = param_input_dict
262+
payload = {
263+
"inputs": inputs,
264+
"instance": True,
265+
"workflow_id": invocation["workflow_id"],
266+
}
267+
else:
268+
# Drop history_id from the payload as we will set history later
269+
payload.pop("history_id")
270+
workflow_id = payload["workflow_id"]
239271
if inputs_update:
240-
for inp, input_value in inputs_update.items():
241-
inputs[inp] = input_value
272+
if payload.get("inputs") is None:
273+
payload["inputs"] = {}
274+
payload["inputs"].update(inputs_update)
242275
if params_update:
243-
for param, param_value in params_update.items():
244-
wf_params[param] = param_value
245-
payload = {"inputs": inputs, "params": wf_params}
246-
276+
if payload.get("parameters") is None:
277+
payload["parameters"] = {}
278+
payload["parameters"].update(params_update)
247279
if replacement_params:
248280
payload["replacement_params"] = replacement_params
249281
if history_id:
@@ -258,9 +290,11 @@ def rerun_invocation(
258290
payload["inputs_by"] = inputs_by
259291
if parameters_normalized:
260292
payload["parameters_normalized"] = parameters_normalized
261-
api_params = {"instance": True}
293+
if resource_params:
294+
payload["resource_params"] = resource_params
295+
payload["use_cached_job"] = use_cached_job
262296
url = "/".join((self.gi.url, "workflows", workflow_id, "invocations"))
263-
return self.gi.make_post_request(url=url, payload=payload, params=api_params)
297+
return self.gi.make_post_request(url=url, payload=payload)
264298

265299
def cancel_invocation(self, invocation_id: str) -> dict[str, Any]:
266300
"""
@@ -374,6 +408,22 @@ def get_invocation_step_jobs_summary(self, invocation_id: str) -> list[dict[str,
374408
url = self._make_url(invocation_id) + "/step_jobs_summary"
375409
return self._get(url=url)
376410

411+
def get_invocation_request(self, invocation_id: str) -> dict[str, Any]:
412+
"""
413+
Get a request dict for an invocation.
414+
415+
:type invocation_id: str
416+
:param invocation_id: Encoded workflow invocation ID
417+
418+
:rtype: dict
419+
:return: The invocation request.
420+
421+
.. note::
422+
This method works only on Galaxy 24.2 or later.
423+
"""
424+
url = self._make_url(invocation_id) + "/request"
425+
return self._get(url=url)
426+
377427
def get_invocation_report(self, invocation_id: str) -> dict[str, Any]:
378428
"""
379429
Get a Markdown report for an invocation.

0 commit comments

Comments
 (0)