Skip to content

Commit b44224b

Browse files
authored
fix: Move flag evaluation details to a dataclass (#27)
* fix/flag-error-message: Move flag evaluation details to a dataclass and add error message to the class Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]> * fix/flag-error-message: Rename flag_key in FlagEvaluationDetails to match spec Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]> * fix/flag-error-message: Rename flag_key in provider.py to match spec Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]> * fix/flag-error-message: Rename flag_key in open_feature_client.py Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]> * fix/flag-error-message: Rename flag_key in open_feature_client.py Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]> * fix/flag-error-message: handle error_message doesn't exist exception Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]> Signed-off-by: Andrew Helsby <[email protected]>
1 parent 7ef8667 commit b44224b

File tree

5 files changed

+63
-52
lines changed

5 files changed

+63
-52
lines changed
Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1+
import typing
2+
from dataclasses import dataclass
3+
14
from open_feature.flag_evaluation.error_code import ErrorCode
25
from open_feature.flag_evaluation.reason import Reason
36

47

8+
@dataclass
59
class FlagEvaluationDetails:
6-
def __init__(
7-
self,
8-
key: str,
9-
value,
10-
reason: Reason,
11-
error_code: ErrorCode = None,
12-
variant=None,
13-
):
14-
self.key = key
15-
self.value = value
16-
self.reason = reason
17-
self.error_code = error_code
18-
self.variant = variant
10+
flag_key: str
11+
value: typing.Any
12+
variant: str = None
13+
reason: Reason = None
14+
error_code: ErrorCode = None
15+
error_message: str = None

open_feature/open_feature_client.py

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from open_feature.evaluation_context.evaluation_context import EvaluationContext
66
from open_feature.exception.exceptions import GeneralError
7+
from open_feature.flag_evaluation.error_code import ErrorCode
78
from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails
89
from open_feature.flag_evaluation.flag_type import FlagType
910
from open_feature.flag_evaluation.reason import Reason
@@ -40,119 +41,119 @@ def add_hooks(self, hooks: typing.List[Hook]):
4041

4142
def get_boolean_value(
4243
self,
43-
key: str,
44+
flag_key: str,
4445
default_value: bool,
4546
evaluation_context: EvaluationContext = None,
4647
flag_evaluation_options: typing.Any = None,
4748
) -> bool:
4849
return self.evaluate_flag_details(
4950
FlagType.BOOLEAN,
50-
key,
51+
flag_key,
5152
default_value,
5253
evaluation_context,
5354
flag_evaluation_options,
5455
).value
5556

5657
def get_boolean_details(
5758
self,
58-
key: str,
59+
flag_key: str,
5960
default_value: bool,
6061
evaluation_context: EvaluationContext = None,
6162
flag_evaluation_options: typing.Any = None,
6263
) -> FlagEvaluationDetails:
6364
return self.evaluate_flag_details(
6465
FlagType.BOOLEAN,
65-
key,
66+
flag_key,
6667
default_value,
6768
evaluation_context,
6869
flag_evaluation_options,
6970
)
7071

7172
def get_string_value(
7273
self,
73-
key: str,
74+
flag_key: str,
7475
default_value: str,
7576
evaluation_context: EvaluationContext = None,
7677
flag_evaluation_options: typing.Any = None,
7778
) -> str:
7879
return self.evaluate_flag_details(
7980
FlagType.STRING,
80-
key,
81+
flag_key,
8182
default_value,
8283
evaluation_context,
8384
flag_evaluation_options,
8485
).value
8586

8687
def get_string_details(
8788
self,
88-
key: str,
89+
flag_key: str,
8990
default_value: str,
9091
evaluation_context: EvaluationContext = None,
9192
flag_evaluation_options: typing.Any = None,
9293
) -> FlagEvaluationDetails:
9394
return self.evaluate_flag_details(
9495
FlagType.STRING,
95-
key,
96+
flag_key,
9697
default_value,
9798
evaluation_context,
9899
flag_evaluation_options,
99100
)
100101

101102
def get_number_value(
102103
self,
103-
key: str,
104+
flag_key: str,
104105
default_value: Number,
105106
evaluation_context: EvaluationContext = None,
106107
flag_evaluation_options: typing.Any = None,
107108
) -> Number:
108109
return self.evaluate_flag_details(
109110
FlagType.NUMBER,
110-
key,
111+
flag_key,
111112
default_value,
112113
evaluation_context,
113114
flag_evaluation_options,
114115
).value
115116

116117
def get_number_details(
117118
self,
118-
key: str,
119+
flag_key: str,
119120
default_value: Number,
120121
evaluation_context: EvaluationContext = None,
121122
flag_evaluation_options: typing.Any = None,
122123
) -> FlagEvaluationDetails:
123124
return self.evaluate_flag_details(
124125
FlagType.NUMBER,
125-
key,
126+
flag_key,
126127
default_value,
127128
evaluation_context,
128129
flag_evaluation_options,
129130
)
130131

131132
def get_object_value(
132133
self,
133-
key: str,
134+
flag_key: str,
134135
default_value: dict,
135136
evaluation_context: EvaluationContext = None,
136137
flag_evaluation_options: typing.Any = None,
137138
) -> dict:
138139
return self.evaluate_flag_details(
139140
FlagType.OBJECT,
140-
key,
141+
flag_key,
141142
default_value,
142143
evaluation_context,
143144
flag_evaluation_options,
144145
).value
145146

146147
def get_object_details(
147148
self,
148-
key: str,
149+
flag_key: str,
149150
default_value: dict,
150151
evaluation_context: EvaluationContext = None,
151152
flag_evaluation_options: typing.Any = None,
152153
) -> FlagEvaluationDetails:
153154
return self.evaluate_flag_details(
154155
FlagType.OBJECT,
155-
key,
156+
flag_key,
156157
default_value,
157158
evaluation_context,
158159
flag_evaluation_options,
@@ -161,7 +162,7 @@ def get_object_details(
161162
def evaluate_flag_details(
162163
self,
163164
flag_type: FlagType,
164-
key: str,
165+
flag_key: str,
165166
default_value: typing.Any,
166167
evaluation_context: EvaluationContext = None,
167168
flag_evaluation_options: typing.Any = None,
@@ -182,7 +183,7 @@ def evaluate_flag_details(
182183
evaluation_context = EvaluationContext()
183184

184185
hook_context = HookContext(
185-
flag_key=key,
186+
flag_key=flag_key,
186187
flag_type=flag_type,
187188
default_value=default_value,
188189
evaluation_context=evaluation_context,
@@ -207,7 +208,7 @@ def evaluate_flag_details(
207208

208209
flag_evaluation = self.create_provider_evaluation(
209210
flag_type,
210-
key,
211+
flag_key,
211212
default_value,
212213
merged_context,
213214
)
@@ -216,15 +217,26 @@ def evaluate_flag_details(
216217

217218
return flag_evaluation
218219

220+
except OpenFeatureError as e: # noqa
221+
error_hooks(flag_type, hook_context, e, merged_hooks, None)
222+
return FlagEvaluationDetails(
223+
flag_key=flag_key,
224+
value=default_value,
225+
reason=Reason.ERROR,
226+
error_code=e.error_code,
227+
error_message=e.error_message,
228+
)
219229
# Catch any type of exception here since the user can provide any exception
220230
# in the error hooks
221231
except Exception as e: # noqa
222232
error_hooks(flag_type, hook_context, e, merged_hooks, None)
233+
error_message = getattr(e, "error_message", str(e))
223234
return FlagEvaluationDetails(
224-
key=key,
235+
flag_key=flag_key,
225236
value=default_value,
226237
reason=Reason.ERROR,
227-
error_code=e.error_message,
238+
error_code=ErrorCode.GENERAL,
239+
error_message=error_message,
228240
)
229241

230242
finally:
@@ -233,7 +245,7 @@ def evaluate_flag_details(
233245
def create_provider_evaluation(
234246
self,
235247
flag_type: FlagType,
236-
key: str,
248+
flag_key: str,
237249
default_value: typing.Any,
238250
evaluation_context: EvaluationContext = None,
239251
) -> FlagEvaluationDetails:
@@ -248,7 +260,7 @@ def create_provider_evaluation(
248260
provider
249261
"""
250262
args = (
251-
key,
263+
flag_key,
252264
default_value,
253265
evaluation_context,
254266
)

open_feature/provider/no_op_provider.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,51 +14,51 @@ def get_name(self) -> str:
1414

1515
def get_boolean_details(
1616
self,
17-
key: str,
17+
flag_key: str,
1818
default_value: bool,
1919
evaluation_context: EvaluationContext = None,
2020
):
2121
return FlagEvaluationDetails(
22-
key=key,
22+
flag_key=flag_key,
2323
value=default_value,
2424
reason=Reason.DEFAULT,
2525
variant=PASSED_IN_DEFAULT,
2626
)
2727

2828
def get_string_details(
2929
self,
30-
key: str,
30+
flag_key: str,
3131
default_value: str,
3232
evaluation_context: EvaluationContext = None,
3333
):
3434
return FlagEvaluationDetails(
35-
key=key,
35+
flag_key=flag_key,
3636
value=default_value,
3737
reason=Reason.DEFAULT,
3838
variant=PASSED_IN_DEFAULT,
3939
)
4040

4141
def get_number_details(
4242
self,
43-
key: str,
43+
flag_key: str,
4444
default_value: Number,
4545
evaluation_context: EvaluationContext = None,
4646
):
4747
return FlagEvaluationDetails(
48-
key=key,
48+
flag_key=flag_key,
4949
value=default_value,
5050
reason=Reason.DEFAULT,
5151
variant=PASSED_IN_DEFAULT,
5252
)
5353

5454
def get_object_details(
5555
self,
56-
key: str,
56+
flag_key: str,
5757
default_value: dict,
5858
evaluation_context: EvaluationContext = None,
5959
):
6060
return FlagEvaluationDetails(
61-
key=key,
61+
flag_key=flag_key,
6262
value=default_value,
6363
reason=Reason.DEFAULT,
6464
variant=PASSED_IN_DEFAULT,

open_feature/provider/provider.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def get_name(self) -> str:
1212
@abstractmethod
1313
def get_boolean_details(
1414
self,
15-
key: str,
15+
flag_key: str,
1616
default_value: bool,
1717
evaluation_context: EvaluationContext = EvaluationContext(),
1818
):
@@ -21,7 +21,7 @@ def get_boolean_details(
2121
@abstractmethod
2222
def get_string_details(
2323
self,
24-
key: str,
24+
flag_key: str,
2525
default_value: str,
2626
evaluation_context: EvaluationContext = EvaluationContext(),
2727
):
@@ -30,7 +30,7 @@ def get_string_details(
3030
@abstractmethod
3131
def get_number_details(
3232
self,
33-
key: str,
33+
flag_key: str,
3434
default_value: Number,
3535
evaluation_context: EvaluationContext = EvaluationContext(),
3636
):
@@ -39,7 +39,7 @@ def get_number_details(
3939
@abstractmethod
4040
def get_object_details(
4141
self,
42-
key: str,
42+
flag_key: str,
4343
default_value: dict,
4444
evaluation_context: EvaluationContext = EvaluationContext(),
4545
):

tests/provider/test_no_op_provider.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def setup():
1313
def test_should_get_boolean_flag_from_no_op(no_op_provider_client):
1414
# Given
1515
# When
16-
flag = no_op_provider_client.get_boolean_details(key="Key", default_value=True)
16+
flag = no_op_provider_client.get_boolean_details(flag_key="Key", default_value=True)
1717
# Then
1818
assert flag is not None
1919
assert flag.value
@@ -23,7 +23,7 @@ def test_should_get_boolean_flag_from_no_op(no_op_provider_client):
2323
def test_should_get_number_flag_from_no_op(no_op_provider_client):
2424
# Given
2525
# When
26-
flag = no_op_provider_client.get_number_details(key="Key", default_value=100)
26+
flag = no_op_provider_client.get_number_details(flag_key="Key", default_value=100)
2727
# Then
2828
assert flag is not None
2929
assert flag.value == 100
@@ -33,7 +33,9 @@ def test_should_get_number_flag_from_no_op(no_op_provider_client):
3333
def test_should_get_string_flag_from_no_op(no_op_provider_client):
3434
# Given
3535
# When
36-
flag = no_op_provider_client.get_string_details(key="Key", default_value="String")
36+
flag = no_op_provider_client.get_string_details(
37+
flag_key="Key", default_value="String"
38+
)
3739
# Then
3840
assert flag is not None
3941
assert flag.value == "String"
@@ -49,7 +51,7 @@ def test_should_get_object_flag_from_no_op(no_op_provider_client):
4951
}
5052
# When
5153
flag = no_op_provider_client.get_string_details(
52-
key="Key", default_value=return_value
54+
flag_key="Key", default_value=return_value
5355
)
5456
# Then
5557
assert flag is not None

0 commit comments

Comments
 (0)