Merge pull request #66 from HideyoshiNakazone/feature/support-type-list

feat: adds support for list of types
This commit was merged in pull request #66.
This commit is contained in:
2025-11-26 10:55:32 -03:00
committed by GitHub
4 changed files with 82 additions and 3 deletions

View File

@@ -73,10 +73,39 @@ class GenericTypeParser(ABC, Generic[T]):
:param kwargs: Additional options for type parsing. :param kwargs: Additional options for type parsing.
:return: A tuple containing the type and its properties. :return: A tuple containing the type and its properties.
""" """
parser = cls._get_impl(properties)
parser = cls._get_impl(cls._normalize_properties(properties))
return parser().from_properties(name=name, properties=properties, **kwargs) return parser().from_properties(name=name, properties=properties, **kwargs)
@staticmethod
def _normalize_properties(properties: JSONSchema) -> JSONSchema:
"""
Normalizes the properties dictionary to ensure consistent structure.
:param properties: The properties to be normalized.
"""
type_value = properties.pop("type", None)
if isinstance(type_value, str):
properties["type"] = type_value
return properties
if isinstance(type_value, list) and len(type_value) == 0:
raise InvalidSchemaException(
"Invalid schema: 'type' list cannot be empty",
invalid_field=str(properties),
)
if isinstance(type_value, list) and len(type_value) == 1:
properties["type"] = type_value[0]
return properties
if isinstance(type_value, list):
properties["anyOf"] = [{"type": t} for t in type_value]
return properties
return properties
@classmethod @classmethod
def _get_impl(cls, properties: JSONSchema) -> type[Self]: def _get_impl(cls, properties: JSONSchema) -> type[Self]:
for subcls in cls.__subclasses__(): for subcls in cls.__subclasses__():

View File

@@ -136,4 +136,11 @@ class SchemaConverter:
if "$ref" in schema: if "$ref" in schema:
return "$ref" return "$ref"
return schema.get("type") type_value = schema.get("type")
if isinstance(type_value, list):
raise InvalidSchemaException(
"Invalid schema: 'type' cannot be a list at the top level",
invalid_field=str(schema),
)
return type_value

View File

@@ -42,7 +42,7 @@ JSONSchema = TypedDict(
"description": str, "description": str,
"default": JSONType, "default": JSONType,
"examples": List[JSONType], "examples": List[JSONType],
"type": JSONSchemaType, "type": JSONSchemaType | List[JSONSchemaType],
"enum": List[JSONType], "enum": List[JSONType],
"const": JSONType, "const": JSONType,
"properties": Dict[str, "JSONSchema"], "properties": Dict[str, "JSONSchema"],

View File

@@ -998,3 +998,46 @@ class TestSchemaConverter(TestCase):
cached_address_model = self.converter.get_cached_ref("address") cached_address_model = self.converter.get_cached_ref("address")
self.assertIsNotNone(cached_address_model) self.assertIsNotNone(cached_address_model)
def test_parse_list_type_multiple_values(self):
schema = {
"title": "TestListType",
"type": "object",
"properties": {"values": {"type": ["string", "number"]}},
}
Model = self.converter.build_with_cache(schema)
obj1 = Model(values="a string")
self.assertEqual(obj1.values, "a string")
obj2 = Model(values=42)
self.assertEqual(obj2.values, 42)
def test_parse_list_type_one_value(self):
schema = {
"title": "TestListType",
"type": "object",
"properties": {"values": {"type": ["string"]}},
}
Model = self.converter.build_with_cache(schema)
obj1 = Model(values="a string")
self.assertEqual(obj1.values, "a string")
def test_parse_list_type_empty(self):
schema = {
"title": "TestListType",
"type": "object",
"properties": {"values": {"type": []}},
}
with self.assertRaises(InvalidSchemaException):
self.converter.build_with_cache(schema)
def test_parse_list_type_root_level_throws(self):
schema = {"title": "TestListType", "type": ["string", "number"]}
with self.assertRaises(InvalidSchemaException):
self.converter.build_with_cache(schema)