From e37e9818ed58049286abd89ed74f6fdbd3c05884 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Tue, 3 Jun 2025 00:44:06 -0300 Subject: [PATCH] Initial Work on TypeParser Kwargs --- jambo/parser/_type_parser.py | 21 ++++++++++++--------- jambo/parser/allof_type_parser.py | 7 ++++--- jambo/parser/anyof_type_parser.py | 19 ++++++++++--------- jambo/parser/array_type_parser.py | 3 ++- jambo/parser/object_type_parser.py | 3 +-- jambo/types/json_schema_type.py | 2 +- jambo/types/type_parser_options.py | 5 +++++ tests/parser/test_anyof_type_parser.py | 3 +-- tests/parser/test_array_type_parser.py | 3 ++- 9 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 jambo/types/type_parser_options.py diff --git a/jambo/parser/_type_parser.py b/jambo/parser/_type_parser.py index 165d9d9..b1a7591 100644 --- a/jambo/parser/_type_parser.py +++ b/jambo/parser/_type_parser.py @@ -1,8 +1,9 @@ +from jambo.types.type_parser_options import TypeParserOptions + from pydantic import Field, TypeAdapter -from typing_extensions import Annotated, Self +from typing_extensions import Annotated, Any, Generic, Self, TypeVar, Unpack from abc import ABC, abstractmethod -from typing import Any, Generic, TypeVar T = TypeVar("T") @@ -18,9 +19,14 @@ class GenericTypeParser(ABC, Generic[T]): "description": "description", } + @abstractmethod + def from_properties( + self, name: str, properties: dict[str, Any], **kwargs: Unpack[TypeParserOptions] + ) -> tuple[T, dict]: ... + @classmethod def type_from_properties( - cls, name: str, properties: dict[str, Any], **kwargs + cls, name: str, properties: dict[str, Any], **kwargs: Unpack[TypeParserOptions] ) -> tuple[type, dict]: parser = cls._get_impl(properties) @@ -51,12 +57,9 @@ class GenericTypeParser(ABC, Generic[T]): return schema_definition[0], schema_definition[1] - @abstractmethod - def from_properties( - self, name: str, properties: dict[str, Any], required: bool = False - ) -> tuple[T, dict]: ... - - def mappings_properties_builder(self, properties, required=False) -> dict[str, Any]: + def mappings_properties_builder( + self, properties, required=False, **kwargs: Unpack[TypeParserOptions] + ) -> dict[str, Any]: if self.type_mappings is None: raise NotImplementedError("Type mappings not defined") diff --git a/jambo/parser/allof_type_parser.py b/jambo/parser/allof_type_parser.py index 0e56cd5..c3a275f 100644 --- a/jambo/parser/allof_type_parser.py +++ b/jambo/parser/allof_type_parser.py @@ -1,6 +1,7 @@ from jambo.parser._type_parser import GenericTypeParser +from jambo.types.type_parser_options import TypeParserOptions -from typing import Any +from typing_extensions import Any, Unpack class AllOfTypeParser(GenericTypeParser): @@ -8,7 +9,7 @@ class AllOfTypeParser(GenericTypeParser): json_schema_type = "allOf" - def from_properties(self, name, properties, required=False): + def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]): sub_properties = properties.get("allOf", []) root_type = properties.get("type") @@ -22,7 +23,7 @@ class AllOfTypeParser(GenericTypeParser): sub_properties ) - return parser().from_properties(name, combined_properties) + return parser().from_properties(name, combined_properties, **kwargs) @staticmethod def _get_type_parser( diff --git a/jambo/parser/anyof_type_parser.py b/jambo/parser/anyof_type_parser.py index ca65e8d..d617406 100644 --- a/jambo/parser/anyof_type_parser.py +++ b/jambo/parser/anyof_type_parser.py @@ -1,9 +1,8 @@ from jambo.parser._type_parser import GenericTypeParser +from jambo.types.type_parser_options import TypeParserOptions from pydantic import Field -from typing_extensions import Annotated - -from typing import Union +from typing_extensions import Annotated, Union, Unpack class AnyOfTypeParser(GenericTypeParser): @@ -11,7 +10,7 @@ class AnyOfTypeParser(GenericTypeParser): json_schema_type = "anyOf" - def from_properties(self, name, properties, required=False): + def from_properties(self, name, properties, **kwargs: Unpack[TypeParserOptions]): if "anyOf" not in properties: raise ValueError(f"Invalid JSON Schema: {properties}") @@ -20,11 +19,11 @@ class AnyOfTypeParser(GenericTypeParser): mapped_properties = dict() - subProperties = properties["anyOf"] + sub_properties = properties["anyOf"] sub_types = [ - GenericTypeParser.type_from_properties(name, subProperty) - for subProperty in subProperties + GenericTypeParser.type_from_properties(name, subProperty, **kwargs) + for subProperty in sub_properties ] default_value = properties.get("default") @@ -42,12 +41,14 @@ class AnyOfTypeParser(GenericTypeParser): mapped_properties["default"] = default_value - if not required: + if not kwargs.get("required", False): mapped_properties["default"] = mapped_properties.get("default") # By defining the type as Union of Annotated type we can use the Field validator # to enforce the constraints of each union type when needed. # 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 is not None else t for t, v in sub_types + ] return Union[(*field_types,)], mapped_properties diff --git a/jambo/parser/array_type_parser.py b/jambo/parser/array_type_parser.py index bdda4ce..d933c66 100644 --- a/jambo/parser/array_type_parser.py +++ b/jambo/parser/array_type_parser.py @@ -1,7 +1,8 @@ from jambo.parser._type_parser import GenericTypeParser +from typing_extensions import TypeVar + import copy -from typing import TypeVar V = TypeVar("V") diff --git a/jambo/parser/object_type_parser.py b/jambo/parser/object_type_parser.py index 827afa7..b10f454 100644 --- a/jambo/parser/object_type_parser.py +++ b/jambo/parser/object_type_parser.py @@ -2,8 +2,7 @@ from jambo.parser._type_parser import GenericTypeParser from pydantic import Field, create_model from pydantic.main import ModelT - -from typing import Any +from typing_extensions import Any class ObjectTypeParser(GenericTypeParser): diff --git a/jambo/types/json_schema_type.py b/jambo/types/json_schema_type.py index 0658db6..c9c1ffc 100644 --- a/jambo/types/json_schema_type.py +++ b/jambo/types/json_schema_type.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Literal, TypedDict, Union +from typing_extensions import Dict, List, Literal, TypedDict, Union JSONSchemaType = Literal[ diff --git a/jambo/types/type_parser_options.py b/jambo/types/type_parser_options.py new file mode 100644 index 0000000..b75490e --- /dev/null +++ b/jambo/types/type_parser_options.py @@ -0,0 +1,5 @@ +from typing_extensions import TypedDict + + +class TypeParserOptions(TypedDict): + required: bool diff --git a/tests/parser/test_anyof_type_parser.py b/tests/parser/test_anyof_type_parser.py index 023fcb9..32c2f45 100644 --- a/tests/parser/test_anyof_type_parser.py +++ b/tests/parser/test_anyof_type_parser.py @@ -1,8 +1,7 @@ from jambo.parser.anyof_type_parser import AnyOfTypeParser -from typing_extensions import Annotated +from typing_extensions import Annotated, Union, get_args, get_origin -from typing import Union, get_args, get_origin from unittest import TestCase diff --git a/tests/parser/test_array_type_parser.py b/tests/parser/test_array_type_parser.py index 172b98f..c81c193 100644 --- a/tests/parser/test_array_type_parser.py +++ b/tests/parser/test_array_type_parser.py @@ -1,6 +1,7 @@ from jambo.parser import ArrayTypeParser -from typing import get_args +from typing_extensions import get_args + from unittest import TestCase