From 7e591f0525b143944a8cff5160a908a2bca52654 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 22 Jun 2025 11:18:42 -0300 Subject: [PATCH] Initial Implementation of Enum --- jambo/parser/__init__.py | 5 +- jambo/parser/enum_type_parser.py | 35 ++++++++++++ tests/parser/test_enum_type_parser.py | 80 +++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 jambo/parser/enum_type_parser.py create mode 100644 tests/parser/test_enum_type_parser.py diff --git a/jambo/parser/__init__.py b/jambo/parser/__init__.py index b804339..9c63244 100644 --- a/jambo/parser/__init__.py +++ b/jambo/parser/__init__.py @@ -1,11 +1,9 @@ -# Exports generic type parser from ._type_parser import GenericTypeParser - -# Exports Implementations 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 .enum_type_parser import EnumTypeParser from .float_type_parser import FloatTypeParser from .int_type_parser import IntTypeParser from .object_type_parser import ObjectTypeParser @@ -15,6 +13,7 @@ from .string_type_parser import StringTypeParser __all__ = [ "GenericTypeParser", + "EnumTypeParser", "AllOfTypeParser", "AnyOfTypeParser", "ArrayTypeParser", diff --git a/jambo/parser/enum_type_parser.py b/jambo/parser/enum_type_parser.py new file mode 100644 index 0000000..ac11c0a --- /dev/null +++ b/jambo/parser/enum_type_parser.py @@ -0,0 +1,35 @@ +from jambo.parser._type_parser import GenericTypeParser +from jambo.types.type_parser_options import TypeParserOptions + +from typing_extensions import Unpack + +from enum import Enum + + +class EnumTypeParser(GenericTypeParser): + json_schema_type = "enum" + + def from_properties_impl( + self, name, properties, **kwargs: Unpack[TypeParserOptions] + ): + if "enum" not in properties: + raise ValueError(f"Enum type {name} must have 'enum' property defined.") + + enum_values = properties["enum"] + + if not isinstance(enum_values, list): + raise ValueError(f"Enum type {name} must have 'enum' as a list of values.") + + # Create a new Enum type dynamically + enum_type = Enum(name, {str(value).upper(): value for value in enum_values}) + parsed_properties = self.mappings_properties_builder(properties, **kwargs) + + if ( + "default" in parsed_properties + and parsed_properties["default"] not in enum_values + ): + raise ValueError( + f"Default value {parsed_properties['default']} is not a valid member of enum {name}." + ) + + return enum_type, parsed_properties diff --git a/tests/parser/test_enum_type_parser.py b/tests/parser/test_enum_type_parser.py new file mode 100644 index 0000000..39d0e29 --- /dev/null +++ b/tests/parser/test_enum_type_parser.py @@ -0,0 +1,80 @@ +from jambo.parser import EnumTypeParser + +from enum import Enum +from unittest import TestCase + + +class TestEnumTypeParser(TestCase): + def test_enum_type_parser_throws_enum_not_defined(self): + parser = EnumTypeParser() + + schema = {} + + with self.assertRaises(ValueError): + parsed_type, parsed_properties = parser.from_properties_impl( + "TestEnum", + schema, + ) + + def test_enum_type_parser_throws_enum_not_list(self): + parser = EnumTypeParser() + + schema = { + "enum": "not_a_list", + } + + with self.assertRaises(ValueError): + parsed_type, parsed_properties = parser.from_properties_impl( + "TestEnum", + schema, + ) + + def test_enum_type_parser_creates_enum(self): + parser = EnumTypeParser() + + schema = { + "enum": ["value1", "value2", "value3"], + } + + parsed_type, parsed_properties = parser.from_properties_impl( + "TestEnum", + schema, + ) + + self.assertIsInstance(parsed_type, type) + self.assertTrue(issubclass(parsed_type, Enum)) + self.assertEqual( + set(parsed_type.__members__.keys()), {"VALUE1", "VALUE2", "VALUE3"} + ) + self.assertEqual(parsed_properties, {"default": None}) + + def test_enum_type_parser_creates_enum_with_default(self): + parser = EnumTypeParser() + + schema = { + "enum": ["value1", "value2", "value3"], + "default": "value2", + } + + parsed_type, parsed_properties = parser.from_properties_impl( + "TestEnum", + schema, + ) + + self.assertIsInstance(parsed_type, type) + self.assertTrue(issubclass(parsed_type, Enum)) + self.assertEqual( + set(parsed_type.__members__.keys()), {"VALUE1", "VALUE2", "VALUE3"} + ) + self.assertEqual(parsed_properties["default"], "value2") + + def test_enum_type_parser_throws_invalid_default(self): + parser = EnumTypeParser() + + schema = { + "enum": ["value1", "value2", "value3"], + "default": "invalid_value", + } + + with self.assertRaises(ValueError): + parser.from_properties_impl("TestEnum", schema)