From 823842e57a6a6878223e60fb48055e4f2124bed6 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 8 Aug 2024 16:37:33 -0400 Subject: [PATCH] Validate wild static select with no options. --- lib/galaxy/tool_util/parameters/models.py | 7 +++-- .../tool_util/unittest_utils/parameters.py | 7 +++++ test/unit/tool_util/framework_tool_checks.yml | 8 +++++ .../tool_util/test_parameter_specification.py | 31 +++++++++++++++++-- 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 test/unit/tool_util/framework_tool_checks.yml diff --git a/lib/galaxy/tool_util/parameters/models.py b/lib/galaxy/tool_util/parameters/models.py index 131ee4d4c732..2571ff5c59f5 100644 --- a/lib/galaxy/tool_util/parameters/models.py +++ b/lib/galaxy/tool_util/parameters/models.py @@ -469,8 +469,11 @@ class SelectParameterModel(BaseGalaxyToolParameterModelDefinition): @property def py_type(self) -> Type: if self.options is not None: - literal_options: List[Type] = [cast_as_type(Literal[o.value]) for o in self.options] - py_type = union_type(literal_options) + if len(self.options) > 0: + literal_options: List[Type] = [cast_as_type(Literal[o.value]) for o in self.options] + py_type = union_type(literal_options) + else: + py_type = type(None) else: py_type = StrictStr if self.multiple: diff --git a/lib/galaxy/tool_util/unittest_utils/parameters.py b/lib/galaxy/tool_util/unittest_utils/parameters.py index 704a2ba15091..07ec28ffcb70 100644 --- a/lib/galaxy/tool_util/unittest_utils/parameters.py +++ b/lib/galaxy/tool_util/unittest_utils/parameters.py @@ -11,6 +11,7 @@ ToolSource, ) from galaxy.util import galaxy_directory +from . import functional_test_tool_path class ParameterBundle(ToolParameterBundle): @@ -23,6 +24,12 @@ def parameter_bundle(parameter: ToolParameterT) -> ParameterBundle: return ParameterBundle(parameter) +def parameter_bundle_for_framework_tool(filename: str) -> ToolParameterBundleModel: + path = functional_test_tool_path(filename) + tool_source = get_tool_source(path, macro_paths=[]) + return input_models_for_tool_source(tool_source) + + def parameter_bundle_for_file(filename: str) -> ToolParameterBundleModel: tool_source = parameter_tool_source(filename) return input_models_for_tool_source(tool_source) diff --git a/test/unit/tool_util/framework_tool_checks.yml b/test/unit/tool_util/framework_tool_checks.yml new file mode 100644 index 000000000000..c9a6cbf661df --- /dev/null +++ b/test/unit/tool_util/framework_tool_checks.yml @@ -0,0 +1,8 @@ +# file format mirrors parameters_specification.yml but applies to any tool in the older +# (and more general) test/functional/tools directory. + +empty_select: + request_valid: + - {} + request_invalid: + - select_optional: anyoption diff --git a/test/unit/tool_util/test_parameter_specification.py b/test/unit/tool_util/test_parameter_specification.py index 52fd285a9b8a..556a6f89d76e 100644 --- a/test/unit/tool_util/test_parameter_specification.py +++ b/test/unit/tool_util/test_parameter_specification.py @@ -4,6 +4,7 @@ Callable, Dict, List, + Optional, ) import yaml @@ -21,7 +22,10 @@ validate_test_case, ) from galaxy.tool_util.parameters.json import to_json_schema_string -from galaxy.tool_util.unittest_utils.parameters import parameter_bundle_for_file +from galaxy.tool_util.unittest_utils.parameters import ( + parameter_bundle_for_file, + parameter_bundle_for_framework_tool, +) from galaxy.util.resources import resource_string RawStateDict = Dict[str, Any] @@ -37,12 +41,31 @@ def specification_object(): return yaml.safe_load(yaml_str) +def framework_tool_checks(): + # Extend parameter_specification with some extra tests against existing framework tools. + # There is something beautiful about a targeted tool for every parameter feature but realistically + # we've been doing a version of the for a decade with tool tests and we can leverage those also. + try: + yaml_str = resource_string(__package__, "framework_tool_checks.yml") + except AttributeError: + # hack for the main() function below where this file is interpreted as part of the + # Galaxy tree. + yaml_str = open("test/unit/tool_util/framework_tool_checks.yml").read() + return yaml.safe_load(yaml_str) + + def test_specification(): parameter_spec = specification_object() for file in parameter_spec.keys(): _test_file(file, parameter_spec) +def test_framework_tool_checks(): + parameter_spec = framework_tool_checks() + for file in parameter_spec.keys(): + _test_file(file, parameter_spec, parameter_bundle_for_framework_tool(f"{file}.xml")) + + def test_single(): # _test_file("gx_int") # _test_file("gx_float") @@ -54,10 +77,12 @@ def test_single(): _test_file("gx_conditional_boolean_checked") -def _test_file(file: str, specification=None): +def _test_file(file: str, specification=None, parameter_bundle: Optional[ToolParameterBundleModel] = None): spec = specification or specification_object() combos = spec[file] - parameter_bundle: ToolParameterBundleModel = parameter_bundle_for_file(file) + if parameter_bundle is None: + parameter_bundle = parameter_bundle_for_file(file) + assert parameter_bundle assertion_functions = { "request_valid": _assert_requests_validate,