1717 SegmentContext ,
1818 SegmentRule ,
1919)
20+ from flag_engine .context .types import SegmentCondition1 as StrValueSegmentCondition
2021from flag_engine .environments .models import EnvironmentModel
2122from flag_engine .identities .models import IdentityModel
2223from flag_engine .identities .traits .types import ContextValue , is_trait_value
@@ -235,6 +236,29 @@ def context_matches_condition(
235236 else None
236237 )
237238
239+ if condition ["operator" ] == constants .IN :
240+ if isinstance (segment_value := condition ["value" ], list ):
241+ in_values = segment_value
242+ else :
243+ try :
244+ in_values = json .loads (segment_value )
245+ # Only accept JSON lists.
246+ # Ideally, we should use something like pydantic.TypeAdapter[list[str]],
247+ # but we aim to ditch the pydantic dependency in the future.
248+ if not isinstance (in_values , list ):
249+ raise ValueError
250+ except ValueError :
251+ in_values = segment_value .split ("," )
252+ in_values = [str (value ) for value in in_values ]
253+ # Guard against comparing boolean values to numeric strings.
254+ if isinstance (context_value , int ) and not any (
255+ context_value is x for x in (False , True )
256+ ):
257+ context_value = str (context_value )
258+ return context_value in in_values
259+
260+ condition = typing .cast (StrValueSegmentCondition , condition )
261+
238262 if condition ["operator" ] == constants .PERCENTAGE_SPLIT :
239263 if context_value is not None :
240264 object_ids = [segment_key , context_value ]
@@ -270,7 +294,7 @@ def get_context_value(
270294
271295
272296def _matches_context_value (
273- condition : SegmentCondition ,
297+ condition : StrValueSegmentCondition ,
274298 context_value : ContextValue ,
275299) -> bool :
276300 if matcher := MATCHERS_BY_OPERATOR .get (condition ["operator" ]):
@@ -316,29 +340,6 @@ def _evaluate_modulo(
316340 return context_value % divisor == remainder
317341
318342
319- def _evaluate_in (
320- segment_value : typing .Optional [str ], context_value : ContextValue
321- ) -> bool :
322- if segment_value :
323- try :
324- in_values = json .loads (segment_value )
325- # Only accept JSON lists.
326- # Ideally, we should use something like pydantic.TypeAdapter[list[str]],
327- # but we aim to ditch the pydantic dependency in the future.
328- if not isinstance (in_values , list ):
329- raise ValueError
330- in_values = [str (value ) for value in in_values ]
331- except ValueError :
332- in_values = segment_value .split ("," )
333- # Guard against comparing boolean values to numeric strings.
334- if isinstance (context_value , int ) and not any (
335- context_value is x for x in (False , True )
336- ):
337- context_value = str (context_value )
338- return context_value in in_values
339- return False
340-
341-
342343def _context_value_typed (
343344 func : typing .Callable [..., bool ],
344345) -> typing .Callable [[typing .Optional [str ], ContextValue ], bool ]:
@@ -365,7 +366,6 @@ def inner(
365366 constants .NOT_CONTAINS : _evaluate_not_contains ,
366367 constants .REGEX : _evaluate_regex ,
367368 constants .MODULO : _evaluate_modulo ,
368- constants .IN : _evaluate_in ,
369369 constants .EQUAL : _context_value_typed (operator .eq ),
370370 constants .GREATER_THAN : _context_value_typed (operator .gt ),
371371 constants .GREATER_THAN_INCLUSIVE : _context_value_typed (operator .ge ),
0 commit comments