Skip to content

Feature collection: parser QoL#277

Open
liamhuber wants to merge 31 commits into
mainfrom
parser-qol
Open

Feature collection: parser QoL#277
liamhuber wants to merge 31 commits into
mainfrom
parser-qol

Conversation

@liamhuber

@liamhuber liamhuber commented Jul 11, 2026

Copy link
Copy Markdown
Member

This is a landing pad for a set of PRs focused around improving quality of life in parsing decorated objects. It's driven by annoyances I encountered formulating @ligerzero-ai's pyiron_workflow_atomistics nodes into flowrep recipes -- I never ran into anything flowrep couldn't do, but there were a bunch of places that I wish it made things easier for me.

The only change to the actual model side, and the only change I anticipate right now, was adding the "constant"-type recipe in #270. The changes really are to the parsing/compiling.

I'm going to try and keep actual changes fairly focused into individual PRs, but when there's more than a small handful of these stacked on top of each other, propagating requested changes from the base on up the stack is just super annoying. So different changes will be digestible and reviewable in their own PRs, but requested changes will be patched in here in the aggregator stage to avoid that propagation.

liamhuber and others added 27 commits July 7, 2026 23:56
Adds a source-node recipe for emitting fixed JSON-serializable values:
RecipeElementType.CONSTANT enum member, the ConstantRecipe pydantic
model (with a strict before-validator rejecting tuples/sets/non-str
keys), its registration in the discriminated union, and public exports.
Literal call arguments (e.g. mul(0.5, mv_2)) previously failed to parse
because consume_call_arguments required every argument to be an ast.Name.
Non-Name arguments are now literal_eval'd and injected as a ConstantRecipe
source node wired to the consuming port; SymbolScope.consume_source
records the resulting sibling edge without polluting the symbol table.
The ConstantRecipe model's mode="before" validator remains the single
source of truth for the JSON-compatibility invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oat constants; cleanups

Address code-review findings from the constant-node-type feature:
- case_helpers.parse_case discarded scope_copy.edges, so a literal argument in an
  if/elif/while condition injected an orphaned constant node and left the
  condition's input sourceless downstream. consume_call_arguments now takes
  allow_constants=False for conditions and raises TypeError up front instead.
- ConstantRecipe accepted non-finite floats (nan/inf/-inf), which are not valid
  JSON and cannot round-trip through ast.literal_eval; _strict_json now rejects
  them.
- Formatting and test-coverage cleanups: black on test_parsing_constants.py,
  removed redundant in-method imports in test_retrospective_wfms.py, restored
  partial-consumption-before-error coverage in test_parser_helpers.py, and a
  clarifying comment in compiler/statements.py.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ition

A constant feeding a workflow output, or sitting bare as a flow-control body,
can't be inlined (`return 5` doesn't re-parse; a bare ConstantRecipe crashes
_emit_single_node_body on node.reference). Add a materialize path: emit_body
gets a ConstantRecipe branch ahead of _emit_single_node_body, and
emit_workflow_body tracks constants whose output feeds a workflow output edge,
emitting `sym = repr(value)` for those instead of inlining. Constants feeding
only call arguments still inline unchanged.

The narrowing in emit_body's new isinstance branch resolves the host-only
mypy arg-type/union-attr errors at statements.py's _emit_single_node_body
call site (mypy segfaults in this sandbox, so this is asserted structurally,
not re-run here).
body.value is expr|None for AnnAssign; short-circuit on None so a valueless
annotation still falls through to the existing error path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Route each literal condition argument to a synthetic flow-control input
port fed by a constant peer injected into the enclosing workflow, replacing
the allow_constants=False rejection. Parser-only; the compiler already
renders the peer-fed condition argument inline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ions

Adds TestConstantsInConditions to test_compiler.py proving if/elif/while
literal conditions execute correctly and round-trip exactly (including
multiple-literals-in-one-condition and nested cases), plus a
determinism-pin test and a non-JSON-literal-raises test in
test_if_parser.py. Confirms allow_constants is fully gone (grep).

Also fixes a stale comment in statements.py: a constant peer feeding a
flow-control input is normal now (Part 2), not an unreachable hand-built
shape as the old prose claimed; the conflict `if` below it remains
correctly unreachable in parser-produced recipes for a different reason
(such a peer is never also a workflow-output source).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
And keep it in a classvar

Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
With safeguards against interactions in flow controls: no reassigning to accumulators; no conditionals leaking input sources.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
And update error message

Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
For the @workflow and @atomic decorators. No behaviour change, just simplifying the code a bit.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
And plug a dangerous edge case where the signature comes from `__new__` by failing cleanly.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
When decorating classes

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
That stacks @atomic and @DataClass

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
Signed-off-by: Liam Huber <liamhuber@greyhavensolutions.com>
@github-actions

Copy link
Copy Markdown

Binder 👈 Launch a binder notebook on branch pyiron/flowrep/parser-qol

@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (e701669) to head (97a552e).

Additional details and impacted files
@@            Coverage Diff             @@
##              main      #277    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files           35        38     +3     
  Lines         2818      3037   +219     
==========================================
+ Hits          2818      3037   +219     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Parse variable reassignment
@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant