from typing import Optional from enum import Enum from pydantic import BaseModel, Field from comfy.comfy_types.node_typing import IO from comfy_api_nodes.mapper_utils import model_field_to_node_input def test_model_field_to_float_input(): """Tests mapping a float field with constraints.""" class ModelWithFloatField(BaseModel): cfg_scale: Optional[float] = Field( default=0.5, description="Flexibility in video generation", ge=0.0, le=1.0, multiple_of=0.001, ) expected_output = ( IO.FLOAT, { "default": 0.5, "tooltip": "Flexibility in video generation", "min": 0.0, "max": 1.0, "step": 0.001, }, ) actual_output = model_field_to_node_input( IO.FLOAT, ModelWithFloatField, "cfg_scale" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_float_input_no_constraints(): """Tests mapping a float field with no constraints.""" class ModelWithFloatField(BaseModel): cfg_scale: Optional[float] = Field(default=0.5) expected_output = ( IO.FLOAT, { "default": 0.5, }, ) actual_output = model_field_to_node_input( IO.FLOAT, ModelWithFloatField, "cfg_scale" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_int_input(): """Tests mapping an int field with constraints.""" class ModelWithIntField(BaseModel): num_frames: Optional[int] = Field( default=10, description="Number of frames to generate", ge=1, le=100, multiple_of=1, ) expected_output = ( IO.INT, { "default": 10, "tooltip": "Number of frames to generate", "min": 1, "max": 100, "step": 1, }, ) actual_output = model_field_to_node_input(IO.INT, ModelWithIntField, "num_frames") assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_string_input(): """Tests mapping a string field.""" class ModelWithStringField(BaseModel): prompt: Optional[str] = Field( default="A beautiful sunset over a calm ocean", description="A prompt for the video generation", ) expected_output = ( IO.STRING, { "default": "A beautiful sunset over a calm ocean", "tooltip": "A prompt for the video generation", }, ) actual_output = model_field_to_node_input(IO.STRING, ModelWithStringField, "prompt") assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_string_input_multiline(): """Tests mapping a string field.""" class ModelWithStringField(BaseModel): prompt: Optional[str] = Field( default="A beautiful sunset over a calm ocean", description="A prompt for the video generation", ) expected_output = ( IO.STRING, { "default": "A beautiful sunset over a calm ocean", "tooltip": "A prompt for the video generation", "multiline": True, }, ) actual_output = model_field_to_node_input( IO.STRING, ModelWithStringField, "prompt", multiline=True ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_combo_input(): """Tests mapping a combo field.""" class MockEnum(str, Enum): option_1 = "option 1" option_2 = "option 2" option_3 = "option 3" class ModelWithComboField(BaseModel): model_name: Optional[MockEnum] = Field("option 1", description="Model Name") expected_output = ( IO.COMBO, { "options": ["option 1", "option 2", "option 3"], "default": "option 1", "tooltip": "Model Name", }, ) actual_output = model_field_to_node_input( IO.COMBO, ModelWithComboField, "model_name", enum_type=MockEnum ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_combo_input_no_options(): """Tests mapping a combo field with no options.""" class ModelWithComboField(BaseModel): model_name: Optional[str] = Field(description="Model Name") expected_output = ( IO.COMBO, { "tooltip": "Model Name", }, ) actual_output = model_field_to_node_input( IO.COMBO, ModelWithComboField, "model_name" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_image_input(): """Tests mapping an image field.""" class ModelWithImageField(BaseModel): image: Optional[str] = Field( default=None, description="An image for the video generation", ) expected_output = ( IO.IMAGE, { "default": None, "tooltip": "An image for the video generation", }, ) actual_output = model_field_to_node_input(IO.IMAGE, ModelWithImageField, "image") assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_node_input_no_description(): """Tests mapping a field with no description.""" class ModelWithNoDescriptionField(BaseModel): field: Optional[str] = Field(default="default value") expected_output = ( IO.STRING, { "default": "default value", }, ) actual_output = model_field_to_node_input( IO.STRING, ModelWithNoDescriptionField, "field" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_node_input_no_default(): """Tests mapping a field with no default.""" class ModelWithNoDefaultField(BaseModel): field: Optional[str] = Field(description="A field with no default") expected_output = ( IO.STRING, { "tooltip": "A field with no default", }, ) actual_output = model_field_to_node_input( IO.STRING, ModelWithNoDefaultField, "field" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_node_input_no_metadata(): """Tests mapping a field with no metadata or properties defined on the schema.""" class ModelWithNoMetadataField(BaseModel): field: Optional[str] = Field() expected_output = ( IO.STRING, {}, ) actual_output = model_field_to_node_input( IO.STRING, ModelWithNoMetadataField, "field" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1] def test_model_field_to_node_input_default_is_none(): """ Tests mapping a field with a default of `None`. I.e., the default field should be included as the schema explicitly sets it to `None`. """ class ModelWithNoneDefaultField(BaseModel): field: Optional[str] = Field( default=None, description="A field with a default of None" ) expected_output = ( IO.STRING, { "default": None, "tooltip": "A field with a default of None", }, ) actual_output = model_field_to_node_input( IO.STRING, ModelWithNoneDefaultField, "field" ) assert actual_output[0] == expected_output[0] assert actual_output[1] == expected_output[1]