fix(workflows): resolve negative list indices in expressions - #4416
fix(workflows): resolve negative list indices in expressions#4416NgoQuocViet2001 wants to merge 2 commits into
Conversation
_resolve_dot_path matched only digits in the index bracket, so `task_list[-1]` never entered the indexing branch. It fell through to the dict lookup and asked for the literal key "task_list[-1]", which returns None — a template reaching for the last element of a step output rendered empty with no error, and a condition on it silently read false. Accept the negative form Python and Jinja2 both use, and bound the index from both ends so out-of-range still yields None rather than raising.
There was a problem hiding this comment.
🟡 Changes recommended
Condition-remediation parsing still rejects negative indices supported by the resolver.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds Python-style negative list indexing to workflow expressions.
Changes:
- Supports bounded negative indices.
- Adds resolution and bounds tests.
File summaries
| File | Description |
|---|---|
expressions.py |
Extends list-index parsing and bounds checks. |
test_workflows.py |
Tests negative and out-of-range indices. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| # Handle list indexing: name[0] | ||
| idx_match = re.match(r"^([\w-]+)\[(\d+)\]$", part) | ||
| # Handle list indexing: name[0], name[-1] | ||
| idx_match = re.match(r"^([\w-]+)\[(-?\d+)\]$", part) |
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback
Addressing review feedback. The resolver now takes `item[-1]`, but the
two matchers the condition-remediation path uses were left on `\d+`:
_PATH_SEGMENT and the indexed-root fullmatch. So a condition the
evaluator resolves fine was classified unresolvable, and
format_condition_remediation withheld the 'wrap the expression'
correction from it:
item[0] == 'x' -> Wrap the expression: "{{ item[0] == 'x' }}".
item[-1] == 'x' -> No correction is offered because 'item[-1]' is not
a name the evaluator can resolve
Allow -?\d+ in both, and extend the existing parametrize with the two
negative cases.
|
Addressed — the Copilot finding was correct, thanks.
Both now allow
|
Problem
_resolve_dot_pathmatches the index bracket with^([\w-]+)\[(\d+)\]$, which accepts digits only. A negative index therefore never enters the indexing branch — it falls through to the dict lookup and asks for the literal key"task_list[-1]", which is absent, so the whole path resolves toNone:list[-1]is valid in both Python and the Jinja2 subset the module documents itself as providing, and "the last item a step produced" is a natural thing for a workflow template to want. There is no error: the template renders empty, andevaluate_conditionon the same path reads false, so a step can be skipped for a reason that never surfaces.Fix
Accept the negative form in the pattern and bound the index from both ends. Out-of-range in either direction keeps returning
Nonerather than raising, matching the existing behaviour for[9]on a short list.Scope
Two lines in
src/specify_cli/workflows/expressions.pyplus a docstring note, and one test next to the existingtest_list_indexing. Positive indices and non-index path segments are untouched.Test plan
pytest tests/test_workflows.py -k "indexing or literal"→ 11 passed.pytest tests/test_workflows.py→ 942 passed. The 20 failures are theTestWorkflowCliAlignmentsymlink cases, which fail identically on an unmodified checkout here (Windows, no symlink privilege).expressions.pyfails the new test withassert None == 'b.md'.