feat: adds support for list of types #66

Merged
HideyoshiNakazone merged 3 commits from feature/support-type-list into main 2025-11-26 13:55:32 +00:00
4 changed files with 91 additions and 4 deletions
Showing only changes of commit d418ad96ad - Show all commits

View File

@@ -73,10 +73,41 @@ 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

@@ -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
@@ -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 InternalAssertionException(
"SchemaConverter._get_schema_type: 'type' field should not be a list here."
" This should have been normalized earlier."
)
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)