IR Reflection & Typed API Guidelines¶
These notes capture the durable lessons from the reflection cleanup completed in PR 96. Use them when extending the converter, optimizer, or plugin helpers so we stay aligned with the typed onnx_ir APIs and keep future audits small.
Cleanup Workflow¶
- Introduce or reuse typed utility helpers (e.g. leveraging
val.dtypeorval.shape) and migrate one module at a time instead of broad rewrites. - Run
scripts/audit_ir_dynamic_access.pyafter each sweep. Classify remaining hits as either expected (document why) or needs follow-up. - Re-run
mypytogether with a focusedpytestslice before marking the sweep complete.
Document ONNX proto shims that still require reflection (plugins/_post_check_onnx_graph.py, plugins/_patching.py) so the audit trail stays actionable.
Core Rules¶
- Typed APIs first — Treat
ir.Attr,ir.Value, andir.Graphas immutable, typed objects. Avoidgetattr, private field mutation, or redundantNoneguards; rely on the documented accessors instead. - Use built-in graph iterators — Iterate via
graph.nodes,graph.all_nodes(),value.consumers(),value.producer(), andir.convenience.replace_all_uses_withinstead of constructing custom maps. - When working with
onnx_irgraphs, prefergraph.all_nodes()so nested functions and control-flow subgraphs are traversed with the typed iterator. Only fall back to the ONNX proto mirrors (function.node) when you truly need the raw proto objects. - Reuse shape & dtype helpers — Use
onnx_ir.Shape.is_unknown_dim,ir.Shape(...), andvalue.dtyperather than cloning dtype/shape logic manually. - Prefer existing passes — Before adding bespoke optimizations, check the available ONNX Script passes (e.g.,
fold_constants.FoldConstantsPass,LiftConstantsToInitializersPass) and the IR optimizer docs. - Keep helpers focused & typed — Provide clear function signatures (e.g.,
_attribute_iter(node: ir.Node) -> Iterable[ir.Attr]) and avoid over-engineered utilities. Document non-obvious helpers. - Lean on
onnx_ircontainers — Use liveAttributes,Functions, and other containers instead of proto mirrors; drop shims now that typed APIs are universal. - Graph rewrites — When eliminating nodes (e.g., identity removal), check
Value.is_graph_input/output, rename the surviving value, updategraph.outputswithValueobjects, callir.convenience.replace_all_uses_with, and remove the node viagraph.remove(..., safe=True). - Annotate aggressively — Keep explicit type annotations in converter and plugin code so mypy enforces alignment with IR interfaces.