feat: adds support for list of types

This commit is contained in:
2025-11-26 10:42:15 -03:00
parent 79e65b994e
commit d418ad96ad
4 changed files with 91 additions and 4 deletions

View File

@@ -73,9 +73,40 @@ 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]:

View File

@@ -1,4 +1,4 @@
from jambo.exceptions import InvalidSchemaException, UnsupportedSchemaException from jambo.exceptions import InternalAssertionException, InvalidSchemaException, UnsupportedSchemaException
from jambo.parser import ObjectTypeParser, RefTypeParser from jambo.parser import ObjectTypeParser, RefTypeParser
from jambo.types import JSONSchema, RefCacheDict from jambo.types import JSONSchema, RefCacheDict
@@ -135,5 +135,12 @@ class SchemaConverter:
""" """
if "$ref" in schema: if "$ref" in schema:
return "$ref" return "$ref"
type_value = schema.get("type")
if isinstance(type_value, list):
raise InternalAssertionException(
"SchemaConverter._get_schema_type: 'type' field should not be a list here."
" This should have been normalized earlier."
)
return schema.get("type") 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,52 @@ 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)