mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Workflow replacement parameters polish.
- Selenium test case demonstrating their use in simple workflows. - API test demonstrating they work with nested workflows from the run perspective. - Update run variant of workflow to_dict to parse out replacement parameters to display on the backend and tweak the client to just accept these. - Parse out replacement parameters for subworkflows recursively, include in new run output attribute - nested workflow replacement parameters work now. - Selenium test case demosntrating subworkflow replacement parameters are rendered and used when submitted.
This commit is contained in:
@@ -127,21 +127,24 @@ var View = Backbone.View.extend({
|
||||
// identify and configure workflow parameters
|
||||
var wp_count = 0;
|
||||
this.wp_inputs = {};
|
||||
|
||||
function _ensureWorkflowParameter(wp_name) {
|
||||
return self.wp_inputs[wp_name] = self.wp_inputs[wp_name] || {
|
||||
label: wp_name,
|
||||
name: wp_name,
|
||||
type: "text",
|
||||
color: `hsl( ${++wp_count * 100}, 70%, 30% )`,
|
||||
style: "ui-form-wp-source",
|
||||
links: []
|
||||
};
|
||||
}
|
||||
|
||||
function _handleWorkflowParameter(value, callback) {
|
||||
var re = /\$\{(.+?)\}/g;
|
||||
var match;
|
||||
while ((match = re.exec(String(value)))) {
|
||||
var wp_name = match[1];
|
||||
callback(
|
||||
(self.wp_inputs[wp_name] = self.wp_inputs[wp_name] || {
|
||||
label: wp_name,
|
||||
name: wp_name,
|
||||
type: "text",
|
||||
color: `hsl( ${++wp_count * 100}, 70%, 30% )`,
|
||||
style: "ui-form-wp-source",
|
||||
links: []
|
||||
})
|
||||
);
|
||||
callback(_ensureWorkflowParameter(wp_name));
|
||||
}
|
||||
}
|
||||
_.each(this.steps, (step, i) => {
|
||||
@@ -154,10 +157,8 @@ var View = Backbone.View.extend({
|
||||
input.style = "ui-form-wp-target";
|
||||
});
|
||||
});
|
||||
_.each(step.post_job_actions, pja => {
|
||||
_.each(pja.action_arguments, arg => {
|
||||
_handleWorkflowParameter(arg, () => {});
|
||||
});
|
||||
_.each(step.replacement_parameters, wp_name => {
|
||||
_ensureWorkflowParameter(wp_name);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -444,6 +444,7 @@ class WorkflowContentsManager(UsesAnnotations):
|
||||
step_model = {
|
||||
'inputs' : [input.to_dict(trans) for input in inputs.values()]
|
||||
}
|
||||
step_model['replacement_parameters'] = step.module.get_replacement_parameters(step)
|
||||
step_model['step_type'] = step.type
|
||||
step_model['step_label'] = step.label
|
||||
step_model['step_name'] = step.module.get_name()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Modules used in building workflows
|
||||
"""
|
||||
import logging
|
||||
import re
|
||||
from json import loads
|
||||
from xml.etree.ElementTree import (
|
||||
Element,
|
||||
@@ -259,6 +260,11 @@ class WorkflowModule(object):
|
||||
|
||||
progress.set_step_outputs(invocation_step, outputs, already_persisted=True)
|
||||
|
||||
def get_replacement_parameters(self, step):
|
||||
"""Return a list of replacement parameters."""
|
||||
|
||||
return []
|
||||
|
||||
|
||||
class SubWorkflowModule(WorkflowModule):
|
||||
# Two step improvements to build runtime inputs for subworkflow modules
|
||||
@@ -403,6 +409,16 @@ class SubWorkflowModule(WorkflowModule):
|
||||
|
||||
return inputs
|
||||
|
||||
def get_replacement_parameters(self, step):
|
||||
"""Return a list of replacement parameters."""
|
||||
replacement_parameters = set()
|
||||
for subworkflow_step in self.subworkflow.steps:
|
||||
module = subworkflow_step.module
|
||||
for replacement_parameter in module.get_replacement_parameters(subworkflow_step):
|
||||
replacement_parameters.add(replacement_parameter)
|
||||
|
||||
return list(replacement_parameters)
|
||||
|
||||
|
||||
class InputProxy(object):
|
||||
"""Provide InputParameter-interfaces over inputs but renamed for workflow context."""
|
||||
@@ -1088,6 +1104,16 @@ class ToolModule(WorkflowModule):
|
||||
action_arguments = None
|
||||
return PostJobAction(value['action_type'], step, output_name, action_arguments)
|
||||
|
||||
def get_replacement_parameters(self, step):
|
||||
"""Return a list of replacement parameters."""
|
||||
replacement_parameters = set()
|
||||
for pja in step.post_job_actions:
|
||||
for argument in pja.action_arguments.values():
|
||||
for match in re.findall(r'\$\{(.+?)\}', argument):
|
||||
replacement_parameters.add(match)
|
||||
|
||||
return list(replacement_parameters)
|
||||
|
||||
|
||||
class WorkflowModuleFactory(object):
|
||||
|
||||
|
||||
+23
-19
@@ -20,8 +20,10 @@ from base.populators import ( # noqa: I100
|
||||
WorkflowPopulator
|
||||
)
|
||||
from base.workflow_fixtures import ( # noqa: I100
|
||||
WORKFLOW_NESTED_REPLACEMENT_PARAMETER,
|
||||
WORKFLOW_NESTED_RUNTIME_PARAMETER,
|
||||
WORKFLOW_NESTED_SIMPLE,
|
||||
WORKFLOW_RENAME_ON_INPUT,
|
||||
WORKFLOW_RUNTIME_PARAMETER_AFTER_PAUSE,
|
||||
WORKFLOW_WITH_DYNAMIC_OUTPUT_COLLECTION,
|
||||
WORKFLOW_WITH_OUTPUT_COLLECTION,
|
||||
@@ -224,6 +226,7 @@ class BaseWorkflowsApiTestCase(api.ApiTestCase):
|
||||
|
||||
test_data = jobs_descriptions.get("test_data", {})
|
||||
parameters = test_data.pop('step_parameters', {})
|
||||
replacement_parameters = test_data.pop("replacement_parameters", {})
|
||||
inputs, label_map, has_uploads = load_data_dict(history_id, test_data, self.dataset_populator, self.dataset_collection_populator)
|
||||
workflow_request = dict(
|
||||
history="hist_id=%s" % history_id,
|
||||
@@ -234,6 +237,8 @@ class BaseWorkflowsApiTestCase(api.ApiTestCase):
|
||||
if parameters:
|
||||
workflow_request["parameters"] = dumps(parameters)
|
||||
workflow_request["parameters_normalized"] = True
|
||||
if replacement_parameters:
|
||||
workflow_request["replacement_params"] = dumps(replacement_parameters)
|
||||
if has_uploads:
|
||||
self.dataset_populator.wait_for_history(history_id, assert_ok=True)
|
||||
url = "workflows/%s/usage" % (workflow_id)
|
||||
@@ -980,6 +985,23 @@ test_data:
|
||||
content = self.dataset_populator.get_history_dataset_content(history_id)
|
||||
assert len([x for x in content.split("\n") if x]) == 2
|
||||
|
||||
@skip_without_tool("cat")
|
||||
def test_run_subworkflow_replacment_parameters(self):
|
||||
with self.dataset_populator.test_history() as history_id:
|
||||
workflow_run_description = """%s
|
||||
|
||||
test_data:
|
||||
replacement_parameters:
|
||||
replaceme: moocow
|
||||
outer_input:
|
||||
value: 1.bed
|
||||
type: File
|
||||
""" % WORKFLOW_NESTED_REPLACEMENT_PARAMETER
|
||||
self._run_jobs(workflow_run_description, history_id=history_id)
|
||||
|
||||
details = self.dataset_populator.get_history_dataset_details(history_id)
|
||||
assert details["name"] == "moocow suffix"
|
||||
|
||||
@skip_without_tool("random_lines1")
|
||||
def test_run_runtime_parameters_after_pause(self):
|
||||
with self.dataset_populator.test_history() as history_id:
|
||||
@@ -2247,25 +2269,7 @@ test_data: {}
|
||||
@skip_without_tool("cat")
|
||||
def test_run_rename_based_on_input(self):
|
||||
with self.dataset_populator.test_history() as history_id:
|
||||
self._run_jobs("""
|
||||
class: GalaxyWorkflow
|
||||
inputs:
|
||||
- id: input1
|
||||
steps:
|
||||
- tool_id: cat
|
||||
label: first_cat
|
||||
state:
|
||||
input1:
|
||||
$link: input1
|
||||
outputs:
|
||||
out_file1:
|
||||
rename: "#{input1 | basename} suffix"
|
||||
test_data:
|
||||
input1:
|
||||
value: 1.fasta
|
||||
type: File
|
||||
name: fasta1
|
||||
""", history_id=history_id)
|
||||
self._run_jobs(WORKFLOW_RENAME_ON_INPUT, history_id=history_id)
|
||||
content = self.dataset_populator.get_history_dataset_details(history_id, wait=True, assert_ok=True)
|
||||
name = content["name"]
|
||||
assert name == "fasta1 suffix", name
|
||||
|
||||
@@ -319,3 +319,67 @@ steps:
|
||||
seed_source_selector: set_seed
|
||||
seed: asdf
|
||||
"""
|
||||
|
||||
WORKFLOW_RENAME_ON_INPUT = """
|
||||
class: GalaxyWorkflow
|
||||
inputs:
|
||||
- id: input1
|
||||
steps:
|
||||
- tool_id: cat
|
||||
label: first_cat
|
||||
state:
|
||||
input1:
|
||||
$link: input1
|
||||
outputs:
|
||||
out_file1:
|
||||
rename: "#{input1 | basename} suffix"
|
||||
test_data:
|
||||
input1:
|
||||
value: 1.fasta
|
||||
type: File
|
||||
name: fasta1
|
||||
"""
|
||||
|
||||
WORKFLOW_RENAME_ON_REPLACEMENT_PARAM = """
|
||||
class: GalaxyWorkflow
|
||||
inputs:
|
||||
- id: input1
|
||||
steps:
|
||||
- tool_id: cat
|
||||
label: first_cat
|
||||
state:
|
||||
input1:
|
||||
$link: input1
|
||||
outputs:
|
||||
out_file1:
|
||||
rename: "${replaceme} suffix"
|
||||
"""
|
||||
|
||||
WORKFLOW_NESTED_REPLACEMENT_PARAMETER = """
|
||||
class: GalaxyWorkflow
|
||||
inputs:
|
||||
- id: outer_input
|
||||
outputs:
|
||||
- id: outer_output
|
||||
source: nested_workflow#workflow_output
|
||||
steps:
|
||||
- run:
|
||||
class: GalaxyWorkflow
|
||||
inputs:
|
||||
- id: inner_input
|
||||
outputs:
|
||||
- id: workflow_output
|
||||
source: first_cat#out_file1
|
||||
steps:
|
||||
- tool_id: cat
|
||||
label: first_cat
|
||||
state:
|
||||
input1:
|
||||
$link: inner_input
|
||||
outputs:
|
||||
out_file1:
|
||||
rename: "${replaceme} suffix"
|
||||
label: nested_workflow
|
||||
connect:
|
||||
inner_input: outer_input
|
||||
"""
|
||||
|
||||
@@ -2,8 +2,10 @@ import yaml
|
||||
from base import rules_test_data
|
||||
from base.populators import load_data_dict
|
||||
from base.workflow_fixtures import (
|
||||
WORKFLOW_NESTED_REPLACEMENT_PARAMETER,
|
||||
WORKFLOW_NESTED_RUNTIME_PARAMETER,
|
||||
WORKFLOW_NESTED_SIMPLE,
|
||||
WORKFLOW_RENAME_ON_REPLACEMENT_PARAM,
|
||||
WORKFLOW_RUNTIME_PARAMETER_SIMPLE,
|
||||
WORKFLOW_SIMPLE_CAT_TWICE,
|
||||
WORKFLOW_WITH_DYNAMIC_OUTPUT_COLLECTION,
|
||||
@@ -78,6 +80,38 @@ class WorkflowRunTestCase(SeleniumTestCase, UsesHistoryItemAssertions):
|
||||
|
||||
self._assert_has_3_lines_after_run(hid=2)
|
||||
|
||||
@selenium_test
|
||||
@managed_history
|
||||
def test_replacement_parameters(self):
|
||||
self.perform_upload(self.get_filename("1.txt"))
|
||||
self.wait_for_history()
|
||||
self.open_in_workflow_run(WORKFLOW_RENAME_ON_REPLACEMENT_PARAM)
|
||||
self.screenshot("workflow_run_rename_simple_empty")
|
||||
self._set_replacement_parameter("replaceme", "moocow")
|
||||
self.screenshot("workflow_run_rename_simple_input")
|
||||
self.workflow_run_submit()
|
||||
output_hid = 2
|
||||
self.history_panel_wait_for_hid_ok(output_hid, allowed_force_refreshes=1)
|
||||
history_id = self.current_history_id()
|
||||
details = self.dataset_populator.get_history_dataset_details(history_id, hid=output_hid)
|
||||
assert details["name"] == "moocow suffix", details
|
||||
|
||||
@selenium_test
|
||||
@managed_history
|
||||
def test_replacement_parameters_on_subworkflows(self):
|
||||
self.perform_upload(self.get_filename("1.txt"))
|
||||
self.wait_for_history()
|
||||
self.open_in_workflow_run(WORKFLOW_NESTED_REPLACEMENT_PARAMETER)
|
||||
self.screenshot("workflow_run_rename_subworkflow_empty")
|
||||
self._set_replacement_parameter("replaceme", "moocow")
|
||||
self.screenshot("workflow_run_rename_subworkflow_input")
|
||||
self.workflow_run_submit()
|
||||
output_hid = 2
|
||||
self.history_panel_wait_for_hid_ok(output_hid, allowed_force_refreshes=1)
|
||||
history_id = self.current_history_id()
|
||||
details = self.dataset_populator.get_history_dataset_details(history_id, hid=output_hid)
|
||||
assert details["name"] == "moocow suffix", details
|
||||
|
||||
@selenium_test
|
||||
def test_execution_with_tool_upgrade(self):
|
||||
name = self.workflow_upload_yaml_with_random_name(WORKFLOW_WITH_OLD_TOOL_VERSION, exact_tools=True)
|
||||
@@ -148,3 +182,12 @@ class WorkflowRunTestCase(SeleniumTestCase, UsesHistoryItemAssertions):
|
||||
assert initial_value == "1", initial_value
|
||||
input_element.clear()
|
||||
input_element.send_keys("3")
|
||||
|
||||
def _set_replacement_parameter(self, tour_id, value):
|
||||
# for random_lines num_lines parameter as runtime parameter in workflow form.
|
||||
div = self.tool_parameter_div(tour_id)
|
||||
input_element = div.find_element_by_css_selector("input")
|
||||
initial_value = input_element.get_attribute("value")
|
||||
assert initial_value == "", initial_value
|
||||
input_element.clear()
|
||||
input_element.send_keys(value)
|
||||
|
||||
Reference in New Issue
Block a user