Merge pull request #28 from HideyoshiNakazone/feature/adds-enums

[Feature] Adds Enums
This commit was merged in pull request #28.
This commit is contained in:
2025-06-22 17:25:27 -03:00
committed by GitHub
7 changed files with 191 additions and 4 deletions

View File

@@ -0,0 +1,37 @@
Enum Type
==================
An enum type is a special data type that enables a variable to be a set of predefined constants. The enum type is used to define variables that can only take one out of a small set of possible values.
It does not have any specific properties, but it has the generic properties:
- default: Default value for the enum.
- description: Description of the enum field.
Examples
-----------------
.. code-block:: python
from jambo import SchemaConverter
schema = {
"title": "EnumExample",
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["active", "inactive", "pending"],
"description": "The status of the object.",
"default": "active",
},
},
"required": ["status"],
}
Model = SchemaConverter.build(schema)
obj = Model(status="active")
print(obj) # Output: EnumExample(status=status.ACTIVE)

View File

@@ -45,3 +45,4 @@ For more complex schemas and types see our documentation on
usage.reference
usage.allof
usage.anyof
usage.enum

View File

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

View File

@@ -0,0 +1,32 @@
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"] is not None
):
parsed_properties["default"] = enum_type(parsed_properties["default"])
return enum_type, parsed_properties

View File

@@ -50,6 +50,7 @@ repository = "https://github.com/HideyoshiNakazone/jambo.git"
create-hooks = "bash .githooks/set-hooks.sh"
tests = "python -m coverage run -m unittest discover -v"
tests-report = "python -m coverage xml"
serve-docs = "sphinx-autobuild docs/source docs/build"
# Build System
[tool.hatch.version]

View File

@@ -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"].value, "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)

View File

@@ -597,3 +597,40 @@ class TestSchemaConverter(TestCase):
self.assertEqual(obj.age, 30)
self.assertEqual(obj.address.street, "123 Main St")
self.assertEqual(obj.address.city, "Springfield")
def test_enum_type_parser(self):
schema = {
"title": "Person",
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["active", "inactive", "pending"],
}
},
"required": ["status"],
}
Model = SchemaConverter.build(schema)
obj = Model(status="active")
self.assertEqual(obj.status.value, "active")
def test_enum_type_parser_with_default(self):
schema = {
"title": "Person",
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["active", "inactive", "pending"],
"default": "active",
}
},
"required": ["status"],
}
Model = SchemaConverter.build(schema)
obj = Model()
self.assertEqual(obj.status.value, "active")