@@ -49,6 +49,29 @@ def _match_by_action(self, action: str, restriction_value: Any, context_value: A
49
49
self ._logger .error (f"caught exception while matching action, action={ action } , exception={ str (exc )} " )
50
50
return False
51
51
52
+ def _is_rule_matched (self , feature_name : str , rule : Dict [str , Any ], rules_context : Dict [str , Any ]) -> bool :
53
+ rule_name = rule .get (schema .RULE_NAME_KEY , "" )
54
+ rule_default_value = rule .get (schema .RULE_DEFAULT_VALUE )
55
+ restrictions : Dict [str , str ] = rule .get (schema .RESTRICTIONS_KEY )
56
+
57
+ for restriction in restrictions :
58
+ context_value = rules_context .get (restriction .get (schema .RESTRICTION_KEY ))
59
+ if not self ._match_by_action (
60
+ restriction .get (schema .RESTRICTION_ACTION ),
61
+ restriction .get (schema .RESTRICTION_VALUE ),
62
+ context_value ,
63
+ ):
64
+ logger .debug (
65
+ f"rule did not match action, rule_name={ rule_name } , rule_default_value={ rule_default_value } , feature_name={ feature_name } , context_value={ str (context_value )} " # noqa: E501
66
+ )
67
+ # context doesn't match restriction
68
+ return False
69
+ # if we got here, all restrictions match
70
+ logger .debug (
71
+ f"rule matched, rule_name={ rule_name } , rule_default_value={ rule_default_value } , feature_name={ feature_name } " # noqa: E501
72
+ )
73
+ return True
74
+
52
75
def _handle_rules (
53
76
self ,
54
77
* ,
@@ -58,34 +81,14 @@ def _handle_rules(
58
81
rules : List [Dict [str , Any ]],
59
82
) -> bool :
60
83
for rule in rules :
61
- rule_name = rule .get (schema .RULE_NAME_KEY , "" )
62
84
rule_default_value = rule .get (schema .RULE_DEFAULT_VALUE )
63
- is_match = True
64
- restrictions : Dict [str , str ] = rule .get (schema .RESTRICTIONS_KEY )
65
-
66
- for restriction in restrictions :
67
- context_value = rules_context .get (restriction .get (schema .RESTRICTION_KEY ))
68
- if not self ._match_by_action (
69
- restriction .get (schema .RESTRICTION_ACTION ),
70
- restriction .get (schema .RESTRICTION_VALUE ),
71
- context_value ,
72
- ):
73
- logger .debug (
74
- f"rule did not match action, rule_name={ rule_name } , rule_default_value={ rule_default_value } , feature_name={ feature_name } , context_value={ str (context_value )} " # noqa: E501
75
- )
76
- is_match = False # rules doesn't match restriction
77
- break
78
- # if we got here, all restrictions match
79
- if is_match :
80
- logger .debug (
81
- f"rule matched, rule_name={ rule_name } , rule_default_value={ rule_default_value } , feature_name={ feature_name } " # noqa: E501
82
- )
85
+ if self ._is_rule_matched (feature_name , rule , rules_context ):
83
86
return rule_default_value
84
- # no rule matched, return default value of feature
85
- logger .debug (
86
- f"no rule matched, returning default value of feature, feature_default_value={ feature_default_value } , feature_name={ feature_name } " # noqa: E501
87
- )
88
- return feature_default_value
87
+ # no rule matched, return default value of feature
88
+ logger .debug (
89
+ f"no rule matched, returning default value of feature, feature_default_value={ feature_default_value } , feature_name={ feature_name } " # noqa: E501
90
+ )
91
+ return feature_default_value
89
92
90
93
def get_configuration (self ) -> Dict [str , Any ]:
91
94
"""Get configuration string from AWs AppConfig and returned the parsed JSON dictionary
@@ -162,3 +165,39 @@ def get_feature_toggle(self, *, feature_name: str, rules_context: Dict[str, Any]
162
165
feature_default_value = feature_default_value ,
163
166
rules = rules_list ,
164
167
)
168
+
169
+ def get_all_enabled_feature_toggles (self , * , rules_context : Dict [str , Any ]) -> List [str ]:
170
+ """Get all enabled feature toggles while also taking into account rule_context (when a feature has defined rules)
171
+
172
+ Args:
173
+ rules_context (Dict[str, Any]): dict of attributes that you would like to match the rules
174
+ against, can be {'tenant_id: 'X', 'username':' 'Y', 'region': 'Z'} etc.
175
+
176
+ Returns:
177
+ List[str]: a list of all features name that are enabled by also taking into account
178
+ rule_context (when a feature has defined rules)
179
+ """
180
+ try :
181
+ toggles_dict : Dict [str , Any ] = self .get_configuration ()
182
+ except ConfigurationException :
183
+ logger .error ("unable to get feature toggles JSON" ) # noqa: E501
184
+ return []
185
+ ret_list = []
186
+ features : Dict [str , Any ] = toggles_dict .get (schema .FEATURES_KEY , {})
187
+ for feature_name , feature_dict_def in features .items ():
188
+ rules_list = feature_dict_def .get (schema .RULES_KEY , [])
189
+ feature_default_value = feature_dict_def .get (schema .FEATURE_DEFAULT_VAL_KEY )
190
+ if feature_default_value and not rules_list :
191
+ self ._logger .debug (
192
+ f"feature is enabled by default and has no defined rules, feature_name={ feature_name } "
193
+ )
194
+ ret_list .append (feature_name )
195
+ elif self ._handle_rules (
196
+ feature_name = feature_name ,
197
+ rules_context = rules_context ,
198
+ feature_default_value = feature_default_value ,
199
+ rules = rules_list ,
200
+ ):
201
+ self ._logger .debug (f"feature's calculated value is True, feature_name={ feature_name } " )
202
+ ret_list .append (feature_name )
203
+ return ret_list
0 commit comments