DAGNode.foreach_param / output_steps()["foreach_artifact"] correctly populated on python3.12+#3237
Conversation
Greptile SummaryThis PR fixes a Python 3.14 regression where
Confidence Score: 5/5Safe to merge — the change is narrowly scoped to AST node reading, backward-compatible with older interpreters, and restores correct behavior on Python 3.14+ without altering graph topology or any other parse path. The fix correctly handles both the legacy ast.Str path (guarded by hasattr(ast, 'Str')) and the modern ast.Constant path. The only code paths touched are the keyword-value extractor and the switch-condition branch, both of which are now consistent. The change introduces no new logic — it consolidates existing, already-working patterns. No files require special attention. Important Files Changed
Reviews (3): Last reviewed commit: "refactor: hoist keyword-value extractor ..." | Re-trigger Greptile |
Move the ast.Str/ast.Constant literal extractor out of DAGNode._parse into a module-level _ast_literal_value() so it is not re-created per call, and reuse it for the switch-condition extraction that previously duplicated the same logic. Also keeps the keywords dict multi-line so black is satisfied (the longer helper name no longer collapses to one line), fixing the pre-commit failure. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
DAGNode.foreach_param / output_steps()["foreach_artifact"] correctly populated on python3.12+
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3237 +/- ##
=========================================
Coverage ? 28.32%
=========================================
Files ? 381
Lines ? 52448
Branches ? 9252
=========================================
Hits ? 14855
Misses ? 36628
Partials ? 965 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
romain-intel
left a comment
There was a problem hiding this comment.
i'll let sakari take a quick look too but lgtm.
PR Type
Summary
The static graph parser silently drops the
foreach=/num_parallel=keyword values on Python 3.14+, soDAGNode.foreach_param,num_parallel, and theforeach_artifactexposed byoutput_steps()all come backNone. Node typing is unaffected, only the artifact name/value is lost. This swaps the removedast.Str.sread for anast.Constantfallback (the same one already used for switch conditions a few lines above).Issue
Fixes #3236
Reproduction
Runtime: local
Commands to run: Run the flow below under Python 3.14 (where
ast.Strand the.salias are gone). On 3.12/3.13 the deprecated.salias still resolves, so the bug stays hidden there. Save it to a file and run it withpython <file>.py, or paste it into a Python 3.14 shell.Where evidence shows up: parent console (the static graph metadata, also consumed by
show, the DAG card, and Argo/Airflow compilation)Before (Python 3.14.3)
After (Python 3.14.3)
Root Cause
In
DAGNode._parse, the keyword extractor readgetattr(k.value, "s", None)..swas the attribute on the legacyast.Strnode. Since Python 3.8 string literals areast.Constantwith the value in.value, and the.scompatibility alias was removed in 3.14. So on 3.14 thegetattrfalls through to itsNonedefault and the value is dropped.Type detection still works because it checks for the presence of the keyword name (
"foreach" in keywords), not its value, which is why the type stays correct while the value goes missing. The switch-condition branch just above already had theast.Constantfallback, so this was effectively a half-applied migration.Why This Fix Is Correct
Restores the invariant that a string/int literal keyword in
self.next(...)round-trips toforeach_param/num_parallel. The_kw_valuehelper keeps theast.Strbranch for older interpreters and readsast.Constant.valueeverywhere else, matching the existing switch-condition handling. Nothing else in the parse path changes.Failure Modes Considered
< 3.14):ast.Str/.sstill exist, and thehasattr(ast, "Str")branch preserves the old path. Verified no regression on 3.12.foreach=some_var): the node is anast.Name, notast.Constant, so_kw_valuereturnsNone, same as before. No behavior change there.Tests
Existing
test/unit/test_graph_structure.pyandtest_sourceless_dag_node.pypass on 3.14 (55 passed). No new unit test added yet since the existing suite runs on the default interpreter where the bug is masked; happy to add a 3.14-gated regression test if preferred.Non-Goals
No change to graph topology, edge resolution,
matching_join, or the switch-condition path. Not touching how non-literal keyword values are handled.AI Tool Usage
Claude Code was used to reproduce the bug on Python 3.14.3, apply the fix, and verify against the existing unit tests. All generated code was reviewed, understood, and tested.