@@ -150,6 +150,7 @@ def evaluate_flag_dependency(
150150 properties ,
151151 cohort_properties ,
152152 device_id = None ,
153+ property_matching_version : int = 1 ,
153154):
154155 """
155156 Evaluate a flag dependency condition under local evaluation.
@@ -260,6 +261,7 @@ def evaluate_flag_dependency(
260261 flags_by_key = flags_by_key ,
261262 evaluation_cache = evaluation_cache ,
262263 device_id = device_id ,
264+ property_matching_version = property_matching_version ,
263265 bucketing_value = dep_bucketing_value ,
264266 )
265267 evaluation_cache [dep_flag_key ] = dep_result
@@ -350,6 +352,7 @@ def match_feature_flag_properties(
350352 group_type_mapping = None ,
351353 groups = None ,
352354 group_properties = None ,
355+ property_matching_version : int = 1 ,
353356) -> FlagValue :
354357 if bucketing_value is None :
355358 warnings .warn (
@@ -416,6 +419,7 @@ def match_feature_flag_properties(
416419 evaluation_cache ,
417420 bucketing_value = effective_bucketing ,
418421 device_id = device_id ,
422+ property_matching_version = property_matching_version ,
419423 )
420424 if match_result == ConditionMatch .MATCH :
421425 variant_override = condition .get ("variant" )
@@ -463,6 +467,7 @@ def is_condition_match(
463467 * ,
464468 bucketing_value ,
465469 device_id = None ,
470+ property_matching_version : int = 1 ,
466471) -> ConditionMatch :
467472 rollout_percentage = condition .get ("rollout_percentage" )
468473 if len (condition .get ("properties" ) or []) > 0 :
@@ -477,6 +482,7 @@ def is_condition_match(
477482 evaluation_cache ,
478483 distinct_id ,
479484 device_id = device_id ,
485+ property_matching_version = property_matching_version ,
480486 )
481487 elif property_type == "flag" :
482488 matches = evaluate_flag_dependency (
@@ -487,9 +493,10 @@ def is_condition_match(
487493 properties ,
488494 cohort_properties ,
489495 device_id = device_id ,
496+ property_matching_version = property_matching_version ,
490497 )
491498 else :
492- matches = match_property (prop , properties )
499+ matches = match_property (prop , properties , property_matching_version )
493500 if not matches :
494501 return ConditionMatch .NO_MATCH
495502
@@ -593,7 +600,9 @@ def _is_truthy_property_value(value) -> bool:
593600 return False
594601
595602
596- def match_property (property , property_values ) -> bool :
603+ def match_property (
604+ property , property_values , property_matching_version : int = 1
605+ ) -> bool :
597606 # only looks for matches where key exists in override_property_values
598607 key = property .get ("key" )
599608 operator = property .get ("operator" ) or "exact"
@@ -623,7 +632,12 @@ def match_property(property, property_values) -> bool:
623632
624633 def compute_exact_match (value , override_value ):
625634 override_string = _value_to_string (override_value ).lower ()
626- if _is_truthy_or_falsy_property_value (value ):
635+ # Empty filters retain recursive truthiness in both matching modes.
636+ if value == []:
637+ return _is_truthy_property_value (override_value )
638+ if property_matching_version != 2 and _is_truthy_or_falsy_property_value (
639+ value
640+ ):
627641 return _is_truthy_property_value (value ) == _is_truthy_property_value (
628642 override_value
629643 )
@@ -814,6 +828,7 @@ def match_cohort(
814828 evaluation_cache = None ,
815829 distinct_id = None ,
816830 device_id = None ,
831+ property_matching_version : int = 1 ,
817832) -> bool :
818833 # Cohort properties are in the form of property groups like this:
819834 # {
@@ -839,6 +854,7 @@ def match_cohort(
839854 evaluation_cache ,
840855 distinct_id ,
841856 device_id = device_id ,
857+ property_matching_version = property_matching_version ,
842858 )
843859
844860 operator = property .get ("operator" ) or "exact"
@@ -857,6 +873,7 @@ def match_property_group(
857873 evaluation_cache = None ,
858874 distinct_id = None ,
859875 device_id = None ,
876+ property_matching_version : int = 1 ,
860877) -> bool :
861878 # The backend serializes its canonical empty PropertyGroup as {}.
862879 if property_group == {}:
@@ -893,6 +910,7 @@ def match_property_group(
893910 evaluation_cache ,
894911 distinct_id ,
895912 device_id = device_id ,
913+ property_matching_version = property_matching_version ,
896914 )
897915 negation = False
898916 elif prop .get ("type" ) == "cohort" :
@@ -904,6 +922,7 @@ def match_property_group(
904922 evaluation_cache ,
905923 distinct_id ,
906924 device_id = device_id ,
925+ property_matching_version = property_matching_version ,
907926 )
908927 negation = prop .get ("negation" , False )
909928 elif prop .get ("type" ) == "flag" :
@@ -915,10 +934,13 @@ def match_property_group(
915934 property_values ,
916935 cohort_properties ,
917936 device_id = device_id ,
937+ property_matching_version = property_matching_version ,
918938 )
919939 negation = prop .get ("negation" , False )
920940 else :
921- matches = match_property (prop , property_values )
941+ matches = match_property (
942+ prop , property_values , property_matching_version
943+ )
922944 negation = prop .get ("negation" , False )
923945
924946 effective_match = matches != bool (negation )
0 commit comments