From 65a81a8da5addeabb70b9886d0b8169c2ab6469a Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 22 Jun 2025 22:13:46 -0300 Subject: [PATCH] Initial Const Implementation --- jambo/parser/__init__.py | 2 ++ jambo/parser/const_type_parser.py | 46 ++++++++++++++++++++++++++ jambo/parser/enum_type_parser.py | 15 ++------- jambo/types/json_schema_type.py | 13 ++++++++ tests/parser/test_const_type_parser.py | 23 +++++++++++++ 5 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 jambo/parser/const_type_parser.py create mode 100644 tests/parser/test_const_type_parser.py diff --git a/jambo/parser/__init__.py b/jambo/parser/__init__.py index 9c63244..a953057 100644 --- a/jambo/parser/__init__.py +++ b/jambo/parser/__init__.py @@ -3,6 +3,7 @@ from .allof_type_parser import AllOfTypeParser from .anyof_type_parser import AnyOfTypeParser from .array_type_parser import ArrayTypeParser from .boolean_type_parser import BooleanTypeParser +from .const_type_parser import ConstTypeParser from .enum_type_parser import EnumTypeParser from .float_type_parser import FloatTypeParser from .int_type_parser import IntTypeParser @@ -14,6 +15,7 @@ from .string_type_parser import StringTypeParser __all__ = [ "GenericTypeParser", "EnumTypeParser", + "ConstTypeParser", "AllOfTypeParser", "AnyOfTypeParser", "ArrayTypeParser", diff --git a/jambo/parser/const_type_parser.py b/jambo/parser/const_type_parser.py new file mode 100644 index 0000000..a408264 --- /dev/null +++ b/jambo/parser/const_type_parser.py @@ -0,0 +1,46 @@ +from jambo.parser._type_parser import GenericTypeParser +from jambo.types.json_schema_type import JSONSchemaNativeTypes +from jambo.types.type_parser_options import TypeParserOptions + +from pydantic import AfterValidator +from typing_extensions import Annotated, Any, Unpack + + +class ConstTypeParser(GenericTypeParser): + json_schema_type = "const" + + def from_properties_impl( + self, name, properties, **kwargs: Unpack[TypeParserOptions] + ): + if "const" not in properties: + raise ValueError(f"Const type {name} must have 'const' property defined.") + + const_value = properties["const"] + + if not isinstance(const_value, JSONSchemaNativeTypes): + raise ValueError( + f"Const type {name} must have 'const' value of allowed types: {JSONSchemaNativeTypes}." + ) + + const_type = self._build_const_type(const_value) + parsed_properties = { + "default": const_value, + "description": properties.get("description"), + } + + return const_type, parsed_properties + + def _build_const_type(self, const_value): + def _validate_const_value(value: Any) -> Any: + if value != const_value: + raise ValueError( + f"Value must be equal to the constant value: {const_value}" + ) + return value + + return Annotated[ + type(const_value), + AfterValidator( + _validate_const_value + ) + ] \ No newline at end of file diff --git a/jambo/parser/enum_type_parser.py b/jambo/parser/enum_type_parser.py index 45480af..5ea9e67 100644 --- a/jambo/parser/enum_type_parser.py +++ b/jambo/parser/enum_type_parser.py @@ -1,4 +1,5 @@ from jambo.parser._type_parser import GenericTypeParser +from jambo.types.json_schema_type import JSONSchemaNativeTypes from jambo.types.type_parser_options import TypeParserOptions from typing_extensions import Unpack @@ -9,16 +10,6 @@ from enum import Enum class EnumTypeParser(GenericTypeParser): json_schema_type = "enum" - allowed_types: tuple[type] = ( - str, - int, - float, - bool, - list, - set, - type(None), - ) - def from_properties_impl( self, name, properties, **kwargs: Unpack[TypeParserOptions] ): @@ -31,10 +22,10 @@ class EnumTypeParser(GenericTypeParser): raise ValueError(f"Enum type {name} must have 'enum' as a list of values.") if any( - not isinstance(value, self.allowed_types) for value in enum_values + not isinstance(value, JSONSchemaNativeTypes) for value in enum_values ): raise ValueError( - f"Enum type {name} must have 'enum' values of allowed types: {self.allowed_types}." + f"Enum type {name} must have 'enum' values of allowed types: {JSONSchemaNativeTypes}." ) # Create a new Enum type dynamically diff --git a/jambo/types/json_schema_type.py b/jambo/types/json_schema_type.py index c9c1ffc..6f61837 100644 --- a/jambo/types/json_schema_type.py +++ b/jambo/types/json_schema_type.py @@ -1,11 +1,24 @@ from typing_extensions import Dict, List, Literal, TypedDict, Union +from types import NoneType + JSONSchemaType = Literal[ "string", "number", "integer", "boolean", "object", "array", "null" ] +JSONSchemaNativeTypes: tuple[type, ...] = ( + str, + int, + float, + bool, + list, + set, + NoneType, +) + + JSONType = Union[str, int, float, bool, None, Dict[str, "JSONType"], List["JSONType"]] diff --git a/tests/parser/test_const_type_parser.py b/tests/parser/test_const_type_parser.py new file mode 100644 index 0000000..d37fa57 --- /dev/null +++ b/tests/parser/test_const_type_parser.py @@ -0,0 +1,23 @@ +from typing_extensions import Annotated, get_args, get_origin +from webbrowser import get +from jambo.parser import ConstTypeParser + +from unittest import TestCase + + +class TestConstTypeParser(TestCase): + def test_parse_const_type(self): + parser = ConstTypeParser() + + expected_const_value = "United States of America" + properties = { + "const": expected_const_value + } + + parsed_type, parsed_properties = parser.from_properties( + "country", properties + ) + + self.assertEqual(get_origin(parsed_type), Annotated) + + self.assertIn(str, get_args(parsed_type)) \ No newline at end of file