Skip to content

Commit 26478f0

Browse files
authored
docs: clean up typing module (#2325)
1 parent 3fbb0ea commit 26478f0

24 files changed

Lines changed: 210 additions & 167 deletions

docs/api.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,17 @@ Types used by the former:
253253
abc.CSCDataset
254254
```
255255

256-
.. these are types, not classes
256+
<!-- these are types, not classes, so don’t use the above template -->
257257

258258
```{eval-rst}
259+
.. toctree::
260+
:hidden:
261+
262+
typing
263+
259264
.. autosummary::
260-
:toctree: generated/
261265
266+
typing.Index1D
262267
typing.Index
263268
typing.AxisStorable
264269
typing.RWAble

docs/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,10 @@ def res(
145145
for kind in ["", "View"]
146146
},
147147
# Can’t use `set_module` for `type`s. When moving out of .experimental, define in actual location.
148-
"anndata.compat.Index": "anndata.typing.Index",
149148
"anndata._types.StorageType": "anndata.experimental.StorageType",
150149
# https://github.com/theislab/scanpydoc/issues/254
150+
"anndata.typing.Index1D": "anndata.typing.Index1D",
151+
"anndata.typing.Index": "anndata.typing.Index",
151152
"anndata.typing.RWAble": "anndata.typing.RWAble",
152153
"anndata.typing.AxisStorable": "anndata.typing.AxisStorable",
153154
#### h5py

docs/typing.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# anndata.typing
2+
3+
```{eval-rst}
4+
.. module:: anndata.typing
5+
6+
.. autotype:: Index1D
7+
.. autotype:: Index
8+
.. autotype:: AxisStorable
9+
.. autotype:: RWAble
10+
```

src/anndata/_core/anndata.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161

6262
from zarr.storage import StoreLike
6363

64-
from ..compat import Index1D, Index1DNorm, XDataset
65-
from ..typing import XDataType
64+
from ..compat import XDataset
65+
from ..typing import Index1D, _Index1DNorm, _XDataType
6666
from .aligned_mapping import AxisArraysView, LayersView, PairwiseArraysView
6767
from .index import Index
6868

@@ -206,8 +206,8 @@ class AnnData(metaclass=utils.DeprecationMixinMeta): # noqa: PLW1641
206206

207207
# view attributes
208208
_adata_ref: AnnData | None
209-
_oidx: Index1DNorm | None
210-
_vidx: Index1DNorm | None
209+
_oidx: _Index1DNorm | None
210+
_vidx: _Index1DNorm | None
211211

212212
@old_positionals(
213213
"obsm",
@@ -222,14 +222,14 @@ class AnnData(metaclass=utils.DeprecationMixinMeta): # noqa: PLW1641
222222
)
223223
def __init__( # noqa: PLR0913
224224
self,
225-
X: XDataType | pd.DataFrame | None = None,
225+
X: _XDataType | pd.DataFrame | None = None,
226226
obs: pd.DataFrame | Mapping[str, Iterable[Any]] | None = None,
227227
var: pd.DataFrame | Mapping[str, Iterable[Any]] | None = None,
228228
uns: Mapping[str, Any] | None = None,
229229
*,
230230
obsm: np.ndarray | Mapping[str, Sequence[Any]] | None = None,
231231
varm: np.ndarray | Mapping[str, Sequence[Any]] | None = None,
232-
layers: Mapping[str, XDataType] | None = None,
232+
layers: Mapping[str, _XDataType] | None = None,
233233
raw: Mapping[str, Any] | None = None,
234234
dtype: np.dtype | type | str | None = None,
235235
shape: tuple[int, int] | None = None,
@@ -238,8 +238,8 @@ def __init__( # noqa: PLR0913
238238
asview: bool = False,
239239
obsp: np.ndarray | Mapping[str, Sequence[Any]] | None = None,
240240
varp: np.ndarray | Mapping[str, Sequence[Any]] | None = None,
241-
oidx: Index1DNorm | int | np.integer | None = None,
242-
vidx: Index1DNorm | int | np.integer | None = None,
241+
oidx: _Index1DNorm | int | np.integer | None = None,
242+
vidx: _Index1DNorm | int | np.integer | None = None,
243243
):
244244
# check for any multi-indices that aren’t later checked in coerce_array
245245
for attr, key in [(obs, "obs"), (var, "var"), (X, "X")]:
@@ -273,8 +273,8 @@ def __init__( # noqa: PLR0913
273273
def _init_as_view(
274274
self,
275275
adata_ref: AnnData,
276-
oidx: Index1DNorm | int | np.integer,
277-
vidx: Index1DNorm | int | np.integer,
276+
oidx: _Index1DNorm | int | np.integer,
277+
vidx: _Index1DNorm | int | np.integer,
278278
):
279279
if adata_ref.isbacked and adata_ref.is_view:
280280
msg = (
@@ -571,7 +571,7 @@ def shape(self) -> tuple[int, int]:
571571
return self.n_obs, self.n_vars
572572

573573
@property
574-
def X(self) -> XDataType | None:
574+
def X(self) -> _XDataType | None:
575575
"""Data matrix of shape :attr:`n_obs` × :attr:`n_vars`."""
576576
if self.isbacked:
577577
if not self.file.is_open:
@@ -602,7 +602,7 @@ def X(self) -> XDataType | None:
602602
# return X
603603

604604
@X.setter
605-
def X(self, value: XDataType | None): # noqa: PLR0912
605+
def X(self, value: _XDataType | None): # noqa: PLR0912
606606
if value is None:
607607
if self.isbacked:
608608
msg = "Cannot currently remove data matrix from backed object."
@@ -1066,7 +1066,7 @@ def _set_backed(self, attr, value):
10661066

10671067
def _normalize_indices(
10681068
self, index: Index | None
1069-
) -> tuple[Index1DNorm | int | np.integer, Index1DNorm | int | np.integer]:
1069+
) -> tuple[_Index1DNorm | int | np.integer, _Index1DNorm | int | np.integer]:
10701070
return _normalize_indices(index, self.obs_names, self.var_names)
10711071

10721072
# TODO: this is not quite complete...
@@ -1244,7 +1244,7 @@ def _inplace_subset_obs(self, index: Index1D):
12441244
self._init_as_actual(adata_subset)
12451245

12461246
# TODO: Update, possibly remove
1247-
def __setitem__(self, index: Index, val: float | XDataType):
1247+
def __setitem__(self, index: Index, val: float | _XDataType):
12481248
if self.is_view:
12491249
msg = "Object is view and cannot be accessed with `[]`."
12501250
raise ValueError(msg)

src/anndata/_core/file_backing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from os import PathLike
1818
from typing import Literal
1919

20-
from .._types import ArrayStorageType
20+
from .._types import _ArrayStorageType
2121
from . import anndata
2222

2323

@@ -143,7 +143,7 @@ def to_memory(x, *, copy: bool = False):
143143

144144
@to_memory.register(ZarrArray)
145145
@to_memory.register(h5py.Dataset)
146-
def _(x: ArrayStorageType, *, copy: bool = False):
146+
def _(x: _ArrayStorageType, *, copy: bool = False):
147147
return x[...]
148148

149149

src/anndata/_core/index.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
if TYPE_CHECKING:
1717
from numpy.typing import NDArray
1818

19-
from ..compat import Index, Index1D, Index1DNorm
19+
from ..typing import Index, Index1D, _Index1DNorm
2020

2121

2222
def _normalize_indices(
2323
index: Index | None, names0: pd.Index, names1: pd.Index
24-
) -> tuple[Index1DNorm | int | np.integer, Index1DNorm | int | np.integer]:
24+
) -> tuple[_Index1DNorm | int | np.integer, _Index1DNorm | int | np.integer]:
2525
# deal with tuples of length 1
2626
if isinstance(index, tuple) and len(index) == 1:
2727
index = index[0]
@@ -33,7 +33,7 @@ def _normalize_indices(
3333

3434
def _normalize_index( # noqa: PLR0911, PLR0912
3535
indexer: Index1D, index: pd.Index
36-
) -> Index1DNorm | int | np.integer:
36+
) -> _Index1DNorm | int | np.integer:
3737
# TODO: why is this here? All tests pass without it and it seems at the minimum not strict enough.
3838
if not isinstance(index, pd.RangeIndex) and index.dtype in (np.float64, np.int64):
3939
msg = f"Don’t call _normalize_index with non-categorical/string names and non-range index {index}"
@@ -172,7 +172,7 @@ def unpack_index(index: Index) -> tuple[Index1D, Index1D]:
172172
@singledispatch
173173
def _subset(
174174
a: np.ndarray | pd.DataFrame,
175-
subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm],
175+
subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm],
176176
):
177177
# Select as combination of indexes, not coordinates
178178
# Correcting for indexing behaviour of np.ndarray
@@ -183,7 +183,7 @@ def _subset(
183183

184184
@_subset.register(DaskArray)
185185
def _subset_dask(
186-
a: DaskArray, subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm]
186+
a: DaskArray, subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm]
187187
):
188188
if len(subset_idx) > 1 and all(isinstance(x, Iterable) for x in subset_idx):
189189
if issparse(a._meta) and a._meta.format == "csc":
@@ -196,7 +196,7 @@ def _subset_dask(
196196
@_subset.register(CSArray)
197197
def _subset_sparse(
198198
a: CSMatrix | CSArray,
199-
subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm],
199+
subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm],
200200
):
201201
# Correcting for indexing behaviour of sparse.spmatrix
202202
if len(subset_idx) > 1 and all(isinstance(x, Iterable) for x in subset_idx):
@@ -211,14 +211,14 @@ def _subset_sparse(
211211
@_subset.register(Dataset2D)
212212
def _subset_df(
213213
df: pd.DataFrame | Dataset2D,
214-
subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm],
214+
subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm],
215215
):
216216
return df.iloc[subset_idx]
217217

218218

219219
@_subset.register(AwkArray)
220220
def _subset_awkarray(
221-
a: AwkArray, subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm]
221+
a: AwkArray, subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm]
222222
):
223223
if all(isinstance(x, Iterable) for x in subset_idx):
224224
subset_idx = np.ix_(*subset_idx)
@@ -228,7 +228,7 @@ def _subset_awkarray(
228228
# Registration for SparseDataset occurs in sparse_dataset.py
229229
@_subset.register(h5py.Dataset)
230230
def _subset_dataset(
231-
d: h5py.Dataset, subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm]
231+
d: h5py.Dataset, subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm]
232232
):
233233
order: tuple[NDArray[np.integer] | slice, ...]
234234
inv_order: tuple[NDArray[np.integer] | slice, ...]
@@ -252,8 +252,8 @@ def _index_order_and_inverse(
252252
@overload
253253
def _index_order_and_inverse(axis_idx: slice) -> tuple[slice, slice]: ...
254254
def _index_order_and_inverse(
255-
axis_idx: Index1DNorm,
256-
) -> tuple[Index1DNorm, NDArray[np.integer] | slice]:
255+
axis_idx: _Index1DNorm,
256+
) -> tuple[_Index1DNorm, NDArray[np.integer] | slice]:
257257
"""Order and get inverse index array."""
258258
if not isinstance(axis_idx, np.ndarray):
259259
return axis_idx, slice(None)
@@ -270,8 +270,8 @@ def _process_index_for_h5py(
270270
@overload
271271
def _process_index_for_h5py(idx: slice) -> tuple[slice, None]: ...
272272
def _process_index_for_h5py(
273-
idx: Index1DNorm,
274-
) -> tuple[Index1DNorm, NDArray[np.integer] | None]:
273+
idx: _Index1DNorm,
274+
) -> tuple[_Index1DNorm, NDArray[np.integer] | None]:
275275
"""Process a single index for h5py compatibility, handling sorting and duplicates."""
276276
if not isinstance(idx, np.ndarray):
277277
# Not an array (slice, integer, list) - no special processing needed
@@ -294,7 +294,7 @@ def _process_index_for_h5py(
294294

295295
def _safe_fancy_index_h5py(
296296
dataset: h5py.Dataset,
297-
subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm],
297+
subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm],
298298
) -> h5py.Dataset:
299299
# Handle multi-dimensional indexing of h5py dataset
300300
# This avoids h5py's limitation with multi-dimensional fancy indexing
@@ -331,7 +331,7 @@ def _safe_fancy_index_h5py(
331331
return result
332332

333333

334-
def _get_index_size(idx: Index1DNorm, dim_size: int) -> int:
334+
def _get_index_size(idx: _Index1DNorm, dim_size: int) -> int:
335335
"""Get size for any index type."""
336336
if isinstance(idx, slice):
337337
return len(range(*idx.indices(dim_size)))

src/anndata/_core/raw.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
from collections.abc import Mapping, Sequence
1818
from typing import ClassVar
1919

20-
from ..compat import CSMatrix, Index, Index1DNorm
20+
from ..compat import CSMatrix
21+
from ..typing import Index, _Index1DNorm
2122
from .aligned_mapping import AxisArraysView
2223
from .anndata import AnnData
2324
from .sparse_dataset import BaseCompressedSparseDataset
@@ -171,7 +172,7 @@ def to_adata(self) -> AnnData:
171172

172173
def _normalize_indices(
173174
self, packed_index: Index
174-
) -> tuple[Index1DNorm | int | np.integer, Index1DNorm | int | np.integer]:
175+
) -> tuple[_Index1DNorm | int | np.integer, _Index1DNorm | int | np.integer]:
175176
# deal with slicing with pd.Series
176177
if isinstance(packed_index, pd.Series):
177178
packed_index = packed_index.values

src/anndata/_core/sparse_dataset.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@
4848
from types import ModuleType
4949
from typing import Any, Literal
5050

51-
from .._types import ArrayStorageType, GroupStorageType
52-
from ..compat import Index1DNorm
53-
from .index import Index, Index1D
51+
from .._types import _ArrayStorageType, _GroupStorageType
52+
from ..typing import Index, Index1D, _Index1DNorm
5453

5554

5655
type DenseType = np.ndarray | CupyArray
@@ -97,7 +96,7 @@ def slice_as_int(s: slice, l: int) -> int:
9796

9897

9998
@dataclass
100-
class BackedSparseMatrix[ArrayT: ArrayStorageType]:
99+
class BackedSparseMatrix[ArrayT: _ArrayStorageType]:
101100
"""\
102101
Mixin class for backed sparse matrices.
103102
@@ -310,7 +309,7 @@ def mean_slice_length(slices) -> int:
310309
)
311310

312311

313-
def _get_group_format(group: GroupStorageType) -> str:
312+
def _get_group_format(group: _GroupStorageType) -> str:
314313
if "h5sparse_format" in group.attrs:
315314
# TODO: Warn about an old format
316315
# If this is only just going to be public, I could insist it's not like this
@@ -331,7 +330,7 @@ def is_sparse_indexing_overridden(
331330
)
332331

333332

334-
class BaseCompressedSparseDataset[GroupT: GroupStorageType, ArrayT: ArrayStorageType](
333+
class BaseCompressedSparseDataset[GroupT: _GroupStorageType, ArrayT: _ArrayStorageType](
335334
abc._AbstractCSDataset, ABC
336335
):
337336
_group: GroupT
@@ -597,7 +596,7 @@ class _CSCDataset(BaseCompressedSparseDataset, abc.CSCDataset):
597596

598597
@doctest_filterwarnings("ignore", r"Moving element.*uns.*to.*obsp", FutureWarning)
599598
def sparse_dataset(
600-
group: GroupStorageType,
599+
group: _GroupStorageType,
601600
*,
602601
should_cache_indptr: bool = True,
603602
) -> abc.CSRDataset | abc.CSCDataset:
@@ -668,6 +667,6 @@ def sparse_dataset(
668667

669668
@_subset.register(BaseCompressedSparseDataset)
670669
def subset_sparsedataset(
671-
d, subset_idx: tuple[Index1DNorm] | tuple[Index1DNorm, Index1DNorm]
670+
d, subset_idx: tuple[_Index1DNorm] | tuple[_Index1DNorm, _Index1DNorm]
672671
):
673672
return d[subset_idx]

src/anndata/_core/storage.py

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

3-
from typing import TYPE_CHECKING, get_args
3+
from typing import TYPE_CHECKING
44

55
import numpy as np
66
import pandas as pd
@@ -12,6 +12,7 @@
1212
from ..compat import XDataset
1313
from ..utils import (
1414
ensure_df_homogeneous,
15+
get_union_members,
1516
join_english,
1617
raise_value_error_if_multiindex_columns,
1718
warn,
@@ -30,13 +31,13 @@ def coerce_array(
3031
allow_array_like: bool = False,
3132
):
3233
"""Coerce arrays stored in layers/X, and aligned arrays ({obs,var}{m,p})."""
33-
from ..typing import ArrayDataStructureTypes
34+
from ..typing import _ArrayDataStructureTypes
3435

3536
# If value is a scalar and we allow that, return it
3637
if allow_array_like and np.isscalar(value):
3738
return value
3839
# If value is one of the allowed types, return it
39-
array_data_structure_types = get_args(ArrayDataStructureTypes)
40+
array_data_structure_types = get_union_members(_ArrayDataStructureTypes)
4041
if isinstance(value, XDataset):
4142
value = Dataset2D(value)
4243
if isinstance(value, (*array_data_structure_types, Dataset2D)):

0 commit comments

Comments
 (0)