fix(docs): restore operator examples (#8332)

### Motivation and Context

Fixes #8314

The operator docs generator passed the default ONNX domain as an empty
string, but the example lookup did not recognize it. It also assumed
non-default examples lived in domain subpackages and depended on
filenames matching operator names. This omitted existing examples from
generated pages and placed GreaterOrEqual and LessOrEqual examples under
Greater and Less in `docs/Operators.md`.

This treats the empty string as the default domain, limits top-level
fallback to the preview domains, aligns legacy module and exporter names
where safe, and keeps Range's legacy module through an explicit alias.
Example source is rendered directly inside trusted code fences so the
Sphinx build can highlight it.

Tested:

- `python -m pytest -q tests/python/onnx_sphinx_test.py` (12 passed)
- `python -m pytest -q tests/python/backend_test.py -k 'batchnorm or
greater_equal or instancenorm or less_equal or test_range or
softmaxcrossentropy'` (51 passed, 51 skipped)
- `ONNX_ML=1 python onnx/defs/gen_doc.py`
- `lintrunner -r HEAD`
- `cd docs/docsgen && make html`

---------

Signed-off-by: kiwigitops <kiwisclubco@gmail.com>
Co-authored-by: Andreas Fehlner <fehlner@arcor.de>
This commit is contained in:
Kiwi
2026-08-20 13:20:56 -04:00
committed by GitHub
parent bf0bd61413
commit 299ec33f2c
9 changed files with 329 additions and 239 deletions
+160 -156
View File
@@ -16281,7 +16281,86 @@ expect(node, inputs=[x, y], outputs=[z], name="test_greater_uint64")
<details>
<summary>greater</summary>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"Greater",
inputs=["x", "y"],
outputs=["greater"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_bcast")
```
</details>
### <a name="GreaterOrEqual"></a><a name="greaterorequal">**GreaterOrEqual**</a>
Returns the tensor resulted from performing the `greater_equal` logical operation
elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).
This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md).
#### Version
This version of the operator has been available since version 16 of the default ONNX operator set.
Other versions of this operator: <a href="Changelog.md#GreaterOrEqual-12">12</a>
#### Inputs
<dl>
<dt><tt>A</tt> (non-differentiable) : T</dt>
<dd>First input operand for the logical operator.</dd>
<dt><tt>B</tt> (non-differentiable) : T</dt>
<dd>Second input operand for the logical operator.</dd>
</dl>
#### Outputs
<dl>
<dt><tt>C</tt> (non-differentiable) : T1</dt>
<dd>Result tensor.</dd>
</dl>
#### Type Constraints
<dl>
<dt><tt>T</tt> : tensor(uint8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(int8), tensor(int16), tensor(int32), tensor(int64), tensor(float16), tensor(float), tensor(double), tensor(bfloat16)</dt>
<dd>Constrain input types to all numeric tensors.</dd>
<dt><tt>T1</tt> : tensor(bool)</dt>
<dd>Constrain output to boolean tensor.</dd>
</dl>
#### Examples
<details>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"GreaterOrEqual",
inputs=["x", "y"],
outputs=["greater_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_equal_bcast")
```
</details>
<details>
<summary>greaterorequal</summary>
```python
node = onnx.helper.make_node(
@@ -16329,83 +16408,6 @@ expect(node, inputs=[x, y], outputs=[z], name="test_greater_equal_uint64")
</details>
<details>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"Greater",
inputs=["x", "y"],
outputs=["greater"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_bcast")
```
</details>
<details>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"GreaterOrEqual",
inputs=["x", "y"],
outputs=["greater_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_equal_bcast")
```
</details>
### <a name="GreaterOrEqual"></a><a name="greaterorequal">**GreaterOrEqual**</a>
Returns the tensor resulted from performing the `greater_equal` logical operation
elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).
This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md).
#### Version
This version of the operator has been available since version 16 of the default ONNX operator set.
Other versions of this operator: <a href="Changelog.md#GreaterOrEqual-12">12</a>
#### Inputs
<dl>
<dt><tt>A</tt> (non-differentiable) : T</dt>
<dd>First input operand for the logical operator.</dd>
<dt><tt>B</tt> (non-differentiable) : T</dt>
<dd>Second input operand for the logical operator.</dd>
</dl>
#### Outputs
<dl>
<dt><tt>C</tt> (non-differentiable) : T1</dt>
<dd>Result tensor.</dd>
</dl>
#### Type Constraints
<dl>
<dt><tt>T</tt> : tensor(uint8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(int8), tensor(int16), tensor(int32), tensor(int64), tensor(float16), tensor(float), tensor(double), tensor(bfloat16)</dt>
<dd>Constrain input types to all numeric tensors.</dd>
<dt><tt>T1</tt> : tensor(bool)</dt>
<dd>Constrain output to boolean tensor.</dd>
</dl>
### <a name="GridSample"></a><a name="gridsample">**GridSample**</a>
Given an input `X` and a flow-field `grid`, computes the output `Y` using `X` values and pixel locations from the `grid`.
@@ -19536,7 +19538,86 @@ expect(node, inputs=[x, y], outputs=[z], name="test_less_uint64")
<details>
<summary>less</summary>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"Less",
inputs=["x", "y"],
outputs=["less"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_bcast")
```
</details>
### <a name="LessOrEqual"></a><a name="lessorequal">**LessOrEqual**</a>
Returns the tensor resulted from performing the `less_equal` logical operation
elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).
This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md).
#### Version
This version of the operator has been available since version 16 of the default ONNX operator set.
Other versions of this operator: <a href="Changelog.md#LessOrEqual-12">12</a>
#### Inputs
<dl>
<dt><tt>A</tt> (non-differentiable) : T</dt>
<dd>First input operand for the logical operator.</dd>
<dt><tt>B</tt> (non-differentiable) : T</dt>
<dd>Second input operand for the logical operator.</dd>
</dl>
#### Outputs
<dl>
<dt><tt>C</tt> (non-differentiable) : T1</dt>
<dd>Result tensor.</dd>
</dl>
#### Type Constraints
<dl>
<dt><tt>T</tt> : tensor(uint8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(int8), tensor(int16), tensor(int32), tensor(int64), tensor(float16), tensor(float), tensor(double), tensor(bfloat16)</dt>
<dd>Constrain input types to all numeric tensors.</dd>
<dt><tt>T1</tt> : tensor(bool)</dt>
<dd>Constrain output to boolean tensor.</dd>
</dl>
#### Examples
<details>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"LessOrEqual",
inputs=["x", "y"],
outputs=["less_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_equal_bcast")
```
</details>
<details>
<summary>lessorequal</summary>
```python
node = onnx.helper.make_node(
@@ -19584,83 +19665,6 @@ expect(node, inputs=[x, y], outputs=[z], name="test_less_equal_uint64")
</details>
<details>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"Less",
inputs=["x", "y"],
outputs=["less"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_bcast")
```
</details>
<details>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"LessOrEqual",
inputs=["x", "y"],
outputs=["less_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_equal_bcast")
```
</details>
### <a name="LessOrEqual"></a><a name="lessorequal">**LessOrEqual**</a>
Returns the tensor resulted from performing the `less_equal` logical operation
elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support).
This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md).
#### Version
This version of the operator has been available since version 16 of the default ONNX operator set.
Other versions of this operator: <a href="Changelog.md#LessOrEqual-12">12</a>
#### Inputs
<dl>
<dt><tt>A</tt> (non-differentiable) : T</dt>
<dd>First input operand for the logical operator.</dd>
<dt><tt>B</tt> (non-differentiable) : T</dt>
<dd>Second input operand for the logical operator.</dd>
</dl>
#### Outputs
<dl>
<dt><tt>C</tt> (non-differentiable) : T1</dt>
<dd>Result tensor.</dd>
</dl>
#### Type Constraints
<dl>
<dt><tt>T</tt> : tensor(uint8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(int8), tensor(int16), tensor(int32), tensor(int64), tensor(float16), tensor(float), tensor(double), tensor(bfloat16)</dt>
<dd>Constrain input types to all numeric tensors.</dd>
<dt><tt>T1</tt> : tensor(bool)</dt>
<dd>Constrain output to boolean tensor.</dd>
</dl>
### <a name="LinearAttention"></a><a name="linearattention">**LinearAttention**</a>
Unified linear attention operator for autoregressive decoding (T=1) and prefill (T>1).
+81 -79
View File
@@ -6,7 +6,7 @@
* [Overall Test Coverage](#overall-test-coverage)
# Node Test Coverage
## Summary
Node tests have covered 190/202 (94.06%, 5 generators excluded) common operators.
Node tests have covered 192/202 (95.05%, 5 generators excluded) common operators.
Node tests have covered 1/1 (100.00%, 0 generators excluded) experimental operators.
@@ -12058,7 +12058,7 @@ expect(
### Greater
There are 4 test cases, listed as following:
There are 2 test cases, listed as following:
<details>
<summary>greater</summary>
@@ -12107,7 +12107,45 @@ expect(node, inputs=[x, y], outputs=[z], name="test_greater_uint64")
</details>
<details>
<summary>greater</summary>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"Greater",
inputs=["x", "y"],
outputs=["greater"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_bcast")
```
</details>
### GreaterOrEqual
There are 2 test cases, listed as following:
<details>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"GreaterOrEqual",
inputs=["x", "y"],
outputs=["greater_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_equal_bcast")
```
</details>
<details>
<summary>greaterorequal</summary>
```python
node = onnx.helper.make_node(
@@ -12152,40 +12190,6 @@ z = np.greater_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_equal_uint64")
```
</details>
<details>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"Greater",
inputs=["x", "y"],
outputs=["greater"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_bcast")
```
</details>
<details>
<summary>greater_broadcast</summary>
```python
node = onnx.helper.make_node(
"GreaterOrEqual",
inputs=["x", "y"],
outputs=["greater_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.greater_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_greater_equal_bcast")
```
</details>
@@ -14255,7 +14259,7 @@ expect(node, inputs=[x], outputs=[y], name="test_leakyrelu_default")
### Less
There are 4 test cases, listed as following:
There are 2 test cases, listed as following:
<details>
<summary>less</summary>
@@ -14304,7 +14308,45 @@ expect(node, inputs=[x, y], outputs=[z], name="test_less_uint64")
</details>
<details>
<summary>less</summary>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"Less",
inputs=["x", "y"],
outputs=["less"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_bcast")
```
</details>
### LessOrEqual
There are 2 test cases, listed as following:
<details>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"LessOrEqual",
inputs=["x", "y"],
outputs=["less_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_equal_bcast")
```
</details>
<details>
<summary>lessorequal</summary>
```python
node = onnx.helper.make_node(
@@ -14349,40 +14391,6 @@ z = np.less_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_equal_uint64")
```
</details>
<details>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"Less",
inputs=["x", "y"],
outputs=["less"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_bcast")
```
</details>
<details>
<summary>less_broadcast</summary>
```python
node = onnx.helper.make_node(
"LessOrEqual",
inputs=["x", "y"],
outputs=["less_equal"],
)
x = np.random.randn(3, 4, 5).astype(np.float32)
y = np.random.randn(5).astype(np.float32)
z = np.less_equal(x, y)
expect(node, inputs=[x, y], outputs=[z], name="test_less_equal_bcast")
```
</details>
@@ -31526,12 +31534,6 @@ expect(node, inputs=[x, y], outputs=[z], name="test_xor_bcast4v4d")
### GlobalLpPool (call for test cases)
### GreaterOrEqual (call for test cases)
### LessOrEqual (call for test cases)
### MaxRoiPool (call for test cases)
+23 -2
View File
@@ -184,7 +184,7 @@ The function definition for this operator.
#### {{ example }}
```python
{{ format_example(code) }}
{{ format_example(code) | safe }}
```
{% endfor %}
{% endif %}
@@ -644,6 +644,10 @@ def _process_example(code: str) -> str:
return "\n".join(elements)
_EXAMPLE_MODULE_ALIASES = {"Range": "rangeop"}
_TOP_LEVEL_EXAMPLE_DOMAINS = {"ai.onnx.preview", "ai.onnx.preview.training"}
def get_onnx_example(op_name, domain):
"""Retrieves examples associated to one operator
stored in onnx packages.
@@ -652,17 +656,27 @@ def get_onnx_example(op_name, domain):
:param fmt: rendering format
:return: dictionary
"""
if domain in (None, "ai.onnx"):
fallback_modules = []
if domain in (None, "", "ai.onnx"):
modules = [
f"onnx.backend.test.case.node.{op_name.lower()}",
f"onnx.backend.test.case.node.{pascal_to_snake_case(op_name)}",
]
if op_name in _EXAMPLE_MODULE_ALIASES:
modules.append(
f"onnx.backend.test.case.node.{_EXAMPLE_MODULE_ALIASES[op_name]}"
)
else:
domain_ = domain.replace(".", "_")
modules = [
f"onnx.backend.test.case.node.{domain_}.{op_name.lower()}",
f"onnx.backend.test.case.node.{domain_}.{pascal_to_snake_case(op_name)}",
]
if domain in _TOP_LEVEL_EXAMPLE_DOMAINS:
fallback_modules = [
f"onnx.backend.test.case.node.{op_name.lower()}",
f"onnx.backend.test.case.node.{pascal_to_snake_case(op_name)}",
]
module = None
for m in modules:
try:
@@ -670,6 +684,13 @@ def get_onnx_example(op_name, domain):
module = m
except ImportError: # noqa: PERF203
continue
if module is None:
for m in fallback_modules:
try:
mod = importlib.import_module(m)
module = m
except ImportError: # noqa: PERF203
continue
if module is None:
# Unable to find an example for 'op_name'.
return {}
@@ -10,7 +10,7 @@ from onnx.backend.test.case.base import Base
from onnx.backend.test.case.node import expect
class Greater(Base):
class GreaterOrEqual(Base):
@staticmethod
def export() -> None:
node = onnx.helper.make_node(
@@ -10,7 +10,7 @@ from onnx.backend.test.case.base import Base
from onnx.backend.test.case.node import expect
class Less(Base):
class LessOrEqual(Base):
@staticmethod
def export() -> None:
node = onnx.helper.make_node(
+63
View File
@@ -0,0 +1,63 @@
# Copyright (c) ONNX Project Contributors
#
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import pytest
pytest.importorskip("sphinx")
from docs.docsgen.source import onnx_sphinx
@pytest.mark.parametrize(
"op_name",
[
"BatchNormalization",
"GreaterOrEqual",
"InstanceNormalization",
"LessOrEqual",
"Range",
"SoftmaxCrossEntropyLoss",
],
)
def test_get_markdown_doc_includes_backend_examples(op_name: str) -> None:
docs, _, example_count = onnx_sphinx.get_markdown_doc(
".", op_name=op_name, domain="", example=True
)
assert example_count > 0
assert "### Examples" in docs
def test_get_markdown_doc_keeps_example_source_unescaped() -> None:
docs, _, example_count = onnx_sphinx.get_markdown_doc(
".", op_name="Attention", domain="", example=True
)
assert example_count > 0
assert "&#34;" not in docs.split("### Examples", maxsplit=1)[1]
@pytest.mark.parametrize(
("op_name", "domain"),
[
("Adagrad", "ai.onnx.preview.training"),
("Adam", "ai.onnx.preview.training"),
("FlexAttention", "ai.onnx.preview"),
("Momentum", "ai.onnx.preview.training"),
],
)
def test_get_markdown_doc_finds_top_level_domain_examples(
op_name: str, domain: str
) -> None:
docs, _, example_count = onnx_sphinx.get_markdown_doc(
".", op_name=op_name, domain=domain, example=True
)
assert example_count > 0
assert "### Examples" in docs
def test_get_onnx_example_does_not_fall_back_for_unrelated_domains() -> None:
assert onnx_sphinx.get_onnx_example("Add", "ai.onnx.ml") == {}