From e1786c23ada2a6bee193af168bb32b2b2d583c29 Mon Sep 17 00:00:00 2001 From: Thomas Poignant Date: Mon, 19 Dec 2022 10:58:47 +0100 Subject: [PATCH 1/2] Get Object should return both list and dict Signed-off-by: Thomas Poignant --- open_feature/flag_evaluation/flag_type.py | 3 ++- open_feature/open_feature_client.py | 5 ++++- open_feature/provider/no_op_provider.py | 4 ++-- open_feature/provider/provider.py | 4 ++-- tests/provider/test_no_op_provider.py | 10 ++++++++++ tests/test_open_feature_client.py | 5 +++++ 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/open_feature/flag_evaluation/flag_type.py b/open_feature/flag_evaluation/flag_type.py index 1deada9a..f19d1d2d 100644 --- a/open_feature/flag_evaluation/flag_type.py +++ b/open_feature/flag_evaluation/flag_type.py @@ -1,9 +1,10 @@ +import typing from enum import Enum class FlagType(Enum): BOOLEAN = bool STRING = str - OBJECT = dict + OBJECT = typing.Union[dict, list] FLOAT = float INTEGER = int diff --git a/open_feature/open_feature_client.py b/open_feature/open_feature_client.py index 1090db0c..3bfdb823 100644 --- a/open_feature/open_feature_client.py +++ b/open_feature/open_feature_client.py @@ -358,7 +358,10 @@ def _create_provider_evaluation( value = get_details_callable(*args) - if not isinstance(value.value, flag_type.value): + # we need to check the get_args to be compatible with union types. + is_right_instance = isinstance(value.value, typing.get_args(flag_type.value)) \ + or isinstance(value.value, flag_type.value) + if not is_right_instance: raise TypeMismatchError() return value diff --git a/open_feature/provider/no_op_provider.py b/open_feature/provider/no_op_provider.py index 14b7dac5..18efa26b 100644 --- a/open_feature/provider/no_op_provider.py +++ b/open_feature/provider/no_op_provider.py @@ -73,9 +73,9 @@ def resolve_float_details( def resolve_object_details( self, flag_key: str, - default_value: dict, + default_value: typing.Union[dict, list], evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagEvaluationDetails[dict]: + ) -> FlagEvaluationDetails[typing.Union[dict, list]]: return FlagEvaluationDetails( flag_key=flag_key, value=default_value, diff --git a/open_feature/provider/provider.py b/open_feature/provider/provider.py index 5b01a499..da7d4ff6 100644 --- a/open_feature/provider/provider.py +++ b/open_feature/provider/provider.py @@ -56,7 +56,7 @@ def resolve_float_details( def resolve_object_details( self, flag_key: str, - default_value: dict, + default_value: typing.Union[dict, list], evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagEvaluationDetails[dict]: + ) -> FlagEvaluationDetails[typing.Union[dict, list]]: pass diff --git a/tests/provider/test_no_op_provider.py b/tests/provider/test_no_op_provider.py index 26e9a9dc..b95849c1 100644 --- a/tests/provider/test_no_op_provider.py +++ b/tests/provider/test_no_op_provider.py @@ -53,6 +53,16 @@ def test_should_resolve_string_flag_from_no_op(): assert isinstance(flag.value, str) +def test_should_resolve_list_flag_from_no_op(): + # Given + # When + flag = NoOpProvider().resolve_object_details(flag_key="Key", default_value=["item1", "item2"]) + # Then + assert flag is not None + assert flag.value == ["item1", "item2"] + assert isinstance(flag.value, list) + + def test_should_resolve_object_flag_from_no_op(): # Given return_value = { diff --git a/tests/test_open_feature_client.py b/tests/test_open_feature_client.py index 2c539e96..b7eaf2a7 100644 --- a/tests/test_open_feature_client.py +++ b/tests/test_open_feature_client.py @@ -24,6 +24,11 @@ }, "get_object_value", ), + ( + list, + ["string1", "string2"], + "get_object_value", + ), ), ) def test_should_get_flag_value_based_on_method_type( From 83e4f9b70764c4b452e3822b0786108911c60900 Mon Sep 17 00:00:00 2001 From: Thomas Poignant Date: Mon, 19 Dec 2022 11:12:47 +0100 Subject: [PATCH 2/2] Run black Signed-off-by: Thomas Poignant --- open_feature/open_feature_client.py | 5 +++-- tests/provider/test_no_op_provider.py | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/open_feature/open_feature_client.py b/open_feature/open_feature_client.py index 3bfdb823..7680f87a 100644 --- a/open_feature/open_feature_client.py +++ b/open_feature/open_feature_client.py @@ -359,8 +359,9 @@ def _create_provider_evaluation( value = get_details_callable(*args) # we need to check the get_args to be compatible with union types. - is_right_instance = isinstance(value.value, typing.get_args(flag_type.value)) \ - or isinstance(value.value, flag_type.value) + is_right_instance = isinstance( + value.value, typing.get_args(flag_type.value) + ) or isinstance(value.value, flag_type.value) if not is_right_instance: raise TypeMismatchError() diff --git a/tests/provider/test_no_op_provider.py b/tests/provider/test_no_op_provider.py index b95849c1..b2762392 100644 --- a/tests/provider/test_no_op_provider.py +++ b/tests/provider/test_no_op_provider.py @@ -56,7 +56,9 @@ def test_should_resolve_string_flag_from_no_op(): def test_should_resolve_list_flag_from_no_op(): # Given # When - flag = NoOpProvider().resolve_object_details(flag_key="Key", default_value=["item1", "item2"]) + flag = NoOpProvider().resolve_object_details( + flag_key="Key", default_value=["item1", "item2"] + ) # Then assert flag is not None assert flag.value == ["item1", "item2"]