1717from datetime import datetime
1818
1919from .user import User
20- from .utils import unicode_to_utf8 , encode_utf8 , get_seconds_since_epoch
20+ from .utils import unicode_to_utf8 , encode_utf8 , get_seconds_since_epoch , is_string_list
2121
2222
2323def sha256 (value_utf8 , salt , context_salt ):
@@ -151,7 +151,7 @@ def _user_attribute_value_to_string(self, value):
151151
152152 if isinstance (value , datetime ):
153153 value = self ._get_user_attribute_value_as_seconds_since_epoch (value )
154- elif isinstance (value , list ):
154+ elif is_string_list (value ):
155155 value = self ._get_user_attribute_value_as_string_list (value )
156156 return json .dumps (value , ensure_ascii = False , separators = (',' , ':' )) # Convert the list to a JSON string
157157
@@ -198,25 +198,15 @@ def _get_user_attribute_value_as_seconds_since_epoch(self, attribute_value):
198198 return self ._convert_numeric_to_float (attribute_value )
199199
200200 def _get_user_attribute_value_as_string_list (self , attribute_value ):
201- if not isinstance (attribute_value , list ):
201+ # Handle unicode strings on Python 2.7
202+ if isinstance (attribute_value , str ) or sys .version_info [0 ] == 2 and isinstance (attribute_value , unicode ): # noqa: F821
202203 attribute_value_list = json .loads (attribute_value )
203204 else :
204205 attribute_value_list = attribute_value
205206
206- # Check if the result is a list
207- if not isinstance (attribute_value_list , list ):
207+ if not is_string_list (attribute_value_list ):
208208 raise ValueError ()
209209
210- # Check if all items in the list are strings
211- for item in attribute_value_list :
212- # Handle unicode strings on Python 2.7
213- if sys .version_info [0 ] == 2 :
214- if not isinstance (attribute_value , (str , unicode )): # noqa: F821
215- return attribute_value
216- else :
217- if not isinstance (item , str ):
218- raise ValueError ()
219-
220210 return attribute_value_list
221211
222212 def _handle_invalid_user_attribute (self , comparison_attribute , comparator , comparison_value , key , validation_error ):
@@ -285,6 +275,12 @@ def _evaluate_percentage_options(self, percentage_options, context, percentage_r
285275 hash_candidate = ('%s%s' % (key , self ._user_attribute_value_to_string (user_key ))).encode ('utf-8' )
286276 hash_val = int (hashlib .sha1 (hash_candidate ).hexdigest ()[:7 ], 16 ) % 100
287277
278+ if log_builder :
279+ log_builder .new_line ('Evaluating %% options based on the User.%s attribute:' % user_attribute_name )
280+ log_builder .new_line ('- Computing hash in the [0..99] range from User.%s => %s '
281+ '(this value is sticky and consistent across all SDKs)' %
282+ (user_attribute_name , hash_val ))
283+
288284 bucket = 0
289285 index = 1
290286 for percentage_option in percentage_options or []:
@@ -294,11 +290,6 @@ def _evaluate_percentage_options(self, percentage_options, context, percentage_r
294290 percentage_value = get_value (percentage_option , context .setting_type )
295291 variation_id = percentage_option .get (VARIATION_ID , default_variation_id )
296292 if log_builder :
297- log_builder .new_line ('Evaluating %% options based on the User.%s attribute:' %
298- user_attribute_name )
299- log_builder .new_line ('- Computing hash in the [0..99] range from User.%s => %s '
300- '(this value is sticky and consistent across all SDKs)' %
301- (user_attribute_name , hash_val ))
302293 log_builder .new_line ("- Hash value %s selects %% option %s (%s%%), '%s'." %
303294 (hash_val , index , percentage , percentage_value ))
304295 return True , percentage_value , variation_id , percentage_option
@@ -421,8 +412,7 @@ def _evaluate_prerequisite_flag_condition(self, prerequisite_flag_condition, con
421412 prerequisite_value , _ , _ , _ , _ = self .evaluate (prerequisite_key , context .user , None , None , config ,
422413 log_builder , context .visited_keys )
423414
424- if visited_keys :
425- visited_keys .pop ()
415+ visited_keys .pop ()
426416
427417 if log_builder :
428418 log_builder .new_line ("Prerequisite flag evaluation result: '%s'." % str (prerequisite_value ))
@@ -438,6 +428,8 @@ def _evaluate_prerequisite_flag_condition(self, prerequisite_flag_condition, con
438428 elif prerequisite_comparator == PrerequisiteComparator .NOT_EQUALS :
439429 if prerequisite_value != prerequisite_comparison_value :
440430 prerequisite_condition_result = True
431+ else :
432+ raise ValueError ('Comparison operator is missing or invalid.' )
441433
442434 if log_builder :
443435 log_builder .append ('%s.' % ('true' if prerequisite_condition_result else 'false' ))
@@ -527,7 +519,7 @@ def _evaluate_segment_condition(self, segment_condition, context, salt, log_buil
527519
528520 return segment_condition_result , error
529521
530- return False , None
522+ raise ValueError ( 'Comparison operator is missing or invalid.' )
531523
532524 def _evaluate_user_condition (self , user_condition , context , context_salt , salt , log_builder ): # noqa: C901, E501
533525 """
@@ -562,7 +554,7 @@ def _evaluate_user_condition(self, user_condition, context, context_salt, salt,
562554 return False , error
563555
564556 user_value = user .get_attribute (comparison_attribute )
565- if user_value is None or (not user_value and not isinstance (user_value , list ) ):
557+ if user_value is None or (isinstance ( user_value , str ) and len (user_value ) == 0 ):
566558 self .log .warning ('Cannot evaluate condition (%s) for setting \' %s\' '
567559 '(the User.%s attribute is missing). You should set the User.%s attribute in order to make '
568560 'targeting work properly. Read more: https://configcat.com/docs/advanced/user-object/' ,
@@ -764,5 +756,7 @@ def _evaluate_user_condition(self, user_condition, context, context_salt, salt,
764756 if comparison in user_value_list :
765757 return False , None
766758 return True , error
759+ else :
760+ raise ValueError ('Comparison operator is missing or invalid.' )
767761
768762 return False , error
0 commit comments