onnx_light.compatibility.schema_diff#
Structured diff between two OpSchema versions.
This module provides compare_schemas() and the accompanying dataclasses
(SchemaDiff, ParameterDiff, AttributeDiff,
ConstraintDiff, DocDiff) for detecting differences —
including breaking changes — between two versions of the same ONNX
operator schema.
Documentation strings are diffed at the line level (via
DocDiff), using difflib (line-based edit distance and
unified diff) rather than character-level comparison, so the result reads
naturally both as plain text and inside Sphinx code-block:: diff
directives.
Typical usage with a full OpSchema:
<<<
from onnx_light.onnx import defs
from onnx_light.compatibility.schema_diff import compare_schemas
defs.register_onnx_operator_set_schema()
old = defs.get_schema("Relu", 6)
new = defs.get_schema("Relu", 14)
diff = compare_schemas(old, new)
print(diff)
>>>
SchemaDiff: Relu (domain='')
old version : 6
new version : 14
breaking : False
Type constraints:
changed 'T': added types: ['tensor(bfloat16)', 'tensor(int16)', 'tensor(int32)', 'tensor(int64)', 'tensor(int8)']
The same function also accepts the lightweight LightOpSchema objects
exposed by onnx_light (those have no attributes nor input/output
arity, so those sections of the diff are simply omitted):
<<<
from collections import defaultdict
from onnx_light.onnx_proto._onnxpy import onnx_op
from onnx_light.compatibility.schema_diff import compare_schemas
by_name = defaultdict(list)
for s in onnx_op.GetAllOnnxOpSchemasWithHistory(True):
by_name[(s.domain, s.name)].append(s)
versions = sorted(by_name[("ai.onnx", "Add")], key=lambda s: s.since_version)
old, new = versions[0], versions[-1]
diff = compare_schemas(old, new)
print(diff)
>>>
SchemaDiff: Add (domain='ai.onnx')
old version : 1
new version : 14
breaking : False
Type constraints:
changed 'T': added types: ['tensor(bfloat16)', 'tensor(int16)', 'tensor(int32)', 'tensor(int64)', 'tensor(int8)', 'tensor(uint16)', 'tensor(uint32)', 'tensor(uint64)', 'tensor(uint8)']
Documentation:
line similarity: 0.09 (+3/-18 lines)
--- Add v1
+++ Add v14
@@ -1,19 +1,4 @@
-Performs element-wise binary addition (with limited broadcast support).
-If necessary the right-hand-side argument will be broadcasted to match the
-shape of left-hand-side argument. When broadcasting is specified, the second
-tensor can either be of element size 1 (including a scalar tensor and any
-tensor with rank equal to or smaller than the first tensor), or having its
-shape as a contiguous subset of the first tensor's shape. The starting of the
-mutually equal shape is specified by the argument "axis", and if it is not set,
-suffix matching is assumed. 1-dim expansion doesn't work yet.
+Performs element-wise binary addition (with Numpy-style broadcasting support).
-For example, the following tensor shapes are supported (with broadcast=1):
-
- shape(A) = (2, 3, 4, 5), shape(B) = (,), i.e. B is a scalar tensor
- shape(A) = (2, 3, 4, 5), shape(B) = (1, 1), i.e. B is an 1-element tensor
- shape(A) = (2, 3, 4, 5), shape(B) = (5,)
- shape(A) = (2, 3, 4, 5), shape(B) = (4, 5)
- shape(A) = (2, 3, 4, 5), shape(B) = (3, 4), with axis=1
- shape(A) = (2, 3, 4, 5), shape(B) = (2), with axis=0
-
-Attribute `broadcast=1` needs to be passed to enable broadcasting.
+This operator supports multidirectional (i.e., Numpy-style) broadcasting;
+for more details please check the broadcasting behavior in ONNX.
A change is considered breaking when upgrading existing ONNX models from the old schema version to the new one could alter observable behaviour without any other modification. Examples of breaking changes:
Removing a previously required input or output.
Adding a new required input (existing models do not supply it).
Changing an attribute’s type or making an optional attribute required.
Narrowing a type constraint (removing previously allowed types).
Non-breaking examples:
Adding a new optional input or output.
Widening a type constraint (adding new allowed types).
Adding an optional attribute with a sensible default.
- class onnx_light.compatibility.schema_diff.AttributeDiff(name: str, kind: str, details: list[str] = <factory>, is_breaking: bool = False)#
Bases:
objectRecords a difference in a single operator attribute.
- Parameters:
name – Name of the attribute.
kind – Type of difference:
'added','removed', or'changed'.details – Human-readable description of what changed.
is_breaking –
Trueif the difference is a breaking change.
- classmethod compare(old_attrs: dict[str, Any], new_attrs: dict[str, Any]) list[AttributeDiff]#
Compares two attribute dictionaries from
OpSchemaobjects.- Parameters:
old_attrs – Attribute mapping from the old schema.
new_attrs – Attribute mapping from the new schema.
- Returns:
A list of
AttributeDiffitems describing additions, removals, and changes.- Return type:
- class onnx_light.compatibility.schema_diff.ConstraintDiff(name: str, kind: str, added_types: list[str] = <factory>, removed_types: list[str] = <factory>, details: list[str] = <factory>, is_breaking: bool = False)#
Bases:
objectRecords a difference in a type constraint.
- Parameters:
name – Type parameter string (e.g.
'T','T1').kind – Type of difference:
'added','removed', or'changed'.added_types – Types present in the new schema but not in the old one.
removed_types – Types present in the old schema but not in the new one.
details – Human-readable description of what changed.
is_breaking –
Trueif the difference is a breaking change.
- classmethod compare(old_constraints: list[Any], new_constraints: list[Any]) list[ConstraintDiff]#
Compares two lists of type constraint parameters.
- Parameters:
old_constraints – Type constraints from the old schema.
new_constraints – Type constraints from the new schema.
- Returns:
A list of
ConstraintDiffitems describing additions, removals, and changes.- Return type:
- class onnx_light.compatibility.schema_diff.DocDiff(old_doc: str = '', new_doc: str = '', similarity: float = 1.0, unified_diff: list[str] = <factory>, added_lines: int = 0, removed_lines: int = 0)#
Bases:
objectRecords a difference between two operator documentation strings.
Differences are computed at the line level using
difflib.SequenceMatcher()anddifflib.unified_diff(), rather than at the character level. This matches how humans typically edit docstrings (line by line) and produces a much more readable diff.A documentation change is never considered breaking on its own, but it is still useful information when reviewing a new operator schema version.
- Parameters:
old_doc – Documentation string of the old schema (may be empty).
new_doc – Documentation string of the new schema (may be empty).
similarity – Line-level similarity ratio in
[0.0, 1.0]as returned bydifflib.SequenceMatcher.ratio()applied to the list of lines. A value of1.0means the two docs are identical.unified_diff – A list of lines produced by
difflib.unified_diff()describing the line-level edits to transformold_docintonew_doc. Empty when the two docs are identical.added_lines – Number of inserted lines (
+lines in the unified diff, excluding the file header).removed_lines – Number of removed lines (
-lines in the unified diff, excluding the file header).
- classmethod compare(old_doc: str | None, new_doc: str | None, old_label: str = 'old', new_label: str = 'new', context_lines: int = 3) DocDiff#
Compares two documentation strings at the line level.
The two strings are split into lines (preserving relative blank lines). Similarity is computed with
difflib.SequenceMatcher.ratio()on the resulting lists, which is equivalent to a normalised line-level edit distance. A unified diff is produced withdifflib.unified_diff()so the result renders nicely both as plain text and inside RSTcode-block:: diffdirectives.- Parameters:
old_doc – Old documentation string (
Noneis treated as an empty string).new_doc – New documentation string (
Noneis treated as an empty string).old_label – Label used for the old side of the unified diff header.
new_label – Label used for the new side of the unified diff header.
context_lines – Number of context lines around each hunk in the unified diff.
- Returns:
A
DocDiffsummarising the differences.- Return type:
- class onnx_light.compatibility.schema_diff.ParameterDiff(name: str, kind: str, details: list[str] = <factory>, is_breaking: bool = False)#
Bases:
objectRecords a difference in a single input or output formal parameter.
- Parameters:
name – Name of the input or output parameter.
kind – Type of difference:
'added','removed', or'changed'.details – Human-readable description of what changed.
is_breaking –
Trueif the difference is a breaking change.
- classmethod compare(old_params: list[Any], new_params: list[Any], kind_label: str) list[ParameterDiff]#
Compares two lists of formal parameters (inputs or outputs).
- Parameters:
old_params – Formal parameters from the old schema.
new_params – Formal parameters from the new schema.
kind_label – Label used for context (
'input'or'output').
- Returns:
A list of
ParameterDiffitems describing additions, removals, and changes.- Return type:
- class onnx_light.compatibility.schema_diff.SchemaDiff(op_name: str, domain: str, old_version: int, new_version: int, inputs: list[ParameterDiff] = <factory>, outputs: list[ParameterDiff] = <factory>, attributes: list[AttributeDiff] = <factory>, constraints: list[ConstraintDiff] = <factory>, doc: DocDiff = <factory>, is_breaking: bool = False, breaking_reasons: list[str] = <factory>)#
Bases:
objectSummarizes the differences between two versions of an operator schema.
Use
compare_schemas()to create instances of this class.- Parameters:
op_name – Operator name.
domain – Operator domain.
old_version –
since_versionof the old (reference) schema.new_version –
since_versionof the new schema.inputs – Differences in formal input parameters.
outputs – Differences in formal output parameters.
attributes – Differences in attributes.
constraints – Differences in type constraints.
doc – Line-level diff of the operator documentation strings.
is_breaking –
Trueif any individual change is breaking.breaking_reasons – Human-readable list of reasons why the change is breaking.
- attributes: list[AttributeDiff]#
- constraints: list[ConstraintDiff]#
- inputs: list[ParameterDiff]#
- outputs: list[ParameterDiff]#
- to_rst() str#
Returns an RST-formatted summary of the schema diff.
Produces reStructuredText markup suitable for inclusion in Sphinx documentation (e.g. via a
.. runpython::directive with the:rst:flag, provided by thesphinx-runpythonextension).- Returns:
An RST string describing all differences.
- Return type:
- onnx_light.compatibility.schema_diff.compare_schemas(schema_old: Any, schema_new: Any) SchemaDiff#
Compares two
OpSchemaobjects for the same operator.The function inspects inputs, outputs, attributes, and type constraints and highlights what was added, removed, or changed. It also determines whether the transition from schema_old to schema_new constitutes a breaking change, defined as a change that would alter the observable behaviour of an existing model when its operator is upgraded to the new schema version without any other modification.
- Parameters:
schema_old – The reference (typically older) schema.
schema_new – The schema compared against (typically newer).
- Returns:
A
SchemaDiffinstance summarising all detected differences.- Return type:
<<<
from onnx_light.onnx import defs from onnx_light.compatibility.schema_diff import compare_schemas defs.register_onnx_operator_set_schema() old = defs.get_schema("Relu", 6) new = defs.get_schema("Relu", 14) diff = compare_schemas(old, new) print(diff)
>>>
SchemaDiff: Relu (domain='') old version : 6 new version : 14 breaking : False Type constraints: changed 'T': added types: ['tensor(bfloat16)', 'tensor(int16)', 'tensor(int32)', 'tensor(int64)', 'tensor(int8)']
The function also accepts lightweight schemas exposed by
onnx_light(onnx_proto._onnxpy.onnx_op.LightOpSchema). Those schemas do not expose attributes nor input/output arity, so those parts of the diff are simply omitted when both schemas lack them.<<<
from collections import defaultdict from onnx_light.onnx_proto._onnxpy import onnx_op from onnx_light.compatibility.schema_diff import compare_schemas by_name = defaultdict(list) for s in onnx_op.GetAllOnnxOpSchemasWithHistory(True): by_name[(s.domain, s.name)].append(s) versions = sorted(by_name[("ai.onnx", "Add")], key=lambda s: s.since_version) old, new = versions[0], versions[-1] diff = compare_schemas(old, new) print(diff)
>>>
SchemaDiff: Add (domain='ai.onnx') old version : 1 new version : 14 breaking : False Type constraints: changed 'T': added types: ['tensor(bfloat16)', 'tensor(int16)', 'tensor(int32)', 'tensor(int64)', 'tensor(int8)', 'tensor(uint16)', 'tensor(uint32)', 'tensor(uint64)', 'tensor(uint8)'] Documentation: line similarity: 0.09 (+3/-18 lines) --- Add v1 +++ Add v14 @@ -1,19 +1,4 @@ -Performs element-wise binary addition (with limited broadcast support). -If necessary the right-hand-side argument will be broadcasted to match the -shape of left-hand-side argument. When broadcasting is specified, the second -tensor can either be of element size 1 (including a scalar tensor and any -tensor with rank equal to or smaller than the first tensor), or having its -shape as a contiguous subset of the first tensor's shape. The starting of the -mutually equal shape is specified by the argument "axis", and if it is not set, -suffix matching is assumed. 1-dim expansion doesn't work yet. +Performs element-wise binary addition (with Numpy-style broadcasting support). -For example, the following tensor shapes are supported (with broadcast=1): - - shape(A) = (2, 3, 4, 5), shape(B) = (,), i.e. B is a scalar tensor - shape(A) = (2, 3, 4, 5), shape(B) = (1, 1), i.e. B is an 1-element tensor - shape(A) = (2, 3, 4, 5), shape(B) = (5,) - shape(A) = (2, 3, 4, 5), shape(B) = (4, 5) - shape(A) = (2, 3, 4, 5), shape(B) = (3, 4), with axis=1 - shape(A) = (2, 3, 4, 5), shape(B) = (2), with axis=0 - -Attribute `broadcast=1` needs to be passed to enable broadcasting. +This operator supports multidirectional (i.e., Numpy-style) broadcasting; +for more details please check the broadcasting behavior in ONNX.