Skip to content

Commit 2bd53b8

Browse files
authored
docs: Sphinx 9 and fix member skipping (#2298)
1 parent 3bac10c commit 2bd53b8

14 files changed

Lines changed: 171 additions & 149 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{{ fullname | escape | underline}}
2+
3+
.. currentmodule:: {{ module }}
4+
5+
.. autoclass:: {{ objname }}
6+
:show-inheritance:
7+
8+
{% block attributes %}
9+
{%- for item in attributes %}
10+
{%- if loop.first %}
11+
.. rubric:: Attributes
12+
{% endif %}
13+
.. autoattribute:: {{ item }}
14+
{%- endfor %}
15+
{% endblock %}
16+
17+
{% block methods %}
18+
{%- for item in methods if item != "__init__" and item not in inherited_members %}
19+
{%- if loop.first %}
20+
.. rubric:: Methods
21+
{% endif %}
22+
.. automethod:: {{ item }}
23+
{%- endfor %}
24+
{% endblock %}

docs/_templates/autosummary/class.rst

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,28 @@
44

55
.. add toctree option to make autodoc generate the pages
66
7-
.. autoclass:: {{ objname }}
7+
.. autoclass:: {{ objname }}
88

9-
{% block attributes %}
10-
{% if attributes %}
11-
.. rubric:: Attributes
9+
{% block attributes %}
10+
{%- for item in attributes %}
11+
{%- if loop.first %}
12+
.. rubric:: Attributes
1213

13-
.. autosummary::
14-
:toctree: .
15-
{% for item in attributes %}
16-
~{{ name }}.{{ item }}
17-
{%- endfor %}
18-
{% endif %}
19-
{% endblock %}
14+
.. autosummary::
15+
:toctree: .
16+
{% endif %}
17+
~{{ name }}.{{ item }}
18+
{%- endfor %}
19+
{% endblock %}
2020

21-
{% block methods %}
22-
{% if methods %}
23-
.. rubric:: Methods
21+
{% block methods %}
22+
{%- for item in methods if item != "__init__" and item not in inherited_members %}
23+
{%- if loop.first %}
24+
.. rubric:: Methods
2425

25-
.. autosummary::
26-
:toctree: .
27-
{% for item in methods %}
28-
{%- if item != '__init__' %}
29-
~{{ name }}.{{ item }}
30-
{%- endif -%}
31-
{%- endfor %}
32-
{% endif %}
33-
{% endblock %}
26+
.. autosummary::
27+
:toctree: .
28+
{% endif %}
29+
~{{ name }}.{{ item }}
30+
{%- endfor %}
31+
{% endblock %}

docs/api.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,27 @@ Types used by the former:
173173
```{eval-rst}
174174
.. autosummary::
175175
:toctree: generated/
176+
:template: class-minimal
177+
:signatures: none
176178
177179
experimental.IOSpec
178180
experimental.Read
179181
experimental.Write
180182
experimental.ReadCallback
181183
experimental.WriteCallback
182-
experimental.StorageType
183184
experimental.backed.MaskedArray
184185
experimental.backed.CategoricalArray
185186
experimental.backed.Dataset2D
186187
experimental.Dataset2DIlocIndexer
188+
189+
..
190+
this is not a class/protocol so since the above
191+
specifies a template, it gets used.
192+
193+
.. autosummary::
194+
:toctree: generated/
195+
196+
experimental.StorageType
187197
```
188198

189199
(extensions-api)=
@@ -237,9 +247,18 @@ Types used by the former:
237247
```{eval-rst}
238248
.. autosummary::
239249
:toctree: generated/
250+
:template: class-minimal
240251
241252
abc.CSRDataset
242253
abc.CSCDataset
254+
```
255+
256+
.. these are types, not classes
257+
258+
```{eval-rst}
259+
.. autosummary::
260+
:toctree: generated/
261+
243262
typing.Index
244263
typing.AxisStorable
245264
typing.RWAble

docs/conf.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
"scanpydoc", # needs to be before linkcode
6161
"sphinx.ext.linkcode",
6262
"IPython.sphinxext.ipython_console_highlighting",
63-
"sphinx_toolbox.more_autodoc.autoprotocol",
6463
*(p.stem for p in _extension_dir.glob("*.py")),
6564
]
6665
myst_enable_extensions = [
@@ -144,6 +143,7 @@ def res(
144143
)
145144

146145
qualname_overrides = {
146+
"types.EllipsisType": ("py:data", "Ellipsis"),
147147
"h5py._hl.group.Group": "h5py.Group",
148148
"h5py._hl.files.File": "h5py.File",
149149
"h5py._hl.dataset.Dataset": "h5py.Dataset",
@@ -157,6 +157,7 @@ def res(
157157
"anndata._types.WriteCallback": "anndata.experimental.WriteCallback",
158158
"anndata._types.Read": "anndata.experimental.Read",
159159
"anndata._types.Write": "anndata.experimental.Write",
160+
"anndata._types.StorageType": "anndata.experimental.StorageType",
160161
"anndata._types.Dataset2DIlocIndexer": "anndata.experimental.Dataset2DIlocIndexer",
161162
"zarr.core.array.Array": "zarr.Array",
162163
"zarr.core.group.Group": "zarr.Group",
@@ -168,19 +169,27 @@ def res(
168169
"anndata.compat.CupySparseMatrix": "cupyx.scipy.sparse.spmatrix",
169170
"anndata.compat.XDataArray": "xarray.DataArray",
170171
"anndata.compat.XDataset": "xarray.Dataset",
172+
"anndata.compat.Index": "anndata.typing.Index",
171173
"awkward.highlevel.Array": "ak.Array",
172174
"numpy.int64": ("py:attr", "numpy.int64"),
173175
"numpy.dtypes.StringDType": ("py:attr", "numpy.dtypes.StringDType"),
174176
"pandas.DataFrame.iloc": ("py:attr", "pandas.DataFrame.iloc"),
175177
"pandas.DataFrame.loc": ("py:attr", "pandas.DataFrame.loc"),
178+
"pandas.core.series.Series": "pandas.Series",
179+
"pandas.core.arrays.categorical.Categorical": "pandas.Categorical",
180+
"pandas.core.arrays.base.ExtensionArray": "pandas.api.extensions.ExtensionArray",
176181
"pandas.core.dtypes.dtypes.BaseMaskedDtype": "pandas.api.extensions.ExtensionDtype",
177-
# should be fixed soon: https://github.com/tox-dev/sphinx-autodoc-typehints/pull/516
178-
"types.EllipsisType": ("py:data", "types.EllipsisType"),
179-
"pathlib._local.Path": "pathlib.Path",
180182
}
181183
autodoc_type_aliases = dict(
182184
NDArray=":data:`~numpy.typing.NDArray`",
183185
AxisStorable=":data:`~anndata.typing.AxisStorable`",
186+
# The following are TypeVars in `anndata._types`, and aren’t actually exported,
187+
# yet this bug causes them to create issues:
188+
# - https://github.com/python/cpython/issues/124089
189+
# - https://github.com/tox-dev/sphinx-autodoc-typehints/issues/580
190+
K=":class:`zarr.Array` | :class:`h5py.Dataset`",
191+
S=":class:`anndata.experimental.StorageType`",
192+
RWAble=":class:`anndata.typing.RWAble`",
184193
)
185194

186195
# -- Social cards ---------------------------------------------------------

docs/extensions/autosummary_skip_inherited.py

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,58 @@
1-
"""Sphinx extension to not skip abstract methods."""
1+
"""Sphinx extension to not skip abstract/protocol methods."""
22

33
from __future__ import annotations
44

5+
import abc
6+
import sys
7+
from traceback import walk_stack
58
from typing import TYPE_CHECKING
69

7-
if TYPE_CHECKING:
8-
from typing import Literal
10+
if sys.version_info >= (3, 13):
11+
from typing import get_protocol_members, is_protocol
12+
else:
13+
from typing_extensions import get_protocol_members, is_protocol
914

15+
if TYPE_CHECKING:
1016
from sphinx.application import Sphinx
1117
from sphinx.ext.autodoc import Options
18+
from sphinx.ext.autodoc._property_types import _AutodocObjType
1219

1320

14-
def autodoc_skip_member( # noqa: PLR0917
21+
def no_skip_abc_members( # noqa: PLR0917
1522
app: Sphinx,
16-
what: Literal["module", "class", "exception", "function", "method", "attribute"],
23+
what: _AutodocObjType,
1724
name: str,
1825
obj: object,
1926
skip: bool, # noqa: FBT001
2027
options: Options,
21-
):
22-
if what == "method" and getattr(obj, "__isabstractmethod__", False):
28+
) -> bool | None:
29+
if what in {"module", "class", "exception", "decorator"}:
30+
return None # speed up by not getting parent of non-class members
31+
32+
# Find parent class
33+
for frame, _ in walk_stack(None):
34+
if frame.f_code.co_name == "_get_members" and frame.f_code.co_filename.endswith(
35+
"/generate.py"
36+
):
37+
parent = frame.f_locals["obj"]
38+
if not isinstance(parent, type):
39+
return None
40+
break
41+
else:
42+
return None
43+
44+
# Don’t skip abstract methods or properties
45+
if issubclass(type(parent), abc.ABCMeta) and getattr(
46+
obj, "__isabstractmethod__", False
47+
):
2348
return False
49+
50+
# If we’re documenting a protocol attribute, include it
51+
if is_protocol(parent) and name in get_protocol_members(parent):
52+
return False
53+
2454
return None
2555

2656

27-
def setup(app: Sphinx):
28-
app.connect("autodoc-skip-member", autodoc_skip_member)
57+
def setup(app: Sphinx) -> None:
58+
app.connect("autodoc-skip-member", no_skip_abc_members)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, Generic, get_origin
4+
5+
if TYPE_CHECKING:
6+
from sphinx.application import Sphinx
7+
8+
9+
def skip_private_bases(
10+
app: Sphinx, name: str, obj: type, _unused, bases: list[type]
11+
) -> None:
12+
bases[:] = [
13+
b
14+
for b in bases
15+
if b is not object
16+
if get_origin(b) is not Generic
17+
if not b.__name__.startswith("_")
18+
]
19+
20+
21+
def setup(app: Sphinx) -> None:
22+
app.connect("autodoc-process-bases", skip_private_bases)

pyproject.toml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,18 @@ dev = [
5959
{ include-group = "dev-doc" },
6060
]
6161
doc = [
62-
"sphinx>=8.2.1,<9", # https://github.com/tox-dev/sphinx-autodoc-typehints/issues/586
62+
"sphinx>=9.1.0",
6363
"sphinx-book-theme>=1.1.0",
64-
"sphinx-autodoc-typehints>=2.2.0",
64+
"sphinx-autodoc-typehints>=3.6.2",
6565
"sphinx-issues>=5.0.1",
6666
"sphinx-copybutton",
67-
"sphinx-toolbox>=3.8.0",
6867
"sphinxext.opengraph",
6968
"myst-nb",
70-
"scanpydoc[theme,typehints] >=0.16",
69+
"scanpydoc[theme,typehints] >=0.17.1",
7170
"awkward>=2.6.3",
72-
"IPython", # For syntax highlighting in notebooks
73-
"myst_parser",
74-
"sphinx_design>=0.5.0",
71+
"IPython", # For syntax highlighting in notebooks
72+
"myst-parser",
73+
"sphinx-design",
7574
"anndata[dask]",
7675
# for unreleased changes
7776
{ include-group = "dev-doc" },

src/anndata/_core/xarray.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from __future__ import annotations
22

33
import warnings
4+
from collections.abc import Hashable, Mapping
45
from dataclasses import dataclass
56
from functools import wraps
6-
from typing import TYPE_CHECKING, overload
7+
from typing import TYPE_CHECKING, Self, overload
78

89
import numpy as np
910
import pandas as pd
@@ -13,14 +14,7 @@
1314
from ..compat import XDataArray, XDataset, XVariable, pandas_as_str
1415

1516
if TYPE_CHECKING:
16-
from collections.abc import (
17-
Callable,
18-
Collection,
19-
Hashable,
20-
Iterable,
21-
Iterator,
22-
Mapping,
23-
)
17+
from collections.abc import Callable, Collection, Iterable, Iterator
2418
from typing import Any, Literal
2519

2620
from .._types import Dataset2DIlocIndexer
@@ -39,10 +33,8 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
3933
return wrapper
4034

4135

42-
class Dataset2D:
36+
class Dataset2D(Mapping[Hashable, XDataArray | Self]):
4337
r"""
44-
Bases :class:`~collections.abc.Mapping`\ [:class:`~collections.abc.Hashable`, :class:`~xarray.DataArray` | :class:`~anndata.experimental.backed.Dataset2D`\ ]
45-
4638
A wrapper class meant to enable working with lazy dataframe data according to
4739
:class:`~anndata.AnnData`'s internal API. This class ensures that "dataframe-invariants"
4840
are respected, namely that there is only one 1d dim and coord with the same name i.e.,

0 commit comments

Comments
 (0)