1414 EvaluationContext ,
1515 FeatureContext ,
1616 SegmentCondition ,
17- SegmentContext ,
18- SegmentRule ,
1917)
18+ from flag_engine .context .types import SegmentCondition1 as StrValueSegmentCondition
19+ from flag_engine .context .types import SegmentContext , SegmentRule
2020from flag_engine .result .types import EvaluationResult , FlagResult , SegmentResult
2121from flag_engine .segments import constants
2222from flag_engine .segments .types import ConditionOperator , ContextValue , is_context_value
@@ -189,6 +189,29 @@ def context_matches_condition(
189189 else None
190190 )
191191
192+ if condition ["operator" ] == constants .IN :
193+ if isinstance (segment_value := condition ["value" ], list ):
194+ in_values = segment_value
195+ else :
196+ try :
197+ in_values = json .loads (segment_value )
198+ # Only accept JSON lists.
199+ # Ideally, we should use something like pydantic.TypeAdapter[list[str]],
200+ # but we aim to ditch the pydantic dependency in the future.
201+ if not isinstance (in_values , list ):
202+ raise ValueError
203+ in_values = [str (value ) for value in in_values ]
204+ except ValueError :
205+ in_values = segment_value .split ("," )
206+ # Guard against comparing boolean values to numeric strings.
207+ if isinstance (context_value , int ) and not any (
208+ context_value is x for x in (False , True )
209+ ):
210+ context_value = str (context_value )
211+ return context_value in in_values
212+
213+ condition = typing .cast (StrValueSegmentCondition , condition )
214+
192215 if condition ["operator" ] == constants .PERCENTAGE_SPLIT :
193216 if context_value is not None :
194217 object_ids = [segment_key , context_value ]
@@ -225,7 +248,7 @@ def get_context_value(
225248
226249
227250def _matches_context_value (
228- condition : SegmentCondition ,
251+ condition : StrValueSegmentCondition ,
229252 context_value : ContextValue ,
230253) -> bool :
231254 if matcher := MATCHERS_BY_OPERATOR .get (condition ["operator" ]):
@@ -271,29 +294,6 @@ def _evaluate_modulo(
271294 return context_value % divisor == remainder
272295
273296
274- def _evaluate_in (
275- segment_value : typing .Optional [str ], context_value : ContextValue
276- ) -> bool :
277- if segment_value :
278- try :
279- in_values = json .loads (segment_value )
280- # Only accept JSON lists.
281- # Ideally, we should use something like pydantic.TypeAdapter[list[str]],
282- # but we aim to ditch the pydantic dependency in the future.
283- if not isinstance (in_values , list ):
284- raise ValueError
285- in_values = [str (value ) for value in in_values ]
286- except ValueError :
287- in_values = segment_value .split ("," )
288- # Guard against comparing boolean values to numeric strings.
289- if isinstance (context_value , int ) and not any (
290- context_value is x for x in (False , True )
291- ):
292- context_value = str (context_value )
293- return context_value in in_values
294- return False
295-
296-
297297def _context_value_typed (
298298 func : typing .Callable [..., bool ],
299299) -> typing .Callable [[typing .Optional [str ], ContextValue ], bool ]:
@@ -320,7 +320,6 @@ def inner(
320320 constants .NOT_CONTAINS : _evaluate_not_contains ,
321321 constants .REGEX : _evaluate_regex ,
322322 constants .MODULO : _evaluate_modulo ,
323- constants .IN : _evaluate_in ,
324323 constants .EQUAL : _context_value_typed (operator .eq ),
325324 constants .GREATER_THAN : _context_value_typed (operator .gt ),
326325 constants .GREATER_THAN_INCLUSIVE : _context_value_typed (operator .ge ),
0 commit comments