diff --git a/changelog/@unreleased/pr-128.v2.yml b/changelog/@unreleased/pr-128.v2.yml new file mode 100644 index 00000000..f8c5b94b --- /dev/null +++ b/changelog/@unreleased/pr-128.v2.yml @@ -0,0 +1,6 @@ +type: improvement +improvement: + description: Deserialize enum variants case-insensitively, for compatibility with + the Java implementation + links: + - https://github.com/palantir/conjure-python-client/pull/128 diff --git a/conjure_python_client/_serde/decoder.py b/conjure_python_client/_serde/decoder.py index aa806acf..817063eb 100644 --- a/conjure_python_client/_serde/decoder.py +++ b/conjure_python_client/_serde/decoder.py @@ -142,8 +142,9 @@ def decode_conjure_enum_type(cls, obj, conjure_type): ) ) - if obj in conjure_type.__members__: - return conjure_type[obj] + upper_value: str = obj.upper() + if upper_value in conjure_type.__members__: + return conjure_type[upper_value] else: return conjure_type["UNKNOWN"] diff --git a/test/example_service/product/datasets/__init__.py b/test/example_service/product/datasets/__init__.py index dca630a6..2a9c9ae7 100644 --- a/test/example_service/product/datasets/__init__.py +++ b/test/example_service/product/datasets/__init__.py @@ -110,3 +110,36 @@ def __init__(self, value: Dict[str, str]) -> None: @property def value(self) -> Dict[str, str]: return self._value + + +class EnumExample(ConjureEnumType): + + ONE = 'ONE' + '''ONE''' + TWO = 'TWO' + '''TWO''' + ONE_HUNDRED = 'ONE_HUNDRED' + '''ONE_HUNDRED''' + UNKNOWN = 'UNKNOWN' + '''UNKNOWN''' + + def __reduce_ex__(self, proto): + return self.__class__, (self.name,) + + +class EnumFieldExample(ConjureBeanType): + + @classmethod + def _fields(cls) -> Dict[str, ConjureFieldDefinition]: + return { + 'enum': ConjureFieldDefinition('enum', EnumExample) + } + + __slots__: List[str] = ['_enum'] + + def __init__(self, enum: "EnumExample") -> None: + self._enum = enum + + @property + def enum(self) -> "EnumExample": + return self._enum diff --git a/test/serde/test_decode_object.py b/test/serde/test_decode_object.py index 05c5f92c..6a5f5614 100644 --- a/test/serde/test_decode_object.py +++ b/test/serde/test_decode_object.py @@ -16,7 +16,7 @@ import re from conjure_python_client import ConjureDecoder from test.example_service.product import CreateDatasetRequest -from test.example_service.product.datasets import ListExample, MapExample +from test.example_service.product.datasets import EnumExample, EnumFieldExample, ListExample, MapExample def test_object_decodes_when_exact_fields_are_present(): @@ -54,6 +54,16 @@ def test_object_with_omitted_map_field_decodes(): assert decoded == MapExample({}) +def test_object_with_enum_field_decodes(): + decoded = ConjureDecoder().read_from_string('{"enum": "ONE"}', EnumFieldExample) + assert decoded == EnumFieldExample(EnumExample.ONE) + + +def test_object_with_enum_field_decodes_case_insensitive(): + decoded = ConjureDecoder().read_from_string('{"enum": "one"}', EnumFieldExample) + assert decoded == EnumFieldExample(EnumExample.ONE) + + def test_object_with_missing_field_should_throw_helpful_exception(): with pytest.raises(Exception) as excinfo: ConjureDecoder().read_from_string(