diff --git a/docs/conf.py b/docs/conf.py index 61fc0f7..e3f1e25 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,6 +28,9 @@ "sphinx.ext.intersphinx", "sphinx.ext.autodoc", "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx_autodoc_typehints", + "scanpydoc.definition_list_typed_field", "scanpydoc.elegant_typehints", "sphinx_autofixture", ] @@ -45,8 +48,16 @@ } napoleon_google_docstring = False napoleon_numpy_docstring = True +napoleon_use_param = True todo_include_todos = False + +typehints_defaults = "braces" + +pygments_style = "default" +pygments_dark_style = "native" + intersphinx_mapping = dict( + anndata=("https://anndata.readthedocs.io/en/stable/", None), cupy=("https://docs.cupy.dev/en/stable/", None), dask=("https://docs.dask.org/en/stable/", None), h5py=("https://docs.h5py.org/en/stable/", None), @@ -56,46 +67,46 @@ zarr=("https://zarr.readthedocs.io/en/stable/", None), ) # Try overriding type paths -qualname_overrides = autodoc_type_aliases = { - "np.bool": ("py:data", "numpy.bool"), - "np.dtype": "numpy.dtype", - "np.number": "numpy.number", - "np.integer": "numpy.integer", - "np.floating": "numpy.floating", - "np.random.Generator": "numpy.random.Generator", - "ArrayLike": "numpy.typing.ArrayLike", - "DTypeLike": "numpy.typing.DTypeLike", - "NDArray": "numpy.typing.NDArray", - "_pytest.fixtures.FixtureRequest": "pytest.FixtureRequest", - **{ - k: v - for k_plain, v in { - "CSBase": "scipy.sparse.spmatrix", - "CupyArray": "cupy.ndarray", - "CupySparseMatrix": "cupyx.scipy.sparse.spmatrix", - "DaskArray": "dask.array.Array", - "H5Dataset": "h5py.Dataset", - "ZarrArray": "zarr.Array", - }.items() - for k in (k_plain, f"types.{k_plain}") - }, -} +# qualname_overrides = autodoc_type_aliases = { +# "np.bool": ("py:data", "numpy.bool"), +# "np.dtype": "numpy.dtype", +# "np.number": "numpy.number", +# "np.integer": "numpy.integer", +# "np.floating": "numpy.floating", +# "np.random.Generator": "numpy.random.Generator", +# "ArrayLike": "numpy.typing.ArrayLike", +# "DTypeLike": "numpy.typing.DTypeLike", +# "NDArray": "numpy.typing.NDArray", +# "_pytest.fixtures.FixtureRequest": "pytest.FixtureRequest", +# **{ +# k: v +# for k_plain, v in { +# "CSBase": "scipy.sparse.spmatrix", +# "CupyArray": "cupy.ndarray", +# "CupySparseMatrix": "cupyx.scipy.sparse.spmatrix", +# "DaskArray": "dask.array.Array", +# "H5Dataset": "h5py.Dataset", +# "ZarrArray": "zarr.Array", +# }.items() +# for k in (k_plain, f"types.{k_plain}") +# }, +# } # If that doesn’t work, ignore them -nitpick_ignore = { - ("py:class", "fast_array_utils.types.T_co"), - ("py:class", "Arr"), - ("py:class", "testing.fast_array_utils._array_type.Arr"), - ("py:class", "testing.fast_array_utils._array_type.Inner"), - ("py:class", "_DTypeLikeFloat32"), - ("py:class", "_DTypeLikeFloat64"), - # sphinx bugs, should be covered by `autodoc_type_aliases` above - ("py:class", "Array"), - ("py:class", "ArrayLike"), - ("py:class", "DTypeLike"), - ("py:class", "NDArray"), - ("py:class", "np.bool"), - ("py:class", "_pytest.fixtures.FixtureRequest"), -} +# nitpick_ignore = { +# ("py:class", "fast_array_utils.types.T_co"), +# ("py:class", "Arr"), +# ("py:class", "testing.fast_array_utils._array_type.Arr"), +# ("py:class", "testing.fast_array_utils._array_type.Inner"), +# ("py:class", "_DTypeLikeFloat32"), +# ("py:class", "_DTypeLikeFloat64"), +# sphinx bugs, should be covered by `autodoc_type_aliases` above +# ("py:class", "Array"), +# ("py:class", "ArrayLike"), +# ("py:class", "DTypeLike"), +# ("py:class", "NDArray"), +# ("py:class", "np.bool"), +# ("py:class", "_pytest.fixtures.FixtureRequest"), +# } # Options for HTML output html_theme = "furo" diff --git a/src/fast_array_utils/stats/_is_constant.py b/src/fast_array_utils/stats/_is_constant.py index 86ee6b4..ab4a676 100644 --- a/src/fast_array_utils/stats/_is_constant.py +++ b/src/fast_array_utils/stats/_is_constant.py @@ -32,12 +32,12 @@ def is_constant( ) -> bool | NDArray[np.bool] | types.DaskArray: """Check whether values in array are constant. - Params - ------ + Parameters + ---------- a Array to check axis - Axis to reduce over. + Axis along which to reduce. Returns ------- diff --git a/src/fast_array_utils/stats/_mean.py b/src/fast_array_utils/stats/_mean.py index a31eb6b..dea611f 100644 --- a/src/fast_array_utils/stats/_mean.py +++ b/src/fast_array_utils/stats/_mean.py @@ -52,6 +52,15 @@ def mean( ) -> NDArray[np.number[Any]] | np.number[Any] | types.DaskArray: """Mean over both or one axis. + Parameters + ---------- + x + Input array. + axis + Axis along which to reduce. + dtype + Type to cast the result to. + Returns ------- If ``axis`` is :data:`None`, then the sum over all elements is returned as a scalar. diff --git a/src/fast_array_utils/stats/_mean_var.py b/src/fast_array_utils/stats/_mean_var.py index e1d65fa..1a7bb44 100644 --- a/src/fast_array_utils/stats/_mean_var.py +++ b/src/fast_array_utils/stats/_mean_var.py @@ -48,13 +48,25 @@ def mean_var( | tuple[np.float64, np.float64] | tuple[types.DaskArray, types.DaskArray] ): + """Calculate mean and variance of an array. + + Parameters + ---------- + x + Input array. + axis + Axis along which to reduce. + correction + Degrees of freedom correction. + The R convention is to set this to 1 (unbiased estimator). + """ if axis is not None and isinstance(x, types.CSBase): mean_, var = _sparse_mean_var(x, axis=axis) else: mean_ = mean(x, axis=axis, dtype=np.float64) mean_sq = mean(power(x, 2), axis=axis, dtype=np.float64) var = mean_sq - mean_**2 - if correction: # R convention == 1 (unbiased estimator) + if correction: n = np.prod(x.shape) if axis is None else x.shape[axis] if n != 1: var *= n / (n - correction) diff --git a/src/fast_array_utils/stats/_sum.py b/src/fast_array_utils/stats/_sum.py index 76cea5a..0fa7bb1 100644 --- a/src/fast_array_utils/stats/_sum.py +++ b/src/fast_array_utils/stats/_sum.py @@ -50,6 +50,15 @@ def sum( ) -> NDArray[Any] | np.number[Any] | types.DaskArray: """Sum over both or one axis. + Parameters + ---------- + x + Array to sum. + axis + Axis along which to reduce. + dtype + Type to cast the result to. + Returns ------- If ``axis`` is :data:`None`, then the sum over all elements is returned as a scalar. diff --git a/src/fast_array_utils/types.py b/src/fast_array_utils/types.py index 23e3385..aa8797b 100644 --- a/src/fast_array_utils/types.py +++ b/src/fast_array_utils/types.py @@ -13,7 +13,9 @@ "CupySparseMatrix", "DaskArray", "H5Dataset", + "H5Group", "ZarrArray", + "ZarrGroup", ] T_co = TypeVar("T_co", covariant=True) @@ -22,23 +24,22 @@ # scipy sparse if TYPE_CHECKING: from scipy.sparse import csc_array, csc_matrix, csr_array, csr_matrix - - CSArray = csr_array | csc_array - CSMatrix = csr_matrix | csc_matrix else: try: # cs?_array isn’t available in older scipy versions from scipy.sparse import csc_array, csr_array - - CSArray = csr_array | csc_array except ImportError: # pragma: no cover - CSArray = type("CSArray", (), {}) + csc_array = type("csc_array", (), {}) + csr_array = type("csr_array", (), {}) + csc_array.__module__ = csr_array.__module__ = "scipy.sparse" try: # cs?_matrix is available when scipy is installed from scipy.sparse import csc_matrix, csr_matrix - - CSMatrix = csr_matrix | csc_matrix except ImportError: # pragma: no cover - CSMatrix = type("CSMatrix", (), {}) + csc_matrix = type("csc_matrix", (), {}) + csr_matrix = type("csr_matrix", (), {}) + csc_matrix.__module__ = csr_matrix.__module__ = "scipy.sparse" +CSMatrix = csc_matrix | csr_matrix +CSArray = csc_array | csr_array CSBase = CSMatrix | CSArray @@ -46,20 +47,21 @@ from cupy import ndarray as CupyArray else: # pragma: no cover CupyArray = type("ndarray", (), {}) + CupyArray.__module__ = "cupy" if TYPE_CHECKING or find_spec("cupyx"): from cupyx.scipy.sparse import spmatrix as CupySparseMatrix else: # pragma: no cover CupySparseMatrix = type("spmatrix", (), {}) + CupySparseMatrix.__module__ = "cupyx.scipy.sparse" -if TYPE_CHECKING: # https://github.com/dask/dask/issues/8853 - from dask.array.core import Array as DaskArray -elif find_spec("dask"): +if TYPE_CHECKING or find_spec("dask"): from dask.array import Array as DaskArray else: # pragma: no cover - DaskArray = type("array", (), {}) + DaskArray = type("Array", (), {}) + DaskArray.__module__ = "dask.array" if TYPE_CHECKING or find_spec("h5py"): @@ -68,6 +70,7 @@ else: # pragma: no cover H5Dataset = type("Dataset", (), {}) H5Group = type("Group", (), {}) + H5Dataset.__module__ = H5Group.__module__ = "h5py" if TYPE_CHECKING or find_spec("zarr"): @@ -76,6 +79,7 @@ else: # pragma: no cover ZarrArray = type("Array", (), {}) ZarrGroup = type("Group", (), {}) + ZarrArray.__module__ = ZarrGroup.__module__ = "zarr" if TYPE_CHECKING or find_spec("anndata"): @@ -83,4 +87,5 @@ else: # pragma: no cover CSRDataset = type("CSRDataset", (), {}) CSCDataset = type("CSCDataset", (), {}) + CSRDataset.__module__ = CSCDataset.__module__ = "anndata.abc" CSDataset = CSRDataset | CSCDataset