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.:]+
+
+
+
+
+
+
+
+
+