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