diff --git a/.gitmodules b/.gitmodules index 32a69b0..f85ff0d 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 = v2.1.0 + tag = v2.2.0 \ No newline at end of file diff --git a/flag_engine/segments/evaluator.py b/flag_engine/segments/evaluator.py index 6cfc799..2d7d537 100644 --- a/flag_engine/segments/evaluator.py +++ b/flag_engine/segments/evaluator.py @@ -4,7 +4,7 @@ import typing import warnings from contextlib import suppress -from functools import lru_cache, wraps +from functools import lru_cache, partial, wraps import jsonpath_rfc9535 import semver @@ -26,7 +26,7 @@ SegmentMetadataT, is_context_value, ) -from flag_engine.segments.utils import escape_double_quotes, get_matching_function +from flag_engine.segments.utils import get_matching_function from flag_engine.utils.hashing import get_hashed_percentage_for_object_ids from flag_engine.utils.semver import is_semver from flag_engine.utils.types import SupportsStr, get_casting_function @@ -268,9 +268,8 @@ def get_context_value( value = None if property.startswith("$."): value = _get_context_value_getter(property)(context) - elif identity_context := context.get("identity"): - if traits := identity_context.get("traits"): - value = traits.get(property) + else: + value = _get_trait_value(context, property) return map_any_value_to_context_value(value) @@ -357,6 +356,16 @@ def inner( } +def _get_trait_value( + context: EvaluationContext[SegmentMetadataT], + trait_key: str, +) -> ContextValue: + if identity_context := context.get("identity"): + if traits := identity_context.get("traits"): + return traits.get(trait_key) + return None + + @lru_cache def _get_context_value_getter( property: str, @@ -373,11 +382,12 @@ def _get_context_value_getter( except jsonpath_rfc9535.JSONPathSyntaxError: # This covers a rare case when a trait starting with "$.", # but not a valid JSONPath, is used. - compiled_query = jsonpath_rfc9535.compile( - f'$.identity.traits["{escape_double_quotes(property)}"]', - ) + return partial(_get_trait_value, trait_key=property) def getter(context: EvaluationContext[SegmentMetadataT]) -> ContextValue: + value: object + if (value := _get_trait_value(context, property)) is not None: + return value if typing.TYPE_CHECKING: # pragma: no cover # Ugly hack to satisfy mypy :( data = dict(context) diff --git a/flag_engine/segments/utils.py b/flag_engine/segments/utils.py index 98fdbae..3dc0ff2 100644 --- a/flag_engine/segments/utils.py +++ b/flag_engine/segments/utils.py @@ -15,10 +15,3 @@ def get_matching_function( def none(iterable: typing.Iterable[object]) -> bool: return not any(iterable) - - -def escape_double_quotes(value: str) -> str: - """ - Escape double quotes in a string for JSONPath compatibility. - """ - return value.replace('"', '\\"') diff --git a/tests/engine_tests/engine-test-data b/tests/engine_tests/engine-test-data index 37606e4..c69e2eb 160000 --- a/tests/engine_tests/engine-test-data +++ b/tests/engine_tests/engine-test-data @@ -1 +1 @@ -Subproject commit 37606e4437d1bd0ee6d86d79828c70a46e94fc8e +Subproject commit c69e2ebcbc8602a77ddfe98181e01ad5c503417d