[Feature] Adds Enums #28
37
docs/source/usage.enum.rst
Normal file
37
docs/source/usage.enum.rst
Normal 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)
|
||||
@@ -44,4 +44,5 @@ For more complex schemas and types see our documentation on
|
||||
usage.object
|
||||
usage.reference
|
||||
usage.allof
|
||||
usage.anyof
|
||||
usage.anyof
|
||||
usage.enum
|
||||
@@ -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",
|
||||
|
||||
32
jambo/parser/enum_type_parser.py
Normal file
32
jambo/parser/enum_type_parser.py
Normal 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
|
||||
@@ -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]
|
||||
|
||||
80
tests/parser/test_enum_type_parser.py
Normal file
80
tests/parser/test_enum_type_parser.py
Normal 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)
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user