Skip to content

Commit 2a2bb6b

Browse files
committed
Group linalg API docs by category and pin them to __all__
The linalg.rst page used `.. automodule:: pytensor.tensor.linalg :members:`, which renders all 36 functions from `__all__` as one unstructured alphabetical list. Replace it with hand-grouped sections (Constructors / Decomposition / Inverse / Products / Solve / Summary) that mirror the internal `_linalg/` package layout, using explicit `autofunction::` directives. To stop the rst from drifting away from the public API, add `tests/tensor/linalg/test_doc_api.py`. It parses every `.. autofunction:: pytensor.tensor.linalg.<name>` directive out of the rst and asserts the resulting set is exactly equal to `pytensor.tensor.linalg.__all__`. Any future addition or removal on either side fails the test with a precise diff. Op classes remain undocumented in the rst — the public surface is intentionally functions only.
1 parent be9420a commit 2a2bb6b

File tree

2 files changed

+118
-4
lines changed

2 files changed

+118
-4
lines changed

doc/library/tensor/linalg.rst

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,65 @@
88
:platform: Unix, Windows
99
:synopsis: Linear Algebra Operations
1010

11-
API
12-
===
11+
The :mod:`pytensor.tensor.linalg` module exposes the user-facing linear
12+
algebra API.
1313

14-
.. automodule:: pytensor.tensor.linalg
15-
:members:
14+
Constructors
15+
============
1616

17+
.. autofunction:: pytensor.tensor.linalg.block_diag
18+
19+
Decomposition
20+
=============
21+
22+
.. autofunction:: pytensor.tensor.linalg.cholesky
23+
.. autofunction:: pytensor.tensor.linalg.lu
24+
.. autofunction:: pytensor.tensor.linalg.lu_factor
25+
.. autofunction:: pytensor.tensor.linalg.pivot_to_permutation
26+
.. autofunction:: pytensor.tensor.linalg.qr
27+
.. autofunction:: pytensor.tensor.linalg.svd
28+
.. autofunction:: pytensor.tensor.linalg.eig
29+
.. autofunction:: pytensor.tensor.linalg.eigh
30+
.. autofunction:: pytensor.tensor.linalg.eigvalsh
31+
.. autofunction:: pytensor.tensor.linalg.schur
32+
.. autofunction:: pytensor.tensor.linalg.qz
33+
.. autofunction:: pytensor.tensor.linalg.ordqz
34+
35+
Inverse
36+
=======
37+
38+
.. autofunction:: pytensor.tensor.linalg.inv
39+
.. autofunction:: pytensor.tensor.linalg.pinv
40+
.. autofunction:: pytensor.tensor.linalg.tensorinv
41+
42+
Products
43+
========
44+
45+
.. autofunction:: pytensor.tensor.linalg.kron
46+
.. autofunction:: pytensor.tensor.linalg.matrix_dot
47+
.. autofunction:: pytensor.tensor.linalg.matrix_power
48+
.. autofunction:: pytensor.tensor.linalg.expm
49+
50+
Solve
51+
=====
52+
53+
.. autofunction:: pytensor.tensor.linalg.solve
54+
.. autofunction:: pytensor.tensor.linalg.solve_triangular
55+
.. autofunction:: pytensor.tensor.linalg.lu_solve
56+
.. autofunction:: pytensor.tensor.linalg.cho_solve
57+
.. autofunction:: pytensor.tensor.linalg.lstsq
58+
.. autofunction:: pytensor.tensor.linalg.tensorsolve
59+
.. autofunction:: pytensor.tensor.linalg.tridiagonal_lu_factor
60+
.. autofunction:: pytensor.tensor.linalg.tridiagonal_lu_solve
61+
.. autofunction:: pytensor.tensor.linalg.solve_continuous_lyapunov
62+
.. autofunction:: pytensor.tensor.linalg.solve_discrete_lyapunov
63+
.. autofunction:: pytensor.tensor.linalg.solve_discrete_are
64+
.. autofunction:: pytensor.tensor.linalg.solve_sylvester
65+
66+
Summary
67+
=======
68+
69+
.. autofunction:: pytensor.tensor.linalg.det
70+
.. autofunction:: pytensor.tensor.linalg.slogdet
71+
.. autofunction:: pytensor.tensor.linalg.norm
72+
.. autofunction:: pytensor.tensor.linalg.trace
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Guard against drift between `pytensor.tensor.linalg.__all__` and the
2+
`doc/library/tensor/linalg.rst` API page.
3+
4+
Both sides have to be edited together: if you add a new function to
5+
`__all__`, this test will fail until you also document it in the rst,
6+
and vice-versa. The doc page is hand-grouped into logical sections
7+
(decomposition, solve, ...), which is why we don't generate it from
8+
`__all__` automatically — but we do want a hard guarantee that the two
9+
stay in sync.
10+
"""
11+
12+
import re
13+
from pathlib import Path
14+
15+
import pytensor.tensor.linalg as linalg
16+
17+
18+
DOC_PATH = (
19+
Path(__file__).resolve().parents[3] / "doc" / "library" / "tensor" / "linalg.rst"
20+
)
21+
22+
_AUTOFUNCTION_RE = re.compile(
23+
r"^\.\.\s+autofunction::\s+pytensor\.tensor\.linalg\.(\w+)\s*$",
24+
re.MULTILINE,
25+
)
26+
27+
28+
def _documented_names() -> set[str]:
29+
return set(_AUTOFUNCTION_RE.findall(DOC_PATH.read_text()))
30+
31+
32+
def test_linalg_doc_matches_all():
33+
documented = _documented_names()
34+
exported = set(linalg.__all__)
35+
36+
missing_from_docs = exported - documented
37+
missing_from_all = documented - exported
38+
39+
assert not missing_from_docs, (
40+
f"{len(missing_from_docs)} name(s) in pytensor.tensor.linalg.__all__ "
41+
f"are not documented in {DOC_PATH.name}: {sorted(missing_from_docs)}. "
42+
"Add an `.. autofunction::` entry to the appropriate section."
43+
)
44+
assert not missing_from_all, (
45+
f"{len(missing_from_all)} name(s) documented in {DOC_PATH.name} "
46+
f"are not in pytensor.tensor.linalg.__all__: {sorted(missing_from_all)}. "
47+
"Either add them to `__all__` or remove the rst entry."
48+
)
49+
50+
51+
def test_linalg_doc_has_no_duplicate_entries():
52+
text = DOC_PATH.read_text()
53+
documented = _AUTOFUNCTION_RE.findall(text)
54+
duplicates = {name for name in documented if documented.count(name) > 1}
55+
assert not duplicates, (
56+
f"Duplicate `.. autofunction::` entries in {DOC_PATH.name}: "
57+
f"{sorted(duplicates)}"
58+
)

0 commit comments

Comments
 (0)