feat: adds support for list of types #66
@@ -73,9 +73,40 @@ class GenericTypeParser(ABC, Generic[T]):
|
||||
:param kwargs: Additional options for type parsing.
|
||||
: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)
|
||||
|
||||
@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
|
||||
def _get_impl(cls, properties: JSONSchema) -> type[Self]:
|
||||
|
||||
@@ -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.types import JSONSchema, RefCacheDict
|
||||
|
||||
@@ -135,5 +135,12 @@ class SchemaConverter:
|
||||
"""
|
||||
if "$ref" in schema:
|
||||
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
|
||||
|
||||
@@ -42,7 +42,7 @@ JSONSchema = TypedDict(
|
||||
"description": str,
|
||||
"default": JSONType,
|
||||
"examples": List[JSONType],
|
||||
"type": JSONSchemaType,
|
||||
"type": JSONSchemaType|List[JSONSchemaType],
|
||||
"enum": List[JSONType],
|
||||
"const": JSONType,
|
||||
"properties": Dict[str, "JSONSchema"],
|
||||
|
||||
@@ -998,3 +998,52 @@ class TestSchemaConverter(TestCase):
|
||||
cached_address_model = self.converter.get_cached_ref("address")
|
||||
|
||||
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)
|
||||
Reference in New Issue
Block a user