diff --git a/lib/galaxy/tool_util/parameters/factory.py b/lib/galaxy/tool_util/parameters/factory.py index 1022fff2035..977e5bcbb67 100644 --- a/lib/galaxy/tool_util/parameters/factory.py +++ b/lib/galaxy/tool_util/parameters/factory.py @@ -184,8 +184,10 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool type="rules", name=input_source.parse_name(), ) - elif param_type == "data": - optional = input_source.parse_optional() + elif param_type in ("data", "hidden_data"): + # hidden_data is broken without optional="true" (job runner rejects + # missing datasets); only known user is cufflinks which sets it. + optional = input_source.parse_optional() if param_type == "data" else True multiple = input_source.get_bool("multiple", False) return DataParameterModel( type="data", diff --git a/lib/galaxy/tool_util/verify/parse.py b/lib/galaxy/tool_util/verify/parse.py index fbf97610d97..65517c4f3ec 100644 --- a/lib/galaxy/tool_util/verify/parse.py +++ b/lib/galaxy/tool_util/verify/parse.py @@ -303,7 +303,7 @@ def _process_raw_inputs( location = param_extra.get("location") if param_type != "text": param_value = split_if_str(param_value) - if param_type == "data": + if param_type in ("data", "hidden_data"): if location and input_source.get_bool("multiple", False): # We get the input/s from the location which can be a list of urls separated by commas locations = split_if_str(location) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 3486e6e859f..e61342a467e 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2711,6 +2711,14 @@ class HiddenDataToolParameter(HiddenToolParameter, DataToolParameter): self.value = "None" self.type = "hidden_data" self.hidden = True + # hidden_data params are broken without optional="true" - the job runner's + # parameter validation rejects them when no dataset is provided. The only + # known tool using hidden_data (cufflinks) sets optional="true". + if not self.optional: + raise ParameterValueError( + 'hidden_data parameters must declare optional="true" to function correctly', + self.name, + ) class BaseJsonToolParameter(ToolParameter): diff --git a/test/functional/tools/parameters/gx_hidden_data.xml b/test/functional/tools/parameters/gx_hidden_data.xml new file mode 100644 index 00000000000..ed89987bda1 --- /dev/null +++ b/test/functional/tools/parameters/gx_hidden_data.xml @@ -0,0 +1,28 @@ + + > '$output' +#else +echo 'NO_DATA' >> '$output' +#end if + ]]> + + + + + + + + + + + + + + + + + + + + diff --git a/test/unit/tool_util/parameter_specification.yml b/test/unit/tool_util/parameter_specification.yml index e9c09d6fa8a..3f2c79ee7fa 100644 --- a/test/unit/tool_util/parameter_specification.yml +++ b/test/unit/tool_util/parameter_specification.yml @@ -1145,11 +1145,11 @@ gx_data: gx_data_optional: - request_valid: + request_valid: &data_optional_request_valid - parameter: {src: hda, id: abcdabcd} - parameter: null - {} - request_invalid: + request_invalid: &data_optional_request_invalid - parameter: {src: hda, id: 5} - parameter: {src: hdca, id: abcdabcd} - parameter: {src: fooda, id: abcdabcd} @@ -1158,11 +1158,11 @@ gx_data_optional: - parameter: true - parameter: 5 - parameter: "5" - request_internal_valid: + request_internal_valid: &data_optional_request_internal_valid - parameter: {src: hda, id: 5} - parameter: null - {} - request_internal_invalid: + request_internal_invalid: &data_optional_request_internal_invalid - parameter: {src: hda, id: abcdabcd} - parameter: {src: hdca, id: abcdabcd} - parameter: {src: fooda, id: abcdabcd} @@ -1171,32 +1171,46 @@ gx_data_optional: - parameter: true - parameter: 5 - parameter: "5" - job_internal_valid: + job_internal_valid: &data_optional_job_internal_valid - parameter: null - parameter: {src: hda, id: 5} - job_internal_invalid: + job_internal_invalid: &data_optional_job_internal_invalid - {} - workflow_step_valid: + workflow_step_valid: &data_optional_workflow_step_valid - {} - workflow_step_invalid: + workflow_step_invalid: &data_optional_workflow_step_invalid - {src: hda, id: abcdabcd} - {src: hda, id: 7} - parameter: {__class__: "Batch", values: [{src: hdca, id: 5}]} - parameter: {__class__: 'ConnectedValue'} - workflow_step_linked_valid: + workflow_step_linked_valid: &data_optional_workflow_step_linked_valid - {} - parameter: {__class__: 'ConnectedValue'} - workflow_step_linked_invalid: + workflow_step_linked_invalid: &data_optional_workflow_step_linked_invalid - {src: hda, id: abcdabcd} - {src: hda, id: 7} - parameter: {__class__: "Batch", values: [{src: hdca, id: 5}]} - parameter: {__class__: 'ConnectedValueX'} - test_case_xml_valid: + test_case_xml_valid: &data_optional_test_case_xml_valid - {} - parameter: {class: "File", path: "1.bed"} - test_case_xml_invalid: + test_case_xml_invalid: &data_optional_test_case_xml_invalid - parameter: {class: "NotAFile", path: "1.bed"} +gx_hidden_data: + request_valid: *data_optional_request_valid + request_invalid: *data_optional_request_invalid + request_internal_valid: *data_optional_request_internal_valid + request_internal_invalid: *data_optional_request_internal_invalid + job_internal_valid: *data_optional_job_internal_valid + job_internal_invalid: *data_optional_job_internal_invalid + workflow_step_valid: *data_optional_workflow_step_valid + workflow_step_invalid: *data_optional_workflow_step_invalid + workflow_step_linked_valid: *data_optional_workflow_step_linked_valid + workflow_step_linked_invalid: *data_optional_workflow_step_linked_invalid + test_case_xml_valid: *data_optional_test_case_xml_valid + test_case_xml_invalid: *data_optional_test_case_xml_invalid + gx_data_multiple: request_valid: - parameter: {src: hda, id: abcdabcd}