From 09bbc8e88574e439949b4916dda483ecc62d7fd7 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 24 Nov 2025 16:15:36 +0000 Subject: [PATCH] fix: Exclude identities when PERCENTAGE_SPLIT trait is undefined --- .gitmodules | 2 +- flag_engine/segments/evaluator.py | 36 +++++++++++++++++------------ tests/engine_tests/engine-test-data | 2 +- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8a03ce7..1f6cd95 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "tests/engine_tests/engine-test-data"] path = tests/engine_tests/engine-test-data url = https://github.com/flagsmith/engine-test-data.git - tag = v3.3.0 + tag = v3.5.0 diff --git a/flag_engine/segments/evaluator.py b/flag_engine/segments/evaluator.py index abf3013..78cd44d 100644 --- a/flag_engine/segments/evaluator.py +++ b/flag_engine/segments/evaluator.py @@ -264,13 +264,21 @@ def context_matches_condition( condition: SegmentCondition, segment_key: SupportsStr, ) -> bool: - context_value = ( - get_context_value(context, condition_property) - if (condition_property := condition.get("property")) - else None - ) + context_value: ContextValue + condition_property = condition["property"] + condition_operator = condition["operator"] + + if condition_operator == constants.PERCENTAGE_SPLIT and (not condition_property): + # Currently, the only supported condition with a blank property + # is percentage split. + # In this case, we use the identity key as context value. + # This is mainly to support legacy segments created before + # we introduced JSONPath support. + context_value = _get_identity_key(context) + else: + context_value = get_context_value(context, condition_property) - if condition["operator"] == constants.IN: + if condition_operator == constants.IN: if isinstance(segment_value := condition["value"], list): in_values = segment_value else: @@ -293,24 +301,22 @@ def context_matches_condition( condition = typing.cast(StrValueSegmentCondition, condition) - if condition["operator"] == constants.PERCENTAGE_SPLIT: - if context_value is not None: - object_ids = [segment_key, context_value] - elif identity_key := _get_identity_key(context): - object_ids = [segment_key, identity_key] - else: + if condition_operator == constants.PERCENTAGE_SPLIT: + if context_value is None: return False + object_ids = [segment_key, context_value] + try: float_value = float(condition["value"]) except ValueError: return False return get_hashed_percentage_for_object_ids(object_ids) <= float_value - if condition["operator"] == constants.IS_NOT_SET: + if condition_operator == constants.IS_NOT_SET: return context_value is None - if condition["operator"] == constants.IS_SET: + if condition_operator == constants.IS_SET: return context_value is not None return ( @@ -417,7 +423,7 @@ def inner( def _get_identity_key( context: _EvaluationContextAnyMeta, -) -> typing.Optional[SupportsStr]: +) -> typing.Optional[str]: if identity_context := context.get("identity"): return identity_context.get("key") return None diff --git a/tests/engine_tests/engine-test-data b/tests/engine_tests/engine-test-data index 024f7bf..7840a13 160000 --- a/tests/engine_tests/engine-test-data +++ b/tests/engine_tests/engine-test-data @@ -1 +1 @@ -Subproject commit 024f7bf6d2aa2090fae69874c87cf39e3d8b711e +Subproject commit 7840a1349b601df3b6b4a089f40864f659801afb