Better TypeParser Kwargs

This commit is contained in:
2025-06-03 02:05:21 -03:00
parent 2b2c823e27
commit be7f04e20d
7 changed files with 50 additions and 25 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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):

View File

@@ -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:

View File

@@ -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:

View File

@@ -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))

View File

@@ -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: