Skip to content

Commit 789d737

Browse files
authored
fix: $.-prefixed traits are not prioritised over valid JSONPaths (#266)
1 parent 8ea7f68 commit 789d737

File tree

4 files changed

+20
-17
lines changed

4 files changed

+20
-17
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "tests/engine_tests/engine-test-data"]
22
path = tests/engine_tests/engine-test-data
33
url = https://github.com/flagsmith/engine-test-data.git
4-
tag = v2.1.0
4+
tag = v2.2.0

flag_engine/segments/evaluator.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import typing
55
import warnings
66
from contextlib import suppress
7-
from functools import lru_cache, wraps
7+
from functools import lru_cache, partial, wraps
88

99
import jsonpath_rfc9535
1010
import semver
@@ -26,7 +26,7 @@
2626
SegmentMetadataT,
2727
is_context_value,
2828
)
29-
from flag_engine.segments.utils import escape_double_quotes, get_matching_function
29+
from flag_engine.segments.utils import get_matching_function
3030
from flag_engine.utils.hashing import get_hashed_percentage_for_object_ids
3131
from flag_engine.utils.semver import is_semver
3232
from flag_engine.utils.types import SupportsStr, get_casting_function
@@ -268,9 +268,8 @@ def get_context_value(
268268
value = None
269269
if property.startswith("$."):
270270
value = _get_context_value_getter(property)(context)
271-
elif identity_context := context.get("identity"):
272-
if traits := identity_context.get("traits"):
273-
value = traits.get(property)
271+
else:
272+
value = _get_trait_value(context, property)
274273
return map_any_value_to_context_value(value)
275274

276275

@@ -357,6 +356,16 @@ def inner(
357356
}
358357

359358

359+
def _get_trait_value(
360+
context: EvaluationContext[SegmentMetadataT],
361+
trait_key: str,
362+
) -> ContextValue:
363+
if identity_context := context.get("identity"):
364+
if traits := identity_context.get("traits"):
365+
return traits.get(trait_key)
366+
return None
367+
368+
360369
@lru_cache
361370
def _get_context_value_getter(
362371
property: str,
@@ -373,11 +382,12 @@ def _get_context_value_getter(
373382
except jsonpath_rfc9535.JSONPathSyntaxError:
374383
# This covers a rare case when a trait starting with "$.",
375384
# but not a valid JSONPath, is used.
376-
compiled_query = jsonpath_rfc9535.compile(
377-
f'$.identity.traits["{escape_double_quotes(property)}"]',
378-
)
385+
return partial(_get_trait_value, trait_key=property)
379386

380387
def getter(context: EvaluationContext[SegmentMetadataT]) -> ContextValue:
388+
value: object
389+
if (value := _get_trait_value(context, property)) is not None:
390+
return value
381391
if typing.TYPE_CHECKING: # pragma: no cover
382392
# Ugly hack to satisfy mypy :(
383393
data = dict(context)

flag_engine/segments/utils.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,3 @@ def get_matching_function(
1515

1616
def none(iterable: typing.Iterable[object]) -> bool:
1717
return not any(iterable)
18-
19-
20-
def escape_double_quotes(value: str) -> str:
21-
"""
22-
Escape double quotes in a string for JSONPath compatibility.
23-
"""
24-
return value.replace('"', '\\"')
Submodule engine-test-data updated 151 files

0 commit comments

Comments
 (0)