1212# limitations under the License.
1313
1414import json
15+ import numbers
1516
1617from six import string_types
1718
1819from . import validator
20+ from .enums import AudienceEvaluationLogs as audience_logs
1921
2022
2123class ConditionOperatorTypes (object ):
@@ -37,20 +39,47 @@ class CustomAttributeConditionEvaluator(object):
3739
3840 CUSTOM_ATTRIBUTE_CONDITION_TYPE = 'custom_attribute'
3941
40- def __init__ (self , condition_data , attributes ):
42+ def __init__ (self , condition_data , attributes , logger ):
4143 self .condition_data = condition_data
4244 self .attributes = attributes or {}
45+ self .logger = logger
4346
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 ):
4567 """ Method to validate if the value is valid for exact match type evaluation.
4668
4769 Args:
4870 value: Value to validate.
4971
5072 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.
5274 """
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 ):
5483 return True
5584
5685 return False
@@ -69,12 +98,32 @@ def exact_evaluator(self, index):
6998 - if the condition value or user attribute value has an invalid type.
7099 - if there is a mismatch between the user attribute type and the condition value type.
71100 """
101+ condition_name = self .condition_data [index ][0 ]
72102 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 )
74104
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 \
77113 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+ ))
78127 return None
79128
80129 return condition_value == user_value
@@ -104,10 +153,29 @@ def greater_than_evaluator(self, index):
104153 - False if the user attribute value is less than or equal to the condition value.
105154 None: if the condition value isn't finite or the user attribute value isn't finite.
106155 """
156+ condition_name = self .condition_data [index ][0 ]
107157 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 )
109159
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+ ))
111179 return None
112180
113181 return user_value > condition_value
@@ -124,10 +192,29 @@ def less_than_evaluator(self, index):
124192 - False if the user attribute value is greater than or equal to the condition value.
125193 None: if the condition value isn't finite or the user attribute value isn't finite.
126194 """
195+ condition_name = self .condition_data [index ][0 ]
127196 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
129212
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+ ))
131218 return None
132219
133220 return user_value < condition_value
@@ -144,10 +231,22 @@ def substring_evaluator(self, index):
144231 - False if the condition value is not a substring of the user attribute value.
145232 None: if the condition value isn't a string or the user attribute value isn't a string.
146233 """
234+ condition_name = self .condition_data [index ][0 ]
147235 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
149243
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+ ))
151250 return None
152251
153252 return condition_value in user_value
@@ -175,15 +274,27 @@ def evaluate(self, index):
175274 """
176275
177276 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 )))
178278 return None
179279
180280 condition_match = self .condition_data [index ][3 ]
181281 if condition_match is None :
182282 condition_match = ConditionMatchTypes .EXACT
183283
184284 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 )))
185286 return None
186287
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+
187298 return self .EVALUATORS_BY_MATCH_TYPE [condition_match ](self , index )
188299
189300
0 commit comments