From 384dfc8b4e030eea3a6606dd8e010af387cdeaa8 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Fri, 3 Jan 2025 15:52:19 +0200 Subject: [PATCH] Make conditional discriminators literals instead of generic string/bool That's a much better consumer experience. A model generated for gx_conditional.xml would look like ```typescript export type ConditionalType = | WhenTestParameterA | WhenTestParameterB | WhenTestParameterC export type TestParameter = "a" export type IntegerParameter = number export type TestParameter1 = "b" export type BooleanParameter = boolean export type TestParameter2 = "c" export type ColorParameter = string export interface MySchema { conditional_parameter: ConditionalType } export interface WhenTestParameterA { test_parameter: TestParameter integer_parameter: IntegerParameter } export interface WhenTestParameterB { test_parameter: TestParameter1 boolean_parameter: BooleanParameter } export interface WhenTestParameterC { test_parameter: TestParameter2 color_parameter: ColorParameter } ``` instead of ```typescript export type ConditionalType = | WhenTestParameterA | WhenTestParameterB | WhenTestParameterC export type TestParameter = string | boolean export type IntegerParameter = number export type TestParameter1 = string | boolean export type BooleanParameter = boolean export type TestParameter2 = string | boolean export type ColorParameter = string export interface MySchema { conditional_parameter: ConditionalType } export interface WhenTestParameterA { test_parameter: TestParameter integer_parameter: IntegerParameter } export interface WhenTestParameterB { test_parameter: TestParameter1 boolean_parameter: BooleanParameter } export interface WhenTestParameterC { test_parameter: TestParameter2 color_parameter: ColorParameter } ``` With the new model I can write an input object without looking at the tool source, with the previous one I don't know what string I would need to supply. --- lib/galaxy/tool_util/parameters/models.py | 2 +- test/unit/tool_util/test_parameter_specification.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/tool_util/parameters/models.py b/lib/galaxy/tool_util/parameters/models.py index d0e7e6bbcb8f..1feae64168f2 100644 --- a/lib/galaxy/tool_util/parameters/models.py +++ b/lib/galaxy/tool_util/parameters/models.py @@ -1099,7 +1099,7 @@ def pydantic_template(self, state_representation: StateRepresentationT) -> Dynam else: initialize_test = None tag = str(discriminator) if not is_boolean else str(discriminator).lower() - extra_kwd = {test_param_name: (Union[str, bool], initialize_test)} + extra_kwd = {test_param_name: (Literal[when.discriminator], initialize_test)} when_types.append( cast( Type[BaseModel], diff --git a/test/unit/tool_util/test_parameter_specification.py b/test/unit/tool_util/test_parameter_specification.py index 41ec1fc9a95a..0096f2c102e7 100644 --- a/test/unit/tool_util/test_parameter_specification.py +++ b/test/unit/tool_util/test_parameter_specification.py @@ -28,7 +28,10 @@ validate_workflow_step_linked, ValidationFunctionT, ) -from galaxy.tool_util.parameters.json import to_json_schema_string +from galaxy.tool_util.parameters.json import ( + to_json_schema, + to_json_schema_string, +) from galaxy.tool_util.unittest_utils.parameters import ( parameter_bundle_for_file, parameter_bundle_for_framework_tool, @@ -223,7 +226,11 @@ def test_decode_gx_int(): def test_json_schema_for_conditional(): input_bundle = parameter_bundle_for_file("gx_conditional_boolean") tool_state = RequestToolState.parameter_model_for(input_bundle) - print(to_json_schema_string(tool_state)) + json_schema = to_json_schema(tool_state) + assert json_schema["$defs"]["When_test_parameter_False"]["properties"]["test_parameter"]["const"] is False + assert json_schema["$defs"]["When_test_parameter_True"]["properties"]["test_parameter"]["const"] is True + assert "test_parameter" not in json_schema["$defs"]["When_test_parameter___absent"]["properties"] + assert to_json_schema_string(tool_state) def test_encode_gx_data(): @@ -244,7 +251,7 @@ def encode_val(val: int) -> str: parameter_models_json = {} for file in parameter_spec.keys(): tool_parameter_model = parameter_bundle_for_file(file) - parameter_models_json[file] = tool_parameter_model.dict() + parameter_models_json[file] = tool_parameter_model.model_dump() yaml_str = yaml.safe_dump(parameter_models_json) with open("client/src/components/Tool/parameter_models.yml", "w") as f: f.write("# auto generated file for JavaScript testing, do not modify manually\n")