12
12
# limitations under the License.
13
13
14
14
import json
15
+ import numbers
15
16
16
17
from six import string_types
17
18
18
19
from . import validator
20
+ from .enums import AudienceEvaluationLogs as audience_logs
19
21
20
22
21
23
class ConditionOperatorTypes (object ):
@@ -37,20 +39,47 @@ class CustomAttributeConditionEvaluator(object):
37
39
38
40
CUSTOM_ATTRIBUTE_CONDITION_TYPE = 'custom_attribute'
39
41
40
- def __init__ (self , condition_data , attributes ):
42
+ def __init__ (self , condition_data , attributes , logger ):
41
43
self .condition_data = condition_data
42
44
self .attributes = attributes or {}
45
+ self .logger = logger
43
46
44
- def is_value_valid_for_exact_conditions (self , value ):
47
+ def _get_condition_json (self , index ):
48
+ """ Method to generate json for logging audience condition.
49
+
50
+ Args:
51
+ index: Index of the condition.
52
+
53
+ Returns:
54
+ String: Audience condition JSON.
55
+ """
56
+ condition = self .condition_data [index ]
57
+ condition_log = {
58
+ 'name' : condition [0 ],
59
+ 'value' : condition [1 ],
60
+ 'type' : condition [2 ],
61
+ 'match' : condition [3 ]
62
+ }
63
+
64
+ return json .dumps (condition_log )
65
+
66
+ def is_value_type_valid_for_exact_conditions (self , value ):
45
67
""" Method to validate if the value is valid for exact match type evaluation.
46
68
47
69
Args:
48
70
value: Value to validate.
49
71
50
72
Returns:
51
- Boolean: True if value is a string type, or a boolean, or is finite . Otherwise False.
73
+ Boolean: True if value is a string, boolean, or number . Otherwise False.
52
74
"""
53
- if isinstance (value , string_types ) or isinstance (value , bool ) or validator .is_finite_number (value ):
75
+ # No need to check for bool since bool is a subclass of int
76
+ if isinstance (value , string_types ) or isinstance (value , (numbers .Integral , float )):
77
+ return True
78
+
79
+ return False
80
+
81
+ def is_value_a_number (self , value ):
82
+ if isinstance (value , (numbers .Integral , float )) and not isinstance (value , bool ):
54
83
return True
55
84
56
85
return False
@@ -69,12 +98,32 @@ def exact_evaluator(self, index):
69
98
- if the condition value or user attribute value has an invalid type.
70
99
- if there is a mismatch between the user attribute type and the condition value type.
71
100
"""
101
+ condition_name = self .condition_data [index ][0 ]
72
102
condition_value = self .condition_data [index ][1 ]
73
- user_value = self .attributes .get (self . condition_data [ index ][ 0 ] )
103
+ user_value = self .attributes .get (condition_name )
74
104
75
- if not self .is_value_valid_for_exact_conditions (condition_value ) or \
76
- not self .is_value_valid_for_exact_conditions (user_value ) or \
105
+ if not self .is_value_type_valid_for_exact_conditions (condition_value ) or \
106
+ (self .is_value_a_number (condition_value ) and not validator .is_finite_number (condition_value )):
107
+ self .logger .warning (audience_logs .UNKNOWN_CONDITION_VALUE .format (
108
+ self ._get_condition_json (index )
109
+ ))
110
+ return None
111
+
112
+ if not self .is_value_type_valid_for_exact_conditions (user_value ) or \
77
113
not validator .are_values_same_type (condition_value , user_value ):
114
+ self .logger .warning (audience_logs .UNEXPECTED_TYPE .format (
115
+ self ._get_condition_json (index ),
116
+ type (user_value ),
117
+ condition_name
118
+ ))
119
+ return None
120
+
121
+ if self .is_value_a_number (user_value ) and \
122
+ not validator .is_finite_number (user_value ):
123
+ self .logger .warning (audience_logs .INFINITE_ATTRIBUTE_VALUE .format (
124
+ self ._get_condition_json (index ),
125
+ condition_name
126
+ ))
78
127
return None
79
128
80
129
return condition_value == user_value
@@ -104,10 +153,29 @@ def greater_than_evaluator(self, index):
104
153
- False if the user attribute value is less than or equal to the condition value.
105
154
None: if the condition value isn't finite or the user attribute value isn't finite.
106
155
"""
156
+ condition_name = self .condition_data [index ][0 ]
107
157
condition_value = self .condition_data [index ][1 ]
108
- user_value = self .attributes .get (self . condition_data [ index ][ 0 ] )
158
+ user_value = self .attributes .get (condition_name )
109
159
110
- if not validator .is_finite_number (condition_value ) or not validator .is_finite_number (user_value ):
160
+ if not validator .is_finite_number (condition_value ):
161
+ self .logger .warning (audience_logs .UNKNOWN_CONDITION_VALUE .format (
162
+ self ._get_condition_json (index )
163
+ ))
164
+ return None
165
+
166
+ if not self .is_value_a_number (user_value ):
167
+ self .logger .warning (audience_logs .UNEXPECTED_TYPE .format (
168
+ self ._get_condition_json (index ),
169
+ type (user_value ),
170
+ condition_name
171
+ ))
172
+ return None
173
+
174
+ if not validator .is_finite_number (user_value ):
175
+ self .logger .warning (audience_logs .INFINITE_ATTRIBUTE_VALUE .format (
176
+ self ._get_condition_json (index ),
177
+ condition_name
178
+ ))
111
179
return None
112
180
113
181
return user_value > condition_value
@@ -124,10 +192,29 @@ def less_than_evaluator(self, index):
124
192
- False if the user attribute value is greater than or equal to the condition value.
125
193
None: if the condition value isn't finite or the user attribute value isn't finite.
126
194
"""
195
+ condition_name = self .condition_data [index ][0 ]
127
196
condition_value = self .condition_data [index ][1 ]
128
- user_value = self .attributes .get (self .condition_data [index ][0 ])
197
+ user_value = self .attributes .get (condition_name )
198
+
199
+ if not validator .is_finite_number (condition_value ):
200
+ self .logger .warning (audience_logs .UNKNOWN_CONDITION_VALUE .format (
201
+ self ._get_condition_json (index )
202
+ ))
203
+ return None
204
+
205
+ if not self .is_value_a_number (user_value ):
206
+ self .logger .warning (audience_logs .UNEXPECTED_TYPE .format (
207
+ self ._get_condition_json (index ),
208
+ type (user_value ),
209
+ condition_name
210
+ ))
211
+ return None
129
212
130
- if not validator .is_finite_number (condition_value ) or not validator .is_finite_number (user_value ):
213
+ if not validator .is_finite_number (user_value ):
214
+ self .logger .warning (audience_logs .INFINITE_ATTRIBUTE_VALUE .format (
215
+ self ._get_condition_json (index ),
216
+ condition_name
217
+ ))
131
218
return None
132
219
133
220
return user_value < condition_value
@@ -144,10 +231,22 @@ def substring_evaluator(self, index):
144
231
- False if the condition value is not a substring of the user attribute value.
145
232
None: if the condition value isn't a string or the user attribute value isn't a string.
146
233
"""
234
+ condition_name = self .condition_data [index ][0 ]
147
235
condition_value = self .condition_data [index ][1 ]
148
- user_value = self .attributes .get (self .condition_data [index ][0 ])
236
+ user_value = self .attributes .get (condition_name )
237
+
238
+ if not isinstance (condition_value , string_types ):
239
+ self .logger .warning (audience_logs .UNKNOWN_CONDITION_VALUE .format (
240
+ self ._get_condition_json (index ),
241
+ ))
242
+ return None
149
243
150
- if not isinstance (condition_value , string_types ) or not isinstance (user_value , string_types ):
244
+ if not isinstance (user_value , string_types ):
245
+ self .logger .warning (audience_logs .UNEXPECTED_TYPE .format (
246
+ self ._get_condition_json (index ),
247
+ type (user_value ),
248
+ condition_name
249
+ ))
151
250
return None
152
251
153
252
return condition_value in user_value
@@ -175,15 +274,27 @@ def evaluate(self, index):
175
274
"""
176
275
177
276
if self .condition_data [index ][2 ] != self .CUSTOM_ATTRIBUTE_CONDITION_TYPE :
277
+ self .logger .warning (audience_logs .UNKNOWN_CONDITION_TYPE .format (self ._get_condition_json (index )))
178
278
return None
179
279
180
280
condition_match = self .condition_data [index ][3 ]
181
281
if condition_match is None :
182
282
condition_match = ConditionMatchTypes .EXACT
183
283
184
284
if condition_match not in self .EVALUATORS_BY_MATCH_TYPE :
285
+ self .logger .warning (audience_logs .UNKNOWN_MATCH_TYPE .format (self ._get_condition_json (index )))
185
286
return None
186
287
288
+ if condition_match != ConditionMatchTypes .EXISTS :
289
+ attribute_key = self .condition_data [index ][0 ]
290
+ if attribute_key not in self .attributes :
291
+ self .logger .debug (audience_logs .MISSING_ATTRIBUTE_VALUE .format (self ._get_condition_json (index ), attribute_key ))
292
+ return None
293
+
294
+ if self .attributes .get (attribute_key ) is None :
295
+ self .logger .debug (audience_logs .NULL_ATTRIBUTE_VALUE .format (self ._get_condition_json (index ), attribute_key ))
296
+ return None
297
+
187
298
return self .EVALUATORS_BY_MATCH_TYPE [condition_match ](self , index )
188
299
189
300
0 commit comments