Spaces:
Running
Running
Jeremiah Lowin commited on
Ensure default fields are not marked nullable (#1224)
Browse files
src/fastmcp/utilities/json_schema_type.py
CHANGED
|
@@ -561,9 +561,7 @@ def _create_dataclass(
|
|
| 561 |
else:
|
| 562 |
field_def = field(default=None, metadata=meta)
|
| 563 |
|
| 564 |
-
if is_required
|
| 565 |
-
fields.append((field_name, field_type, field_def))
|
| 566 |
-
elif is_required:
|
| 567 |
fields.append((field_name, field_type, field_def))
|
| 568 |
else:
|
| 569 |
fields.append((field_name, Union[field_type, type(None)], field_def)) # type: ignore[misc] # noqa: UP007
|
|
|
|
| 561 |
else:
|
| 562 |
field_def = field(default=None, metadata=meta)
|
| 563 |
|
| 564 |
+
if is_required or default_val is not MISSING:
|
|
|
|
|
|
|
| 565 |
fields.append((field_name, field_type, field_def))
|
| 566 |
else:
|
| 567 |
fields.append((field_name, Union[field_type, type(None)], field_def)) # type: ignore[misc] # noqa: UP007
|
tests/utilities/test_json_schema_type.py
CHANGED
|
@@ -1523,3 +1523,58 @@ class TestAdditionalProperties:
|
|
| 1523 |
# Should be the same cached class
|
| 1524 |
assert Type1 is Type2
|
| 1525 |
assert issubclass(Type1, BaseModel)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1523 |
# Should be the same cached class
|
| 1524 |
assert Type1 is Type2
|
| 1525 |
assert issubclass(Type1, BaseModel)
|
| 1526 |
+
|
| 1527 |
+
|
| 1528 |
+
class TestFieldsWithDefaults:
|
| 1529 |
+
"""Test suite for fields with default values not being made nullable."""
|
| 1530 |
+
|
| 1531 |
+
def test_field_with_default_preserves_type(self):
|
| 1532 |
+
"""Test that fields with defaults preserve their original type."""
|
| 1533 |
+
schema = {
|
| 1534 |
+
"type": "object",
|
| 1535 |
+
"properties": {"flag": {"type": "boolean", "default": False}},
|
| 1536 |
+
}
|
| 1537 |
+
|
| 1538 |
+
generated_type = json_schema_to_type(schema)
|
| 1539 |
+
regenerated_schema = TypeAdapter(generated_type).json_schema()
|
| 1540 |
+
|
| 1541 |
+
assert regenerated_schema["properties"]["flag"]["type"] == "boolean"
|
| 1542 |
+
|
| 1543 |
+
def test_field_with_default_not_nullable(self):
|
| 1544 |
+
"""Test that fields with defaults are not made nullable."""
|
| 1545 |
+
schema = {
|
| 1546 |
+
"type": "object",
|
| 1547 |
+
"properties": {"flag": {"type": "boolean", "default": False}},
|
| 1548 |
+
}
|
| 1549 |
+
|
| 1550 |
+
generated_type = json_schema_to_type(schema)
|
| 1551 |
+
regenerated_schema = TypeAdapter(generated_type).json_schema()
|
| 1552 |
+
|
| 1553 |
+
flag_prop = regenerated_schema["properties"]["flag"]
|
| 1554 |
+
assert "anyOf" not in flag_prop
|
| 1555 |
+
|
| 1556 |
+
def test_field_with_default_uses_default(self):
|
| 1557 |
+
"""Test that fields with defaults use their default values."""
|
| 1558 |
+
schema = {
|
| 1559 |
+
"type": "object",
|
| 1560 |
+
"properties": {"flag": {"type": "boolean", "default": False}},
|
| 1561 |
+
}
|
| 1562 |
+
|
| 1563 |
+
generated_type = json_schema_to_type(schema)
|
| 1564 |
+
validator = TypeAdapter(generated_type)
|
| 1565 |
+
result = validator.validate_python({})
|
| 1566 |
+
|
| 1567 |
+
assert result.flag is False
|
| 1568 |
+
|
| 1569 |
+
def test_field_with_default_accepts_explicit_value(self):
|
| 1570 |
+
"""Test that fields with defaults accept explicit values."""
|
| 1571 |
+
schema = {
|
| 1572 |
+
"type": "object",
|
| 1573 |
+
"properties": {"flag": {"type": "boolean", "default": False}},
|
| 1574 |
+
}
|
| 1575 |
+
|
| 1576 |
+
generated_type = json_schema_to_type(schema)
|
| 1577 |
+
validator = TypeAdapter(generated_type)
|
| 1578 |
+
result = validator.validate_python({"flag": True})
|
| 1579 |
+
|
| 1580 |
+
assert result.flag is True
|