Better Object Internal Structure and Type Selection #16
@@ -48,7 +48,9 @@ class GenericTypeParser(ABC, Generic[T]):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _get_schema_type(cls) -> tuple[str, str | None]:
|
def _get_schema_type(cls) -> tuple[str, str | None]:
|
||||||
if cls.json_schema_type is None:
|
if cls.json_schema_type is None:
|
||||||
raise RuntimeError("TypeParser: json_schema_type not defined")
|
raise RuntimeError(
|
||||||
|
f"TypeParser: json_schema_type not defined for subclass {cls.__name__}"
|
||||||
|
)
|
||||||
|
|
||||||
schema_definition = cls.json_schema_type.split(":")
|
schema_definition = cls.json_schema_type.split(":")
|
||||||
|
|
||||||
@@ -58,12 +60,12 @@ class GenericTypeParser(ABC, Generic[T]):
|
|||||||
return schema_definition[0], schema_definition[1]
|
return schema_definition[0], schema_definition[1]
|
||||||
|
|
||||||
def mappings_properties_builder(
|
def mappings_properties_builder(
|
||||||
self, properties, required=False, **kwargs: Unpack[TypeParserOptions]
|
self, properties, **kwargs: Unpack[TypeParserOptions]
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
if self.type_mappings is None:
|
if self.type_mappings is None:
|
||||||
raise NotImplementedError("Type mappings not defined")
|
raise NotImplementedError("Type mappings not defined")
|
||||||
|
|
||||||
if not required:
|
if not kwargs.get("required", False):
|
||||||
properties["default"] = properties.get("default", None)
|
properties["default"] = properties.get("default", None)
|
||||||
|
|
||||||
mappings = self.default_mappings | self.type_mappings
|
mappings = self.default_mappings | self.type_mappings
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
|
from jambo.types.type_parser_options import TypeParserOptions
|
||||||
|
|
||||||
from typing_extensions import TypeVar
|
from typing_extensions import TypeVar, Unpack
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
@@ -20,18 +21,17 @@ class ArrayTypeParser(GenericTypeParser):
|
|||||||
"minItems": "min_length",
|
"minItems": "min_length",
|
||||||
}
|
}
|
||||||
|
|
||||||
def from_properties(self, name, properties, required=False):
|
def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]):
|
||||||
|
item_properties = kwargs.copy()
|
||||||
|
item_properties["required"] = True
|
||||||
_item_type, _item_args = GenericTypeParser.type_from_properties(
|
_item_type, _item_args = GenericTypeParser.type_from_properties(
|
||||||
name, properties["items"], required=True
|
name, properties["items"], **item_properties
|
||||||
)
|
)
|
||||||
|
|
||||||
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]
|
field_type = wrapper_type[_item_type]
|
||||||
|
|
||||||
mapped_properties = self.mappings_properties_builder(
|
mapped_properties = self.mappings_properties_builder(properties, **kwargs)
|
||||||
properties,
|
|
||||||
required=required,
|
|
||||||
)
|
|
||||||
|
|
||||||
default_list = properties.pop("default", None)
|
default_list = properties.pop("default", None)
|
||||||
if default_list is not None:
|
if default_list is not None:
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
|
from jambo.types.type_parser_options import TypeParserOptions
|
||||||
|
|
||||||
|
from typing_extensions import Unpack
|
||||||
|
|
||||||
|
|
||||||
class BooleanTypeParser(GenericTypeParser):
|
class BooleanTypeParser(GenericTypeParser):
|
||||||
@@ -10,8 +13,8 @@ class BooleanTypeParser(GenericTypeParser):
|
|||||||
"default": "default",
|
"default": "default",
|
||||||
}
|
}
|
||||||
|
|
||||||
def from_properties(self, name, properties, required=False):
|
def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]):
|
||||||
mapped_properties = self.mappings_properties_builder(properties, required)
|
mapped_properties = self.mappings_properties_builder(properties, **kwargs)
|
||||||
|
|
||||||
default_value = properties.get("default")
|
default_value = properties.get("default")
|
||||||
if default_value is not None and not isinstance(default_value, bool):
|
if default_value is not None and not isinstance(default_value, bool):
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
|
from jambo.types.type_parser_options import TypeParserOptions
|
||||||
|
|
||||||
|
from typing_extensions import Unpack
|
||||||
|
|
||||||
|
|
||||||
class FloatTypeParser(GenericTypeParser):
|
class FloatTypeParser(GenericTypeParser):
|
||||||
@@ -15,8 +18,8 @@ class FloatTypeParser(GenericTypeParser):
|
|||||||
"default": "default",
|
"default": "default",
|
||||||
}
|
}
|
||||||
|
|
||||||
def from_properties(self, name, properties, required=False):
|
def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]):
|
||||||
mapped_properties = self.mappings_properties_builder(properties, required)
|
mapped_properties = self.mappings_properties_builder(properties, **kwargs)
|
||||||
|
|
||||||
default_value = mapped_properties.get("default")
|
default_value = mapped_properties.get("default")
|
||||||
if default_value is not None:
|
if default_value is not None:
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
|
from jambo.types.type_parser_options import TypeParserOptions
|
||||||
|
|
||||||
|
from typing_extensions import Unpack
|
||||||
|
|
||||||
|
|
||||||
class IntTypeParser(GenericTypeParser):
|
class IntTypeParser(GenericTypeParser):
|
||||||
@@ -15,8 +18,8 @@ class IntTypeParser(GenericTypeParser):
|
|||||||
"default": "default",
|
"default": "default",
|
||||||
}
|
}
|
||||||
|
|
||||||
def from_properties(self, name, properties, required=False):
|
def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]):
|
||||||
mapped_properties = self.mappings_properties_builder(properties, required)
|
mapped_properties = self.mappings_properties_builder(properties, **kwargs)
|
||||||
|
|
||||||
default_value = mapped_properties.get("default")
|
default_value = mapped_properties.get("default")
|
||||||
if default_value is not None:
|
if default_value is not None:
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
|
from jambo.types.type_parser_options import TypeParserOptions
|
||||||
|
|
||||||
from pydantic import Field, create_model
|
from pydantic import Field, create_model
|
||||||
from pydantic.main import ModelT
|
from pydantic.main import ModelT
|
||||||
from typing_extensions import Any
|
from typing_extensions import Any, Unpack
|
||||||
|
|
||||||
|
|
||||||
class ObjectTypeParser(GenericTypeParser):
|
class ObjectTypeParser(GenericTypeParser):
|
||||||
@@ -11,10 +12,13 @@ class ObjectTypeParser(GenericTypeParser):
|
|||||||
json_schema_type = "type:object"
|
json_schema_type = "type:object"
|
||||||
|
|
||||||
def from_properties(
|
def from_properties(
|
||||||
self, name: str, properties: dict[str, Any], required: bool = False
|
self, name: str, properties: dict[str, Any], **kwargs: Unpack[TypeParserOptions]
|
||||||
):
|
):
|
||||||
type_parsing = self.to_model(
|
type_parsing = self.to_model(
|
||||||
name, properties.get("properties", {}), properties.get("required", [])
|
name,
|
||||||
|
properties.get("properties", {}),
|
||||||
|
properties.get("required", []),
|
||||||
|
**kwargs,
|
||||||
)
|
)
|
||||||
type_properties = {}
|
type_properties = {}
|
||||||
|
|
||||||
@@ -26,7 +30,11 @@ class ObjectTypeParser(GenericTypeParser):
|
|||||||
return type_parsing, type_properties
|
return type_parsing, type_properties
|
||||||
|
|
||||||
def to_model(
|
def to_model(
|
||||||
self, name: str, schema: dict[str, Any], required_keys: list[str], **kwargs
|
self,
|
||||||
|
name: str,
|
||||||
|
schema: dict[str, Any],
|
||||||
|
required_keys: list[str],
|
||||||
|
**kwargs: Unpack[TypeParserOptions],
|
||||||
) -> type[ModelT]:
|
) -> type[ModelT]:
|
||||||
"""
|
"""
|
||||||
Converts JSON Schema object properties to a Pydantic model.
|
Converts JSON Schema object properties to a Pydantic model.
|
||||||
@@ -40,15 +48,19 @@ class ObjectTypeParser(GenericTypeParser):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_properties(
|
def _parse_properties(
|
||||||
properties: dict[str, Any], required_keys: list[str], **kwargs
|
properties: dict[str, Any],
|
||||||
|
required_keys: list[str],
|
||||||
|
**kwargs: Unpack[TypeParserOptions],
|
||||||
) -> dict[str, tuple[type, Field]]:
|
) -> dict[str, tuple[type, Field]]:
|
||||||
required_keys = required_keys or []
|
required_keys = required_keys or []
|
||||||
|
|
||||||
fields = {}
|
fields = {}
|
||||||
for name, prop in properties.items():
|
for name, prop in properties.items():
|
||||||
is_required = name in required_keys
|
sub_property = kwargs.copy()
|
||||||
|
sub_property["required"] = name in required_keys
|
||||||
|
|
||||||
parsed_type, parsed_properties = GenericTypeParser.type_from_properties(
|
parsed_type, parsed_properties = GenericTypeParser.type_from_properties(
|
||||||
name, prop, required=is_required, **kwargs
|
name, prop, **sub_property
|
||||||
)
|
)
|
||||||
fields[name] = (parsed_type, Field(**parsed_properties))
|
fields[name] = (parsed_type, Field(**parsed_properties))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from jambo.parser._type_parser import GenericTypeParser
|
from jambo.parser._type_parser import GenericTypeParser
|
||||||
|
from jambo.types.type_parser_options import TypeParserOptions
|
||||||
|
|
||||||
from pydantic import EmailStr, HttpUrl, IPvAnyAddress
|
from pydantic import EmailStr, HttpUrl, IPvAnyAddress
|
||||||
|
from typing_extensions import Unpack
|
||||||
|
|
||||||
from datetime import date, datetime, time
|
from datetime import date, datetime, time
|
||||||
|
|
||||||
@@ -32,8 +34,8 @@ class StringTypeParser(GenericTypeParser):
|
|||||||
"hostname": r"^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$",
|
"hostname": r"^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$",
|
||||||
}
|
}
|
||||||
|
|
||||||
def from_properties(self, name, properties, required=False):
|
def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]):
|
||||||
mapped_properties = self.mappings_properties_builder(properties, required)
|
mapped_properties = self.mappings_properties_builder(properties, **kwargs)
|
||||||
|
|
||||||
format_type = properties.get("format")
|
format_type = properties.get("format")
|
||||||
if format_type:
|
if format_type:
|
||||||
|
|||||||
Reference in New Issue
Block a user