feat(workflows): add from_json expression filter#2961
Conversation
Step outputs captured as strings could never become typed values in templates - the filter set was default/join/map/contains only, so e.g. a fan-out items: could never consume a step's JSON stdout. Add an arg-less from_json pipe filter with parse-or-raise semantics: invalid JSON or non-string input raises a clear ValueError rather than passing through silently. Fixes github#2960
|
@mnriem when you have a moment, would appreciate a review — happy to adjust anything. |
There was a problem hiding this comment.
Pull request overview
Adds a new from_json pipe filter to the workflow expression evaluator so step outputs (typically strings like stdout) can be converted into typed Python values (dict/list/scalar) inside templates, enabling patterns like feeding fan-out.items from a runtime-emitted JSON string.
Changes:
- Implement
from_jsonfilter in the sandboxed expression evaluator (json.loadswith strict ValueError semantics on misuse). - Extend filter documentation in the evaluator docstring to include
from_json. - Add unit tests validating successful parsing and failure modes (invalid JSON, non-string input).
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/workflows/expressions.py |
Adds the from_json filter and wires it into filter dispatch. |
tests/test_workflows.py |
Adds 3 tests covering from_json success + error cases. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
|
Please address Copilot feedback |
Address review (github#2961): from_json('x') and from_json() previously fell through to a silent passthrough of the unparsed value. Reject any parenthesized form with a clear error so mis-wired templates fail loudly. Rename test to ...parses_object (JSON under test is an object) and add coverage for the strict no-arguments behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@mnriem Thanks for the review — addressed the Copilot feedback:
Full suite green; |
Address review (github#2961): from_json('x') and from_json() previously fell through to a silent passthrough of the unparsed value. Reject any parenthesized form with a clear error so mis-wired templates fail loudly. Rename test to ...parses_object (JSON under test is an object) and add coverage for the strict no-arguments behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b8bbc8a to
3751f5f
Compare
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback
Address Copilot review: the user-facing filter references omitted the
newly added `from_json` filter. Add it to the ARCHITECTURE.md filter table
(with the `{{ steps.emit.output.stdout | from_json }}` example) and to the
filter enumerations in workflows/README.md and docs/reference/workflows.md
so the docs match the evaluator's capabilities.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@mnriem Pushed
The earlier strictness fix (parenthesized forms like |
|
Please address Copilot feedback |
… docstring Address Copilot review: - Strictness only rejected parenthesized forms, so typos like `| from_json)` or `| from_json extra` still fell through to the unknown-filter path and silently returned the unparsed value. Match on the leading filter token and require the whole filter to be exactly `from_json`, so every mis-wired form raises. Extend the rejection test to cover the trailing-token cases. - The module docstring claimed "no imports", which is misleading now that the module imports `json`. Reword to state the actual sandbox guarantee: templates cannot do file I/O, import modules, or run arbitrary code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@mnriem Pushed
Full |
|
Thank you! |
Description
Fixes #2960.
Adds one arg-less pipe filter to the sandboxed expression evaluator:
_filter_from_jsonparses a JSON string into its typed value (list/dict/scalar). Semantics are parse-or-raise: invalid JSON or non-string input raises a clearValueError— never a silent passthrough, since a parse failure means the pipeline wiring is wrong and silence would hide it. The module docstring's filter list is updated; no other filter or evaluator behavior is touched.This is the smallest unblock for feeding
fan-outitems:(or any condition/arg) from a step that computes a collection at runtime. It composes with — and doesn't preclude — a future declared-outputs:mechanism, which I'm proposing separately.Testing
uv sync && uv run pytest—tests/test_workflows.py210 passedTestExpressions(valid JSON → typed value; invalid JSON raises; non-string raises) — all three are red against currentmain, green with the filter (verified both directions)uvx ruff check src/— cleanuv run specify --help| from_json)AI Disclosure
Code, tests, and this description were authored with AI assistance (Claude); verified by running the repo's test suite and ruff locally in both red and green directions.