diff --git a/lib/galaxy/tool_util/parameters/convert.py b/lib/galaxy/tool_util/parameters/convert.py index f5e5970f769..b2d544c541c 100644 --- a/lib/galaxy/tool_util/parameters/convert.py +++ b/lib/galaxy/tool_util/parameters/convert.py @@ -195,14 +195,14 @@ def strictify(relaxed_state: RelaxedRequestToolState, input_models: ToolParamete if not parameter.optional: # restore legacy behavior of allowing empty string implicit default # for these non-optional inputs. - tool_state[parameter_name] = "" + tool_state[parameter_name] = parameter.default_value if parameter.default_value is not None else "" else: - tool_state[parameter_name] = None + tool_state[parameter_name] = parameter.default_value else: # legacy behavior of converting explicit None into implicit null. We should introduce # a layer somewhere to deal with this behavior further up the stack and clean up these models. if not parameter.optional and tool_state[parameter_name] is None: - tool_state[parameter_name] = "" + tool_state[parameter_name] = parameter.default_value if parameter.default_value is not None else "" def _strictify_parameters(tool_state: Dict[str, Any], input_models: ToolParameterBundle) -> None: for parameter in input_models.parameters: @@ -399,14 +399,14 @@ def _fill_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT) -> if not parameter.optional: # restore legacy behavior of allowing empty string implicit default # for these non-optional inputs. - tool_state[parameter_name] = parameter.default_value or "" + tool_state[parameter_name] = parameter.default_value if parameter.default_value is not None else "" else: - tool_state[parameter_name] = parameter.default_value or None + tool_state[parameter_name] = parameter.default_value else: # legacy behavior of converting explicit None into implicit null. We should introduce # a layer somewhere to deal with this behavior further up the stack and clean up these models. if not parameter.optional and tool_state[parameter_name] is None: - tool_state[parameter_name] = parameter.default_value or "" + tool_state[parameter_name] = parameter.default_value if parameter.default_value is not None else "" def _initialize_section_state(parameter: SectionParameterModel, tool_state: Dict[str, Any]) -> Dict[str, Any]: diff --git a/lib/galaxy_test/api/test_tool_execute.py b/lib/galaxy_test/api/test_tool_execute.py index 8d776d74519..5a430c49e38 100644 --- a/lib/galaxy_test/api/test_tool_execute.py +++ b/lib/galaxy_test/api/test_tool_execute.py @@ -735,15 +735,58 @@ def test_null_to_text_tool_with_validation(required_tool: RequiredTool, tool_inp required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": ""})).assert_fails() +@requires_tool_id("gx_text_optional_with_empty_default") +def test_optional_text_with_empty_default(required_tool: RequiredTool, tool_input_format: DescribeToolInputs): + # absent — all formats resolve to value="" default + execute = required_tool.execute().with_inputs(tool_input_format.when.any({})) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": ""}) + + # explicit null + execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": None})) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": None}) + + # explicit empty string + execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": ""})) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": ""}) + + # provided value + execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": "hello"})) + execute.assert_has_single_job.with_output("output").with_contents_stripped("hello") + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": "hello"}) + + @requires_tool_id("gx_text_optional_regex_validation") def test_optional_text_with_regex_validation(required_tool: RequiredTool, tool_input_format: DescribeToolInputs): - # absent param — legacy/21.01 resolve to value="" default, runtime skips regex for empty optional + # absent — no value="" default so all formats treat as None execute = required_tool.execute().with_inputs(tool_input_format.when.any({})) - execute.assert_has_single_job.with_output("inputs_json").with_json( - {"parameter": None} if tool_input_format.is_request else {"parameter": ""} - ) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": None}) - # explicit null — all formats treat as "not provided" for optional + # explicit null + execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": None})) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": None}) + + # explicit empty string — optional so skip regex validation, "" stays as "" + execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": ""})) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": ""}) + + # valid value + execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": "0.5"})) + execute.assert_has_single_job.with_output("output").with_contents_stripped("0.5") + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": "0.5"}) + + # invalid value should fail regardless of format + required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": "abc"})).assert_fails() + + +@requires_tool_id("gx_text_optional_with_empty_default_regex_validation") +def test_optional_text_with_empty_default_with_regex_validation( + required_tool: RequiredTool, tool_input_format: DescribeToolInputs +): + # absent — all formats resolve to value="" default + execute = required_tool.execute().with_inputs(tool_input_format.when.any({})) + execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": ""}) + + # explicit null execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": None})) execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": None}) @@ -751,7 +794,7 @@ def test_optional_text_with_regex_validation(required_tool: RequiredTool, tool_i execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": ""})) execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": ""}) - # valid value should pass all formats + # valid value execute = required_tool.execute().with_inputs(tool_input_format.when.any({"parameter": "0.5"})) execute.assert_has_single_job.with_output("output").with_contents_stripped("0.5") execute.assert_has_single_job.with_output("inputs_json").with_json({"parameter": "0.5"}) diff --git a/test/functional/tools/parameters/gx_text_optional_regex_validation.xml b/test/functional/tools/parameters/gx_text_optional_regex_validation.xml index 514b8c5389c..0c0d432092d 100644 --- a/test/functional/tools/parameters/gx_text_optional_regex_validation.xml +++ b/test/functional/tools/parameters/gx_text_optional_regex_validation.xml @@ -7,7 +7,7 @@ cat '$inputs' >> $inputs_json; - + [0-9.:]+ diff --git a/test/functional/tools/parameters/gx_text_optional_with_empty_default.xml b/test/functional/tools/parameters/gx_text_optional_with_empty_default.xml new file mode 100644 index 00000000000..2c9ae2fd65c --- /dev/null +++ b/test/functional/tools/parameters/gx_text_optional_with_empty_default.xml @@ -0,0 +1,18 @@ + + > '$output'; +cat '$inputs' >> $inputs_json; + ]]> + + + + + + + + + + + + + diff --git a/test/functional/tools/parameters/gx_text_optional_with_empty_default_regex_validation.xml b/test/functional/tools/parameters/gx_text_optional_with_empty_default_regex_validation.xml new file mode 100644 index 00000000000..936e5d7ac72 --- /dev/null +++ b/test/functional/tools/parameters/gx_text_optional_with_empty_default_regex_validation.xml @@ -0,0 +1,20 @@ + + > '$output'; +cat '$inputs' >> $inputs_json; + ]]> + + + + + + [0-9.:]+ + + + + + + + + +