mirror of
https://github.com/ComposioHQ/composio.git
synced 2026-09-22 11:46:35 +08:00
fix: preserve nullability in null-only anyOf and fix validate param alias
Merge PR #3173 as the preferred fix for the null-only anyOf schema behavior and validate alias handling.
This commit is contained in:
@@ -234,6 +234,8 @@ def _handle_toplevel_combiner(
|
||||
allow_undefined_array_items=True,
|
||||
allow_undefined_type=True,
|
||||
)
|
||||
if result is type(None):
|
||||
return t.Optional[t.Any]
|
||||
# If result is a type (like a Union or Optional), return it directly
|
||||
# If result is a model class, return it
|
||||
return result
|
||||
@@ -270,7 +272,7 @@ def _build_union_from_options(options: t.List[t.Dict[str, t.Any]]) -> t.Type:
|
||||
pydantic_types.append(ptype)
|
||||
|
||||
if len(pydantic_types) == 0:
|
||||
return str # Fallback
|
||||
return t.Optional[t.Any] if has_null else str
|
||||
|
||||
if len(pydantic_types) == 1:
|
||||
base_type = pydantic_types[0]
|
||||
|
||||
@@ -210,9 +210,10 @@ def json_schema_to_pydantic_field(
|
||||
default = _coerce_default_value(default, json_schema)
|
||||
|
||||
# Check if the field name is a reserved Pydantic name
|
||||
original_name = name
|
||||
if name in reserved_names:
|
||||
name = f"{name}_"
|
||||
alias = name
|
||||
alias = original_name
|
||||
else:
|
||||
alias = None
|
||||
|
||||
@@ -222,7 +223,7 @@ def json_schema_to_pydantic_field(
|
||||
"alias": alias,
|
||||
}
|
||||
if not skip_default:
|
||||
field["default"] = ... if name in required else default
|
||||
field["default"] = ... if original_name in required else default
|
||||
|
||||
return (
|
||||
name,
|
||||
|
||||
@@ -121,7 +121,26 @@ class TestJsonSchemaToPydanticField:
|
||||
)
|
||||
|
||||
assert field_name == "validate_" # Should be renamed
|
||||
assert field_info.alias == "validate_" # Should have alias
|
||||
assert field_info.alias == "validate" # Should preserve original name
|
||||
|
||||
def test_reserved_required_field_name_preserves_required_status(self):
|
||||
"""Test that reserved field names keep the original alias and required status."""
|
||||
name = "validate"
|
||||
json_schema = {
|
||||
"type": "string",
|
||||
"description": "A required field with reserved name",
|
||||
"title": "Validate",
|
||||
}
|
||||
required = ["validate"]
|
||||
|
||||
field_name, field_type, field_info = json_schema_to_pydantic_field(
|
||||
name, json_schema, required
|
||||
)
|
||||
|
||||
assert field_name == "validate_"
|
||||
assert field_type is str
|
||||
assert field_info.alias == "validate"
|
||||
assert field_info.default is PydanticUndefined
|
||||
|
||||
def test_field_with_examples(self):
|
||||
"""Test that examples are properly preserved in field info."""
|
||||
@@ -394,6 +413,14 @@ class TestJsonSchemaToPydanticType:
|
||||
result = json_schema_to_pydantic_type(json_schema)
|
||||
assert result == expected_type
|
||||
|
||||
def test_anyof_null_only_preserves_nullability(self):
|
||||
"""Test that anyOf with only null maps to Optional[Any] instead of str."""
|
||||
result = json_schema_to_pydantic_type({"anyOf": [{"type": "null"}]})
|
||||
|
||||
assert t.get_origin(result) is t.Union
|
||||
assert t.Any in t.get_args(result)
|
||||
assert type(None) in t.get_args(result)
|
||||
|
||||
def test_array_type(self):
|
||||
"""Test array type conversion."""
|
||||
json_schema = {"type": "array", "items": {"type": "string"}}
|
||||
|
||||
Reference in New Issue
Block a user