From eb7ce0d217aff30eb1d27302efc70bc359582c49 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Sun, 11 Aug 2024 19:42:02 +0200 Subject: [PATCH 1/6] Allow specifying multi-select workflow parameters This just works, what's needed is: - Only allow multiple=true on actual multiple=true inputs - gxformat2 language to describe this - test --- lib/galaxy/workflow/modules.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index eeece34fe554..7109efe8c38e 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -1290,6 +1290,18 @@ def get_inputs(self): optional_cond.cases = optional_cases if param_type == "text": + + specify_multiple_source = dict( + name="multiple", + label="Allow multiple selection", + help="Only applies when connected to multi-select parameter(s)", + type="boolean", + checked=parameter_def.get("multiple", False), + ) + specify_multiple = BooleanToolParameter(None, specify_multiple_source) + # Insert multiple option as first option, which is determined by dictionary insert order + when_this_type.inputs = {"multiple": specify_multiple, **when_this_type.inputs} + restrict_how_source: Dict[str, Union[str, List[Dict[str, Union[str, bool]]]]] = dict( name="how", label="Restrict Text Values?", type="select" ) @@ -1449,6 +1461,8 @@ def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepCo # Optional parameters for tool input source definition. parameter_kwds: Dict[str, Union[str, List[Dict[str, Any]]]] = {} + if "multiple" in parameter_def: + parameter_kwds["multiple"] = parameter_def["multiple"] is_text = parameter_type == "text" restricted_inputs = False @@ -1499,9 +1513,6 @@ def _parameter_def_list_to_options(parameter_value): if parameter_type == "boolean": parameter_kwds["checked"] = default_value - if "value" not in parameter_kwds and parameter_type in ["integer", "float"]: - parameter_kwds["value"] = str(0) - if is_text and parameter_def.get("suggestions") is not None: suggestion_values = parameter_def.get("suggestions") parameter_kwds["options"] = _parameter_def_list_to_options(suggestion_values) @@ -1556,6 +1567,7 @@ def step_state_to_tool_state(self, state): default_set = True default_value = state["default"] state["optional"] = True + multiple = state.get("multiple") restrictions = state.get("restrictions") restrictOnConnections = state.get("restrictOnConnections") suggestions = state.get("suggestions") @@ -1573,6 +1585,8 @@ def step_state_to_tool_state(self, state): "optional": {"optional": str(state.get("optional", False))}, } } + if multiple is not None: + state["parameter_definition"]["multiple"] = multiple state["parameter_definition"]["restrictions"] = {} state["parameter_definition"]["restrictions"]["how"] = restrictions_how @@ -1614,6 +1628,8 @@ def _parse_state_into_dict(self): rval["default"] = optional_state["specify_default"]["default"] else: optional = False + if "multiple" in parameters_def: + rval["multiple"] = parameters_def["multiple"] restrictions_cond_values = parameters_def.get("restrictions") if restrictions_cond_values: From ee297166b46b0efd476938dd873159bf59b82dbe Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Sun, 18 Aug 2024 17:06:27 +0200 Subject: [PATCH 2/6] Install gxformat2 from my branch --- lib/galaxy/dependencies/pinned-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/dependencies/pinned-requirements.txt b/lib/galaxy/dependencies/pinned-requirements.txt index daa9d9bcca7f..3850821b26ea 100644 --- a/lib/galaxy/dependencies/pinned-requirements.txt +++ b/lib/galaxy/dependencies/pinned-requirements.txt @@ -80,7 +80,7 @@ graphql-relay==3.2.0 ; python_version >= "3.8" and python_version < "3.13" gravity==1.0.6 ; python_version >= "3.8" and python_version < "3.13" greenlet==3.0.3 ; python_version < "3.13" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version >= "3.8" gunicorn==22.0.0 ; python_version >= "3.8" and python_version < "3.13" -gxformat2==0.19.0 ; python_version >= "3.8" and python_version < "3.13" +gxformat2 @ git+https://github.com/mvdbeek/gxformat2.git@d3854afc03ee0e0831b22414d1fb6db719f4575b ; python_version >= "3.8" and python_version < "3.13" h11==0.14.0 ; python_version >= "3.8" and python_version < "3.13" h5grove==2.2.0 ; python_version >= "3.8" and python_version < "3.13" h5py==3.11.0 ; python_version >= "3.8" and python_version < "3.13" From a73139d1d97752498a21a94e890311fe45d4df5f Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Sun, 18 Aug 2024 17:21:31 +0200 Subject: [PATCH 3/6] Add workflow tests for multiple="true" workflow parameter --- ...tiple_integer_into_data_column.gxwf-tests.yml | 15 +++++++++++++++ .../multiple_integer_into_data_column.gxwf.yml | 16 ++++++++++++++++ .../workflow/multiple_text.gxwf-tests.yml | 14 ++++++++++++++ lib/galaxy_test/workflow/multiple_text.gxwf.yml | 15 +++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf-tests.yml create mode 100644 lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf.yml create mode 100644 lib/galaxy_test/workflow/multiple_text.gxwf-tests.yml create mode 100644 lib/galaxy_test/workflow/multiple_text.gxwf.yml diff --git a/lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf-tests.yml b/lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf-tests.yml new file mode 100644 index 000000000000..c960ea73e8ff --- /dev/null +++ b/lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf-tests.yml @@ -0,0 +1,15 @@ +- doc: | + Test to verify text parameter can be connected to data column param + job: + input: + type: File + value: 2.tabular + file_type: tabular + column: + value: [1, 2] + type: raw + outputs: + output: + asserts: + - that: has_text + text: "col 1,2" diff --git a/lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf.yml b/lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf.yml new file mode 100644 index 000000000000..9778e0aa5676 --- /dev/null +++ b/lib/galaxy_test/workflow/multiple_integer_into_data_column.gxwf.yml @@ -0,0 +1,16 @@ +class: GalaxyWorkflow +inputs: + input: + type: data + column: + type: [integer] +outputs: + output: + outputSource: column_param_list/output2 +steps: + column_param_list: + tool_id: column_param_list + in: + input1: input + col: column + col_names: column diff --git a/lib/galaxy_test/workflow/multiple_text.gxwf-tests.yml b/lib/galaxy_test/workflow/multiple_text.gxwf-tests.yml new file mode 100644 index 000000000000..15fd0dba0254 --- /dev/null +++ b/lib/galaxy_test/workflow/multiple_text.gxwf-tests.yml @@ -0,0 +1,14 @@ +- doc: | + Test that workflows can run with multiple text parameter fed into a multi select parameter. + job: + input: + value: + - --ex1 + - ex2 + - --ex3 + type: raw + outputs: + output: + asserts: + - that: has_line + line: '--ex1,ex2,--ex3' diff --git a/lib/galaxy_test/workflow/multiple_text.gxwf.yml b/lib/galaxy_test/workflow/multiple_text.gxwf.yml new file mode 100644 index 000000000000..f62f668ba9b9 --- /dev/null +++ b/lib/galaxy_test/workflow/multiple_text.gxwf.yml @@ -0,0 +1,15 @@ +class: GalaxyWorkflow +inputs: + input: + type: [string] +outputs: + output: + outputSource: multi_select/output +steps: + multi_select: + tool_id: multi_select + tool_version: "0.1" + in: + select_ex: input + tool_state: + select_optional: null From 4c722841acf474c47c85a789fb1439724bc704a3 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Sun, 18 Aug 2024 19:11:22 +0200 Subject: [PATCH 4/6] Fix https://github.com/galaxyproject/galaxy/issues/17957 --- client/src/components/Workflow/Editor/NodeOutput.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Workflow/Editor/NodeOutput.vue b/client/src/components/Workflow/Editor/NodeOutput.vue index 7f0e5c68ec06..b3fe8a014f3a 100644 --- a/client/src/components/Workflow/Editor/NodeOutput.vue +++ b/client/src/components/Workflow/Editor/NodeOutput.vue @@ -310,7 +310,7 @@ const outputDetails = computed(() => { const outputType = collectionType && collectionType.isCollection && collectionType.collectionType ? `output is ${collectionTypeToDescription(collectionType)}` - : `output is dataset`; + : `output is ${terminal.value.type || "dataset"}`; if (isMultiple.value) { if (!collectionType) { collectionType = NULL_COLLECTION_TYPE_DESCRIPTION; From 8750f06f02ec8e20950dccacd3dc1c73d208a303 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Sun, 18 Aug 2024 19:14:05 +0200 Subject: [PATCH 5/6] Don't allow connecting multiple=true parameter to single inputs --- .../Workflow/Editor/modules/terminals.ts | 9 +++++++++ .../Editor/test-data/parameter_steps.json | 16 ++++++++++------ client/src/stores/workflowStepStore.ts | 1 + lib/galaxy/workflow/modules.py | 1 + 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/client/src/components/Workflow/Editor/modules/terminals.ts b/client/src/components/Workflow/Editor/modules/terminals.ts index 314da150dec1..1e74b55827a8 100644 --- a/client/src/components/Workflow/Editor/modules/terminals.ts +++ b/client/src/components/Workflow/Editor/modules/terminals.ts @@ -552,6 +552,12 @@ export class InputParameterTerminal extends BaseInputTerminal { const otherType = ("type" in other && other.type) || "data"; const effectiveOtherType = this.effectiveType(otherType); const canAccept = effectiveThisType === effectiveOtherType; + if (!this.multiple && other.multiple) { + return new ConnectionAcceptable( + false, + `This output parameter represents multiple values but input only accepts a single value` + ); + } return new ConnectionAcceptable( canAccept, canAccept ? null : `Cannot attach a ${effectiveOtherType} parameter to a ${effectiveThisType} input` @@ -812,12 +818,14 @@ export class OutputCollectionTerminal extends BaseOutputTerminal { interface OutputParameterTerminalArgs extends Omit { type: ParameterOutput["type"]; + multiple: ParameterOutput["multiple"]; } export class OutputParameterTerminal extends BaseOutputTerminal { constructor(attr: OutputParameterTerminalArgs) { super({ ...attr, datatypes: [] }); this.type = attr.type; + this.multiple = attr.multiple; } } @@ -988,6 +996,7 @@ export function terminalFactory( if (isOutputParameterArg(terminalSource)) { return new OutputParameterTerminal({ ...outputArgs, + multiple: terminalSource.multiple, type: terminalSource.type, }) as TerminalOf; } else if (isOutputCollectionArg(terminalSource)) { diff --git a/client/src/components/Workflow/Editor/test-data/parameter_steps.json b/client/src/components/Workflow/Editor/test-data/parameter_steps.json index d3cff2cf8d98..3cfc3941a127 100644 --- a/client/src/components/Workflow/Editor/test-data/parameter_steps.json +++ b/client/src/components/Workflow/Editor/test-data/parameter_steps.json @@ -199,7 +199,7 @@ "content_id": null, "name": "Input parameter", "tool_state": { - "parameter_definition": "{\"__current_case__\": 1, \"optional\": {\"__current_case__\": 1, \"optional\": \"false\"}, \"parameter_type\": \"integer\"}", + "parameter_definition": "{\"__current_case__\": 1, \"optional\": {\"__current_case__\": 1, \"optional\": \"false\"}, \"parameter_type\": \"integer\", \"multiple\": \"false\",}", "__page__": null, "__rerun_remap_job_id__": null }, @@ -211,7 +211,8 @@ "label": "integer parameter input", "type": "integer", "optional": false, - "parameter": true + "parameter": true, + "multiple": false } ], "annotation": "", @@ -427,7 +428,7 @@ "content_id": null, "name": "Input parameter", "tool_state": { - "parameter_definition": "{\"__current_case__\": 0, \"optional\": {\"__current_case__\": 1, \"optional\": \"false\"}, \"parameter_type\": \"text\", \"restrictions\": {\"__current_case__\": 0, \"how\": \"none\"}}", + "parameter_definition": "{\"__current_case__\": 0, \"optional\": {\"__current_case__\": 1, \"optional\": \"false\"}, \"parameter_type\": \"text\", \"multiple\": \"false\", \"restrictions\": {\"__current_case__\": 0, \"how\": \"none\"}}", "__page__": null, "__rerun_remap_job_id__": null }, @@ -439,7 +440,8 @@ "label": "text parameter input", "type": "text", "optional": false, - "parameter": true + "parameter": true, + "multiple": false } ], "annotation": "", @@ -746,7 +748,8 @@ "txt" ], "type": "data", - "optional": false + "optional": false, + "multiple": false }, { "name": "out2", @@ -754,7 +757,8 @@ "txt" ], "type": "data", - "optional": false + "optional": false, + "multiple": false } ], "annotation": "", diff --git a/client/src/stores/workflowStepStore.ts b/client/src/stores/workflowStepStore.ts index 30a5f80cba00..ff2d1f6b97a5 100644 --- a/client/src/stores/workflowStepStore.ts +++ b/client/src/stores/workflowStepStore.ts @@ -50,6 +50,7 @@ export declare const ParameterTypes: "text" | "integer" | "float" | "boolean" | export interface ParameterOutput extends Omit { type: typeof ParameterTypes; parameter: true; + multiple: boolean; } interface BaseStepInput { diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index 7109efe8c38e..8ff70b180736 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -1539,6 +1539,7 @@ def get_all_outputs(self, data_only=False): label=self.label, type=parameter_def.get("parameter_type"), optional=parameter_def["optional"], + multiple=parameter_def.get("multiple", False), parameter=True, ) ] From e6efc93b6dbe54c3da981fd39bcb56ce31b68dfa Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Fri, 23 Aug 2024 16:13:23 +0200 Subject: [PATCH 6/6] Update to new gxformat2 release --- lib/galaxy/dependencies/pinned-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/dependencies/pinned-requirements.txt b/lib/galaxy/dependencies/pinned-requirements.txt index 3850821b26ea..9e022cbeb8d7 100644 --- a/lib/galaxy/dependencies/pinned-requirements.txt +++ b/lib/galaxy/dependencies/pinned-requirements.txt @@ -80,7 +80,7 @@ graphql-relay==3.2.0 ; python_version >= "3.8" and python_version < "3.13" gravity==1.0.6 ; python_version >= "3.8" and python_version < "3.13" greenlet==3.0.3 ; python_version < "3.13" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version >= "3.8" gunicorn==22.0.0 ; python_version >= "3.8" and python_version < "3.13" -gxformat2 @ git+https://github.com/mvdbeek/gxformat2.git@d3854afc03ee0e0831b22414d1fb6db719f4575b ; python_version >= "3.8" and python_version < "3.13" +gxformat2==0.20.0 ; python_version >= "3.8" and python_version < "3.13" h11==0.14.0 ; python_version >= "3.8" and python_version < "3.13" h5grove==2.2.0 ; python_version >= "3.8" and python_version < "3.13" h5py==3.11.0 ; python_version >= "3.8" and python_version < "3.13"