Implements: allOf, anyOf #11
@@ -50,8 +50,8 @@ class AnyOfTypeParser(GenericTypeParser):
|
|||||||
if not required:
|
if not required:
|
||||||
mapped_properties["default"] = mapped_properties.get("default")
|
mapped_properties["default"] = mapped_properties.get("default")
|
||||||
|
|
||||||
# By defining the type as Union, we can use the Field validator to enforce
|
# By defining the type as Union of Annotated type we can use the Field validator
|
||||||
# the constraints on the union type.
|
# to enforce the constraints of each union type when needed.
|
||||||
# We use Annotated to attach the Field validators to the type.
|
# We use Annotated to attach the Field validators to the type.
|
||||||
field_types = [Annotated[t, Field(**v)] if v else t for t, v in sub_types]
|
field_types = [Annotated[t, Field(**v)] if v else t for t, v in sub_types]
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class ArrayTypeParser(GenericTypeParser):
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrapper_type = set if properties.get("uniqueItems", False) else list
|
wrapper_type = set if properties.get("uniqueItems", False) else list
|
||||||
|
field_type = wrapper_type[_item_type]
|
||||||
|
|
||||||
mapped_properties = mappings_properties_builder(
|
mapped_properties = mappings_properties_builder(
|
||||||
properties,
|
properties,
|
||||||
@@ -37,24 +38,10 @@ class ArrayTypeParser(GenericTypeParser):
|
|||||||
|
|
||||||
default_list = properties.get("default")
|
default_list = properties.get("default")
|
||||||
if default_list is not None:
|
if default_list is not None:
|
||||||
if not isinstance(default_list, list):
|
ArrayTypeParser.validate_default(
|
||||||
raise ValueError(
|
field_type,
|
||||||
f"Default value must be a list, got {type(default_list).__name__}"
|
mapped_properties,
|
||||||
)
|
default_list,
|
||||||
|
|
||||||
if len(default_list) > properties.get("maxItems", float("inf")):
|
|
||||||
raise ValueError(
|
|
||||||
f"Default list exceeds maxItems limit of {properties.get('maxItems')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(default_list) < properties.get("minItems", 0):
|
|
||||||
raise ValueError(
|
|
||||||
f"Default list is below minItems limit of {properties.get('minItems')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not all(isinstance(item, _item_type) for item in default_list):
|
|
||||||
raise ValueError(
|
|
||||||
f"All items in the default list must be of type {_item_type.__name__}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if wrapper_type is list:
|
if wrapper_type is list:
|
||||||
@@ -69,4 +56,4 @@ class ArrayTypeParser(GenericTypeParser):
|
|||||||
if "default_factory" in mapped_properties and "default" in mapped_properties:
|
if "default_factory" in mapped_properties and "default" in mapped_properties:
|
||||||
del mapped_properties["default"]
|
del mapped_properties["default"]
|
||||||
|
|
||||||
return wrapper_type[_item_type], mapped_properties
|
return field_type, mapped_properties
|
||||||
|
|||||||
@@ -14,4 +14,11 @@ class BooleanTypeParser(GenericTypeParser):
|
|||||||
_mappings = {
|
_mappings = {
|
||||||
"default": "default",
|
"default": "default",
|
||||||
}
|
}
|
||||||
return bool, mappings_properties_builder(properties, _mappings)
|
|
||||||
|
mapped_properties = mappings_properties_builder(properties, _mappings, required)
|
||||||
|
|
||||||
|
default_value = properties.get("default")
|
||||||
|
if default_value is not None and not isinstance(default_value, bool):
|
||||||
|
raise ValueError(f"Default value for {name} must be a boolean.")
|
||||||
|
|
||||||
|
return bool, mapped_properties
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
from jambo.utils.properties_builder.numeric_properties_builder import (
|
from jambo.utils.properties_builder.mappings_properties_builder import (
|
||||||
numeric_properties_builder,
|
mappings_properties_builder,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -11,4 +11,18 @@ class FloatTypeParser(GenericTypeParser):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_properties(name, properties, required=False):
|
def from_properties(name, properties, required=False):
|
||||||
return float, numeric_properties_builder(properties, required)
|
_mappings = {
|
||||||
|
"minimum": "ge",
|
||||||
|
"exclusiveMinimum": "gt",
|
||||||
|
"maximum": "le",
|
||||||
|
"exclusiveMaximum": "lt",
|
||||||
|
"multipleOf": "multiple_of",
|
||||||
|
"default": "default",
|
||||||
|
}
|
||||||
|
mapped_properties = mappings_properties_builder(properties, _mappings, required)
|
||||||
|
|
||||||
|
default_value = mapped_properties.get("default")
|
||||||
|
if default_value is not None:
|
||||||
|
FloatTypeParser.validate_default(float, mapped_properties, default_value)
|
||||||
|
|
||||||
|
return float, mapped_properties
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
from jambo.utils.properties_builder.numeric_properties_builder import (
|
from jambo.utils.properties_builder.mappings_properties_builder import (
|
||||||
numeric_properties_builder,
|
mappings_properties_builder,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -11,4 +11,18 @@ class IntTypeParser(GenericTypeParser):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_properties(name, properties, required=False):
|
def from_properties(name, properties, required=False):
|
||||||
return int, numeric_properties_builder(properties, required)
|
_mappings = {
|
||||||
|
"minimum": "ge",
|
||||||
|
"exclusiveMinimum": "gt",
|
||||||
|
"maximum": "le",
|
||||||
|
"exclusiveMaximum": "lt",
|
||||||
|
"multipleOf": "multiple_of",
|
||||||
|
"default": "default",
|
||||||
|
}
|
||||||
|
mapped_properties = mappings_properties_builder(properties, _mappings, required)
|
||||||
|
|
||||||
|
default_value = mapped_properties.get("default")
|
||||||
|
if default_value is not None:
|
||||||
|
IntTypeParser.validate_default(int, mapped_properties, default_value)
|
||||||
|
|
||||||
|
return int, mapped_properties
|
||||||
|
|||||||
@@ -66,38 +66,25 @@ class TestArrayTypeParser(TestCase):
|
|||||||
|
|
||||||
properties = {"items": {"type": "string"}, "default": ["a", 1, "c"]}
|
properties = {"items": {"type": "string"}, "default": ["a", 1, "c"]}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"All items in the default list must be of type str",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_array_parser_with_invalid_default_type(self):
|
def test_array_parser_with_invalid_default_type(self):
|
||||||
parser = ArrayTypeParser()
|
parser = ArrayTypeParser()
|
||||||
|
|
||||||
properties = {"items": {"type": "string"}, "default": "not_a_list"}
|
properties = {"items": {"type": "string"}, "default": "not_a_list"}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception), "Default value must be a list, got str"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_array_parser_with_invalid_default_min(self):
|
def test_array_parser_with_invalid_default_min(self):
|
||||||
parser = ArrayTypeParser()
|
parser = ArrayTypeParser()
|
||||||
|
|
||||||
properties = {"items": {"type": "string"}, "default": ["a"], "minItems": 2}
|
properties = {"items": {"type": "string"}, "default": ["a"], "minItems": 2}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception), "Default list is below minItems limit of 2"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_array_parser_with_invalid_default_max(self):
|
def test_array_parser_with_invalid_default_max(self):
|
||||||
parser = ArrayTypeParser()
|
parser = ArrayTypeParser()
|
||||||
|
|
||||||
@@ -107,9 +94,5 @@ class TestArrayTypeParser(TestCase):
|
|||||||
"maxItems": 3,
|
"maxItems": 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception), "Default list exceeds maxItems limit of 3"
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -61,14 +61,9 @@ class TestFloatTypeParser(TestCase):
|
|||||||
"multipleOf": 0.5,
|
"multipleOf": 0.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value must be a number, got str",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_float_parser_with_default_invalid_maximum(self):
|
def test_float_parser_with_default_invalid_maximum(self):
|
||||||
parser = FloatTypeParser()
|
parser = FloatTypeParser()
|
||||||
|
|
||||||
@@ -80,14 +75,9 @@ class TestFloatTypeParser(TestCase):
|
|||||||
"multipleOf": 0.5,
|
"multipleOf": 0.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value exceeds maximum limit of 10.5",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_float_parser_with_default_invalid_minimum(self):
|
def test_float_parser_with_default_invalid_minimum(self):
|
||||||
parser = FloatTypeParser()
|
parser = FloatTypeParser()
|
||||||
|
|
||||||
@@ -99,14 +89,9 @@ class TestFloatTypeParser(TestCase):
|
|||||||
"multipleOf": 0.5,
|
"multipleOf": 0.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value is below minimum limit of 1.0",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_float_parser_with_default_invalid_exclusive_maximum(self):
|
def test_float_parser_with_default_invalid_exclusive_maximum(self):
|
||||||
parser = FloatTypeParser()
|
parser = FloatTypeParser()
|
||||||
|
|
||||||
@@ -118,14 +103,9 @@ class TestFloatTypeParser(TestCase):
|
|||||||
"multipleOf": 0.5,
|
"multipleOf": 0.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value exceeds exclusive maximum limit of 10.5",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_float_parser_with_default_invalid_exclusive_minimum(self):
|
def test_float_parser_with_default_invalid_exclusive_minimum(self):
|
||||||
parser = FloatTypeParser()
|
parser = FloatTypeParser()
|
||||||
|
|
||||||
@@ -137,14 +117,9 @@ class TestFloatTypeParser(TestCase):
|
|||||||
"multipleOf": 0.5,
|
"multipleOf": 0.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value is below exclusive minimum limit of 1.0",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_float_parser_with_default_invalid_multiple(self):
|
def test_float_parser_with_default_invalid_multiple(self):
|
||||||
parser = FloatTypeParser()
|
parser = FloatTypeParser()
|
||||||
|
|
||||||
@@ -156,10 +131,5 @@ class TestFloatTypeParser(TestCase):
|
|||||||
"multipleOf": 2.0,
|
"multipleOf": 2.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value 5.0 is not a multiple of 2.0",
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -61,14 +61,9 @@ class TestIntTypeParser(TestCase):
|
|||||||
"multipleOf": 2,
|
"multipleOf": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value must be a number, got str",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_int_parser_with_default_invalid_maximum(self):
|
def test_int_parser_with_default_invalid_maximum(self):
|
||||||
parser = IntTypeParser()
|
parser = IntTypeParser()
|
||||||
|
|
||||||
@@ -80,14 +75,9 @@ class TestIntTypeParser(TestCase):
|
|||||||
"multipleOf": 2,
|
"multipleOf": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value exceeds maximum limit of 10",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_int_parser_with_default_invalid_minimum(self):
|
def test_int_parser_with_default_invalid_minimum(self):
|
||||||
parser = IntTypeParser()
|
parser = IntTypeParser()
|
||||||
|
|
||||||
@@ -99,14 +89,9 @@ class TestIntTypeParser(TestCase):
|
|||||||
"multipleOf": 2,
|
"multipleOf": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value is below minimum limit of 1",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_int_parser_with_default_invalid_exclusive_maximum(self):
|
def test_int_parser_with_default_invalid_exclusive_maximum(self):
|
||||||
parser = IntTypeParser()
|
parser = IntTypeParser()
|
||||||
|
|
||||||
@@ -118,14 +103,9 @@ class TestIntTypeParser(TestCase):
|
|||||||
"multipleOf": 2,
|
"multipleOf": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value exceeds exclusive maximum limit of 10",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_int_parser_with_default_invalid_exclusive_minimum(self):
|
def test_int_parser_with_default_invalid_exclusive_minimum(self):
|
||||||
parser = IntTypeParser()
|
parser = IntTypeParser()
|
||||||
|
|
||||||
@@ -137,14 +117,9 @@ class TestIntTypeParser(TestCase):
|
|||||||
"multipleOf": 2,
|
"multipleOf": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value is below exclusive minimum limit of 1",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_int_parser_with_default_invalid_multipleOf(self):
|
def test_int_parser_with_default_invalid_multipleOf(self):
|
||||||
parser = IntTypeParser()
|
parser = IntTypeParser()
|
||||||
|
|
||||||
@@ -156,10 +131,5 @@ class TestIntTypeParser(TestCase):
|
|||||||
"multipleOf": 2,
|
"multipleOf": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError):
|
||||||
parser.from_properties("placeholder", properties)
|
parser.from_properties("placeholder", properties)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Default value 5 is not a multiple of 2",
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user