From 72fb8d4ce9bf51b166d6807ba49e2bc3710e2db6 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 22 Jul 2025 09:14:15 -0400 Subject: [PATCH] Ensure default fields are not marked nullable (#1224) --- src/fastmcp/utilities/json_schema_type.py | 4 +- tests/utilities/test_json_schema_type.py | 55 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/fastmcp/utilities/json_schema_type.py b/src/fastmcp/utilities/json_schema_type.py index ff5ab4102..62577402b 100644 --- a/src/fastmcp/utilities/json_schema_type.py +++ b/src/fastmcp/utilities/json_schema_type.py @@ -561,9 +561,7 @@ def _create_dataclass( else: field_def = field(default=None, metadata=meta) - if is_required and default_val is not MISSING: - fields.append((field_name, field_type, field_def)) - elif is_required: + if is_required or default_val is not MISSING: fields.append((field_name, field_type, field_def)) else: fields.append((field_name, Union[field_type, type(None)], field_def)) # type: ignore[misc] # noqa: UP007 diff --git a/tests/utilities/test_json_schema_type.py b/tests/utilities/test_json_schema_type.py index ca8cd11b6..8cb9ca90a 100644 --- a/tests/utilities/test_json_schema_type.py +++ b/tests/utilities/test_json_schema_type.py @@ -1523,3 +1523,58 @@ class TestAdditionalProperties: # Should be the same cached class assert Type1 is Type2 assert issubclass(Type1, BaseModel) + + +class TestFieldsWithDefaults: + """Test suite for fields with default values not being made nullable.""" + + def test_field_with_default_preserves_type(self): + """Test that fields with defaults preserve their original type.""" + schema = { + "type": "object", + "properties": {"flag": {"type": "boolean", "default": False}}, + } + + generated_type = json_schema_to_type(schema) + regenerated_schema = TypeAdapter(generated_type).json_schema() + + assert regenerated_schema["properties"]["flag"]["type"] == "boolean" + + def test_field_with_default_not_nullable(self): + """Test that fields with defaults are not made nullable.""" + schema = { + "type": "object", + "properties": {"flag": {"type": "boolean", "default": False}}, + } + + generated_type = json_schema_to_type(schema) + regenerated_schema = TypeAdapter(generated_type).json_schema() + + flag_prop = regenerated_schema["properties"]["flag"] + assert "anyOf" not in flag_prop + + def test_field_with_default_uses_default(self): + """Test that fields with defaults use their default values.""" + schema = { + "type": "object", + "properties": {"flag": {"type": "boolean", "default": False}}, + } + + generated_type = json_schema_to_type(schema) + validator = TypeAdapter(generated_type) + result = validator.validate_python({}) + + assert result.flag is False + + def test_field_with_default_accepts_explicit_value(self): + """Test that fields with defaults accept explicit values.""" + schema = { + "type": "object", + "properties": {"flag": {"type": "boolean", "default": False}}, + } + + generated_type = json_schema_to_type(schema) + validator = TypeAdapter(generated_type) + result = validator.validate_python({"flag": True}) + + assert result.flag is True