flagsmith-flag-engine 10.0.2__tar.gz → 10.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flagsmith_flag_engine-10.0.2/flagsmith_flag_engine.egg-info → flagsmith_flag_engine-10.0.4}/PKG-INFO +1 -1
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/evaluator.py +47 -31
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4/flagsmith_flag_engine.egg-info}/PKG-INFO +1 -1
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/setup.py +1 -1
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/LICENSE.txt +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/README.md +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/__init__.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/context/__init__.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/context/mappers.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/context/types.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/engine.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/py.typed +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/result/__init__.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/result/types.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/__init__.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/constants.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/types.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/utils.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/__init__.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/hashing.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/json/__init__.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/json/encoders.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/semver.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/types.py +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flagsmith_flag_engine.egg-info/SOURCES.txt +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flagsmith_flag_engine.egg-info/dependency_links.txt +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flagsmith_flag_engine.egg-info/requires.txt +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flagsmith_flag_engine.egg-info/top_level.txt +0 -0
- {flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/setup.cfg +0 -0
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/evaluator.py
RENAMED
|
@@ -264,53 +264,45 @@ def context_matches_condition(
|
|
|
264
264
|
condition: SegmentCondition,
|
|
265
265
|
segment_key: SupportsStr,
|
|
266
266
|
) -> bool:
|
|
267
|
-
context_value
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
)
|
|
267
|
+
context_value: ContextValue
|
|
268
|
+
condition_property = condition["property"]
|
|
269
|
+
condition_operator = condition["operator"]
|
|
270
|
+
|
|
271
|
+
if condition_operator == constants.PERCENTAGE_SPLIT and (not condition_property):
|
|
272
|
+
# Currently, the only supported condition with a blank property
|
|
273
|
+
# is percentage split.
|
|
274
|
+
# In this case, we use the identity key as context value.
|
|
275
|
+
# This is mainly to support legacy segments created before
|
|
276
|
+
# we introduced JSONPath support.
|
|
277
|
+
context_value = _get_identity_key(context)
|
|
278
|
+
else:
|
|
279
|
+
context_value = get_context_value(context, condition_property)
|
|
272
280
|
|
|
273
|
-
if
|
|
274
|
-
|
|
275
|
-
in_values = segment_value
|
|
276
|
-
else:
|
|
277
|
-
try:
|
|
278
|
-
in_values = json.loads(segment_value)
|
|
279
|
-
# Only accept JSON lists.
|
|
280
|
-
# Ideally, we should use something like pydantic.TypeAdapter[list[str]],
|
|
281
|
-
# but we aim to ditch the pydantic dependency in the future.
|
|
282
|
-
if not isinstance(in_values, list):
|
|
283
|
-
raise ValueError
|
|
284
|
-
except ValueError:
|
|
285
|
-
in_values = segment_value.split(",")
|
|
286
|
-
in_values = [str(value) for value in in_values]
|
|
281
|
+
if condition_operator == constants.IN:
|
|
282
|
+
in_values = _get_in_values(condition["value"])
|
|
287
283
|
# Guard against comparing boolean values to numeric strings.
|
|
288
|
-
if
|
|
289
|
-
context_value is True or context_value is False
|
|
290
|
-
):
|
|
284
|
+
if type(context_value) is int:
|
|
291
285
|
context_value = str(context_value)
|
|
292
286
|
return context_value in in_values
|
|
293
287
|
|
|
294
288
|
condition = typing.cast(StrValueSegmentCondition, condition)
|
|
295
289
|
|
|
296
|
-
if
|
|
297
|
-
if context_value is
|
|
298
|
-
object_ids = [segment_key, context_value]
|
|
299
|
-
elif identity_key := _get_identity_key(context):
|
|
300
|
-
object_ids = [segment_key, identity_key]
|
|
301
|
-
else:
|
|
290
|
+
if condition_operator == constants.PERCENTAGE_SPLIT:
|
|
291
|
+
if context_value is None:
|
|
302
292
|
return False
|
|
303
293
|
|
|
294
|
+
object_ids = [segment_key, context_value]
|
|
295
|
+
|
|
304
296
|
try:
|
|
305
297
|
float_value = float(condition["value"])
|
|
306
298
|
except ValueError:
|
|
307
299
|
return False
|
|
308
300
|
return get_hashed_percentage_for_object_ids(object_ids) <= float_value
|
|
309
301
|
|
|
310
|
-
if
|
|
302
|
+
if condition_operator == constants.IS_NOT_SET:
|
|
311
303
|
return context_value is None
|
|
312
304
|
|
|
313
|
-
if
|
|
305
|
+
if condition_operator == constants.IS_SET:
|
|
314
306
|
return context_value is not None
|
|
315
307
|
|
|
316
308
|
return (
|
|
@@ -342,6 +334,30 @@ def _matches_context_value(
|
|
|
342
334
|
return False
|
|
343
335
|
|
|
344
336
|
|
|
337
|
+
@lru_cache(maxsize=1024)
|
|
338
|
+
def _parse_in_values_str(segment_value: str) -> frozenset[str]:
|
|
339
|
+
"""
|
|
340
|
+
Parse a string-form IN condition value into a frozenset of strings.
|
|
341
|
+
A bracketed value is tried as JSON first (with CSV fallback on parse
|
|
342
|
+
error); anything else is split on commas directly.
|
|
343
|
+
"""
|
|
344
|
+
if segment_value.startswith("["):
|
|
345
|
+
try:
|
|
346
|
+
parsed: list[typing.Any] = json.loads(segment_value)
|
|
347
|
+
except ValueError:
|
|
348
|
+
return frozenset(segment_value.split(","))
|
|
349
|
+
return frozenset(v if type(v) is str else str(v) for v in parsed)
|
|
350
|
+
return frozenset(segment_value.split(","))
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _get_in_values(
|
|
354
|
+
segment_value: typing.Union[str, list[typing.Any]],
|
|
355
|
+
) -> frozenset[str]:
|
|
356
|
+
if isinstance(segment_value, list):
|
|
357
|
+
return frozenset(v if type(v) is str else str(v) for v in segment_value)
|
|
358
|
+
return _parse_in_values_str(segment_value)
|
|
359
|
+
|
|
360
|
+
|
|
345
361
|
def _evaluate_not_contains(
|
|
346
362
|
segment_value: typing.Optional[str],
|
|
347
363
|
context_value: ContextValue,
|
|
@@ -417,7 +433,7 @@ MATCHERS_BY_OPERATOR: dict[
|
|
|
417
433
|
|
|
418
434
|
def _get_identity_key(
|
|
419
435
|
context: _EvaluationContextAnyMeta,
|
|
420
|
-
) -> typing.Optional[
|
|
436
|
+
) -> typing.Optional[str]:
|
|
421
437
|
if identity_context := context.get("identity"):
|
|
422
438
|
return identity_context.get("key")
|
|
423
439
|
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/context/__init__.py
RENAMED
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/context/mappers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/result/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/__init__.py
RENAMED
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/segments/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/json/__init__.py
RENAMED
|
File without changes
|
{flagsmith_flag_engine-10.0.2 → flagsmith_flag_engine-10.0.4}/flag_engine/utils/json/encoders.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|