fix(workflows): don't crash on membership test against a non-iterable#3448
Merged
Conversation
the `in` / `not in` operators in _evaluate_simple_expression only guarded
`right is not None`, so `left in right` still raised a raw TypeError when the
right operand was any other non-iterable (int, bool, float). a condition like
`{{ inputs.tag in inputs.count }}` where count is a number crashed the whole
workflow run instead of evaluating.
nothing is contained in a non-iterable, so treat membership as False (`not in`
as True) via a new _safe_membership helper that swallows TypeError. this
generalizes the old None guard and mirrors _safe_compare, which already
catches TypeError for the ordering operators.
added a regression test; confirmed it fails on the pre-fix code (raw
TypeError) and that genuine list/substring membership still works.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes workflow expression evaluation so the in / not in operators no longer crash workflow runs when the right-hand operand is a non-iterable (e.g., int, bool, None). It aligns membership operator behavior with existing _safe_compare behavior by swallowing TypeError and producing a deterministic boolean result.
Changes:
- Route
in/not inthrough a new_safe_membership()helper that catchesTypeErrorand treats membership as falsey (not inas truthy). - Add a regression test to ensure non-iterable membership does not raise and that normal iterable membership still works.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/workflows/expressions.py |
Adds _safe_membership() and uses it for in / not in in _evaluate_simple_expression() to prevent raw TypeError crashes. |
tests/test_workflows.py |
Adds regression coverage for membership tests against non-iterable right operands and confirms valid membership still behaves correctly. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Low
…tring - add a float right-operand assertion so the test matches its comment (was claiming float coverage while only exercising int/bool/None). - reword the _safe_membership docstring to describe TypeError generally (non-iterable right is the common case, but also e.g. an unhashable left against a set) rather than implying only the right operand matters.
Collaborator
|
Thank you! |
This was referenced Jul 13, 2026
Noor-ul-ain001
added a commit
to Noor-ul-ain001/spec-kit
that referenced
this pull request
Jul 14, 2026
github#3447 was fixed independently by github#3448 (merged first), which added the same _safe_membership helper this branch introduced. Per Copilot review: - Revert the redundant _safe_contains rename in expressions.py so the file matches main; the working membership guard already lives there. - Drop the duplicate test_in_operator_non_iterable_right_operand test and fold its only new coverage (not in against float/bool/None right operands, which the base test only checked for the int case) into the existing test_membership_against_non_iterable_is_false_not_error. Also merges latest upstream/main into the branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fixes #3447
the
in/not inoperators in_evaluate_simple_expressiononly guardedright is not None, soleft in rightstill raised a rawTypeErrorwhen the right operand was any other non-iterable (int, bool, float). a workflow condition like{{ inputs.tag in inputs.count }}wherecountis a number crashed the whole run instead of evaluating. this was asymmetric with_safe_compare, which already swallows TypeError for the ordering operators.fix: route both operators through a new
_safe_membershiphelper that doesleft in rightinside atry/except TypeErrorand returns False (not inreturns True) on failure. nothing is contained in a non-iterable, so this generalizes the old None guard and matches_safe_compare's handling.added a regression test (
test_membership_against_non_iterable_is_false_not_error) covering int/bool/missing right operands plus a condition that would otherwise crash the run. i confirmed it fails on the pre-fix code by stashing the source and re-running (raw TypeError). genuine list/substring membership still works, and the full expression test class (42 tests) passes.