Implements: allOf, anyOf #11
@@ -1,11 +1,11 @@
|
||||
# Exports generic type parser
|
||||
from ._type_parser import GenericTypeParser as GenericTypeParser
|
||||
from .allof_type_parser import AllOfTypeParser as AllOfTypeParser
|
||||
from .array_type_parser import ArrayTypeParser as ArrayTypeParser
|
||||
from .boolean_type_parser import BooleanTypeParser as BooleanTypeParser
|
||||
from .float_type_parser import FloatTypeParser as FloatTypeParser
|
||||
|
||||
# Exports Implementations
|
||||
from .int_type_parser import IntTypeParser as IntTypeParser
|
||||
from .object_type_parser import ObjectTypeParser as ObjectTypeParser
|
||||
from .string_type_parser import StringTypeParser as StringTypeParser
|
||||
from .array_type_parser import ArrayTypeParser as ArrayTypeParser
|
||||
from .boolean_type_parser import BooleanTypeParser as BooleanTypeParser
|
||||
from .float_type_parser import FloatTypeParser as FloatTypeParser
|
||||
from .allof_type_parser import AllOfTypeParser as AllOfTypeParser
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Generic, TypeVar
|
||||
from pydantic import Field
|
||||
from typing_extensions import Self
|
||||
|
||||
from pydantic import Field
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import copy
|
||||
|
||||
from jambo.parser._type_parser import GenericTypeParser
|
||||
|
||||
from typing import TypeVar
|
||||
|
||||
from jambo.utils.properties_builder.mappings_properties_builder import (
|
||||
mappings_properties_builder,
|
||||
)
|
||||
|
||||
import copy
|
||||
from typing import TypeVar
|
||||
|
||||
|
||||
V = TypeVar("V")
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List, Dict, Union, TypedDict, Literal
|
||||
from typing import Dict, List, Literal, TypedDict, Union
|
||||
|
||||
|
||||
JSONSchemaType = Literal[
|
||||
|
||||
@@ -58,7 +58,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
|
||||
# Linters
|
||||
[tool.ruff]
|
||||
[tool.ruff.lint]
|
||||
extend-select = ["I"]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
|
||||
288
tests/parser/test_allof_type_parser.py
Normal file
288
tests/parser/test_allof_type_parser.py
Normal file
@@ -0,0 +1,288 @@
|
||||
from jambo.parser.allof_type_parser import AllOfTypeParser
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestAllOfTypeParser(TestCase):
|
||||
def test_all_of_type_parser_object_type(self):
|
||||
"""
|
||||
Test the AllOfTypeParser with an object type and validate the properties.
|
||||
When using allOf with object it should be able to validate the properties
|
||||
and join them correctly.
|
||||
"""
|
||||
properties = {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 4,
|
||||
},
|
||||
"age": {
|
||||
"type": "integer",
|
||||
"maximum": 100,
|
||||
"minimum": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
type_parsing, type_validator = AllOfTypeParser.from_properties(
|
||||
"placeholder", properties
|
||||
)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
type_parsing(name="John", age=101)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
type_parsing(name="", age=30)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
type_parsing(name="John Invalid", age=30)
|
||||
|
||||
obj = type_parsing(name="John", age=30)
|
||||
self.assertEqual(obj.name, "John")
|
||||
self.assertEqual(obj.age, 30)
|
||||
|
||||
def test_all_of_type_parser_object_type_required(self):
|
||||
"""
|
||||
Tests the required properties of the AllOfTypeParser with an object type.
|
||||
"""
|
||||
|
||||
properties = {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
}
|
||||
},
|
||||
"required": ["name"],
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"age": {
|
||||
"type": "integer",
|
||||
}
|
||||
},
|
||||
"required": ["age"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
type_parsing, type_validator = AllOfTypeParser.from_properties(
|
||||
"placeholder", properties
|
||||
)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
type_parsing(name="John")
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
type_parsing(age=30)
|
||||
|
||||
obj = type_parsing(name="John", age=30)
|
||||
self.assertEqual(obj.name, "John")
|
||||
self.assertEqual(obj.age, 30)
|
||||
|
||||
def test_all_of_type_top_level_type(self):
|
||||
"""
|
||||
Tests the AllOfTypeParser with a top-level type and validate the properties.
|
||||
"""
|
||||
|
||||
properties = {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{"maxLength": 11},
|
||||
{"maxLength": 4},
|
||||
{"minLength": 1},
|
||||
{"minLength": 2},
|
||||
],
|
||||
}
|
||||
|
||||
type_parsing, type_validator = AllOfTypeParser.from_properties(
|
||||
"placeholder", properties
|
||||
)
|
||||
|
||||
self.assertEqual(type_parsing, str)
|
||||
self.assertEqual(type_validator["max_length"], 11)
|
||||
self.assertEqual(type_validator["min_length"], 1)
|
||||
|
||||
def test_all_of_type_parser_in_fields(self):
|
||||
"""
|
||||
Tests the AllOfTypeParser when set in the fields of a model.
|
||||
"""
|
||||
properties = {
|
||||
"allOf": [
|
||||
{"type": "string", "maxLength": 11},
|
||||
{"type": "string", "maxLength": 4},
|
||||
{"type": "string", "minLength": 1},
|
||||
{"type": "string", "minLength": 2},
|
||||
]
|
||||
}
|
||||
|
||||
type_parsing, type_validator = AllOfTypeParser.from_properties(
|
||||
"placeholder", properties
|
||||
)
|
||||
|
||||
self.assertEqual(type_parsing, str)
|
||||
self.assertEqual(type_validator["max_length"], 11)
|
||||
self.assertEqual(type_validator["min_length"], 1)
|
||||
|
||||
def test_invalid_all_of(self):
|
||||
"""
|
||||
Tests that an error is raised when the allOf type is not present.
|
||||
"""
|
||||
properties = {
|
||||
"wrongKey": [
|
||||
{"type": "string", "maxLength": 11},
|
||||
{"type": "string", "maxLength": 4},
|
||||
{"type": "string", "minLength": 1},
|
||||
{"type": "string", "minLength": 2},
|
||||
]
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
AllOfTypeParser.from_properties("placeholder", properties)
|
||||
|
||||
def test_all_of_invalid_type_not_present(self):
|
||||
properties = {
|
||||
"allOf": [
|
||||
{"maxLength": 11},
|
||||
{"maxLength": 4},
|
||||
{"minLength": 1},
|
||||
{"minLength": 2},
|
||||
]
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
AllOfTypeParser.from_properties("placeholder", properties)
|
||||
|
||||
def test_all_of_invalid_type_in_fields(self):
|
||||
properties = {
|
||||
"allOf": [
|
||||
{"type": "string", "maxLength": 11},
|
||||
{"type": "integer", "maxLength": 4},
|
||||
{"type": "string", "minLength": 1},
|
||||
{"minLength": 2},
|
||||
]
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
AllOfTypeParser.from_properties("placeholder", properties)
|
||||
|
||||
def test_all_of_description_field(self):
|
||||
"""
|
||||
Tests the AllOfTypeParser with a description field.
|
||||
"""
|
||||
|
||||
properties = {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "One",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Of",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Us",
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
type_parsing, _ = AllOfTypeParser.from_properties("placeholder", properties)
|
||||
|
||||
self.assertEqual(
|
||||
type_parsing.schema()["properties"]["name"]["description"],
|
||||
"One | Of | Us",
|
||||
)
|
||||
|
||||
def test_all_of_with_defaults(self):
|
||||
"""
|
||||
Tests the AllOfTypeParser with a default value.
|
||||
"""
|
||||
|
||||
properties = {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"default": "John",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"age": {
|
||||
"type": "integer",
|
||||
"default": 30,
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
type_parsing, _ = AllOfTypeParser.from_properties("placeholder", properties)
|
||||
obj = type_parsing()
|
||||
self.assertEqual(obj.name, "John")
|
||||
self.assertEqual(obj.age, 30)
|
||||
|
||||
def test_all_of_with_conflicting_defaults(self):
|
||||
"""
|
||||
Tests the AllOfTypeParser with conflicting default values.
|
||||
"""
|
||||
|
||||
properties = {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"default": "John",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"default": "Doe",
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
AllOfTypeParser.from_properties("placeholder", properties)
|
||||
@@ -1,8 +1,8 @@
|
||||
from jambo.parser import ArrayTypeParser
|
||||
|
||||
from typing import get_args
|
||||
from unittest import TestCase
|
||||
|
||||
from jambo.parser import ArrayTypeParser
|
||||
|
||||
|
||||
class TestArrayTypeParser(TestCase):
|
||||
def test_array_parser_no_options(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from jambo.parser import BooleanTypeParser
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestBoolTypeParser(TestCase):
|
||||
def test_bool_parser_no_options(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from jambo.parser import FloatTypeParser
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestFloatTypeParser(TestCase):
|
||||
def test_float_parser_no_options(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from jambo.parser import IntTypeParser
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestIntTypeParser(TestCase):
|
||||
def test_int_parser_no_options(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from jambo.parser import ObjectTypeParser
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestObjectTypeParser(TestCase):
|
||||
def test_object_type_parser(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from jambo.parser import StringTypeParser
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestStringTypeParser(TestCase):
|
||||
def test_string_parser_no_options(self):
|
||||
|
||||
Reference in New Issue
Block a user