description
the in / not in operators in _evaluate_simple_expression (src/specify_cli/workflows/expressions.py) only guard right is not None:
if op == " in ":
return left in right if right is not None else False
but left in right also raises TypeError for any other non-iterable right operand (int, bool, float). so a workflow condition like {{ inputs.tag in inputs.count }} where count is a number leaks a raw TypeError: argument of type 'int' is not iterable and crashes the whole run, instead of evaluating like the None case does.
this is asymmetric with _safe_compare, which already swallows TypeError and returns False for the ordering operators (<, >, etc.).
repro:
from specify_cli.workflows.expressions import evaluate_condition
from specify_cli.workflows.base import StepContext
evaluate_condition("{{ inputs.tag in inputs.count }}", StepContext(inputs={"tag":"x","count":5}))
# TypeError: argument of type 'int' is not iterable
expected: False (nothing is contained in a non-iterable), same as the right is None branch right beside it.
note: i used an ai assistant to help investigate and write this up.
description
the
in/not inoperators in_evaluate_simple_expression(src/specify_cli/workflows/expressions.py) only guardright is not None:but
left in rightalso raisesTypeErrorfor any other non-iterable right operand (int, bool, float). so a workflow condition like{{ inputs.tag in inputs.count }}wherecountis a number leaks a rawTypeError: argument of type 'int' is not iterableand crashes the whole run, instead of evaluating like the None case does.this is asymmetric with
_safe_compare, which already swallowsTypeErrorand returns False for the ordering operators (<,>, etc.).repro:
expected:
False(nothing is contained in a non-iterable), same as theright is Nonebranch right beside it.note: i used an ai assistant to help investigate and write this up.