Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(chore): adopt scientific python deprecation schedule #1768

Merged
merged 44 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f2af154
(chore): migrate to only checking `cs{r,c}_matrix` instead of `spmatrix`
ilan-gold Nov 14, 2024
4f97787
(chore): alter tests as well
ilan-gold Nov 14, 2024
8ea1c4e
(chore): release note
ilan-gold Nov 14, 2024
0253072
(chore): update for scientific python deprecation schedule
ilan-gold Nov 15, 2024
b547a2c
(chore): change name in azure pipeline
ilan-gold Nov 15, 2024
fb686af
(fix): use `https`
ilan-gold Nov 15, 2024
b891b7c
(fix): remove `git@`
ilan-gold Nov 15, 2024
7ab8eee
(chore): remove py3.11 checks
ilan-gold Nov 15, 2024
94c1cdf
(fix): remove scanpy for now
ilan-gold Nov 15, 2024
5d45a79
Merge branch 'main' into ig/scientific_python_deprecation_schedule
ilan-gold Jan 29, 2025
2e53c19
Merge branch 'main' into ig/scientific_python_deprecation_schedule
ilan-gold Jan 29, 2025
51c26a4
(fix): correct h5py version
ilan-gold Jan 29, 2025
7286691
(fix): h5py 3.8
ilan-gold Jan 29, 2025
b77beaa
(fix): respect `pyproject.toml` max versions
ilan-gold Jan 29, 2025
3f18c10
(fix): no `asv` for python 3.13
ilan-gold Jan 29, 2025
c8fedea
(fix): install command
ilan-gold Jan 29, 2025
2e705f8
(fix): path re-route
ilan-gold Jan 29, 2025
23ca307
(fix): remove `add_note`
ilan-gold Jan 29, 2025
f2200ba
(fix): gpu ci
ilan-gold Jan 29, 2025
00e972f
(fix): no `eye_array` in 1.11
ilan-gold Jan 31, 2025
3cd8330
(fix): filter h5py-numpy deprecation
ilan-gold Jan 31, 2025
5768b12
(fix): concatenation bugs
ilan-gold Feb 2, 2025
ee7faa9
(fix): still an issue with matrices!
ilan-gold Feb 2, 2025
60e1149
(fix): minimum version needs to be higher of dask
ilan-gold Feb 3, 2025
06d11e3
(fix): try different constraint
ilan-gold Feb 3, 2025
94d08eb
(chore): remove `CAN_USE_SPARSE_ARRAY`
ilan-gold Feb 3, 2025
296b6c9
(chore): remove duplicated lines
ilan-gold Feb 3, 2025
2740341
(chore): release note
ilan-gold Feb 3, 2025
3f0afae
(fix): bring back skip for array allocation
ilan-gold Feb 3, 2025
3351c43
(fix): PR for relnote
ilan-gold Feb 3, 2025
81f893f
(chore): remove `pandas` 1.X comment
ilan-gold Feb 17, 2025
73f1252
(refactor): `Sp{Matrix,Array}` -> `CS{Matrix,Array}`
ilan-gold Feb 17, 2025
e5d2394
(fix): include `CSArray` in mutable mapping subclasses
ilan-gold Feb 17, 2025
95d18f5
(fix): add back in scalar type for `__setitem__`
ilan-gold Feb 17, 2025
0e914b6
(chore): remove `stdlib` header
ilan-gold Feb 17, 2025
71ca506
(fix): remove `allow-direct-references`
ilan-gold Feb 17, 2025
0250831
(fix): pass through reqs unchanged in `min-deps`
ilan-gold Feb 17, 2025
5b50436
(fix): remove exceptiongroup
ilan-gold Feb 17, 2025
1211e44
Merge branch 'main' into ig/scientific_python_deprecation_schedule
ilan-gold Feb 17, 2025
22ed422
(fix): dask sparse array bound
ilan-gold Feb 17, 2025
29838ed
Merge branch 'ig/scientific_python_deprecation_schedule' of github.co…
ilan-gold Feb 17, 2025
7a42a1f
(chore): add comment about dask bound
ilan-gold Feb 17, 2025
ba154db
(fix): correct minimum dask version
ilan-gold Feb 17, 2025
8b5048e
Merge branch 'main' into ig/scientific_python_deprecation_schedule
ilan-gold Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ jobs:
vmImage: "ubuntu-22.04"
strategy:
matrix:
Python3.12:
python.version: "3.12"
Python3.13:
python.version: "3.13"
RUN_COVERAGE: yes
TEST_TYPE: "coverage"
Python3.10:
python.version: "3.10"
Python3.11:
python.version: "3.11"
PreRelease:
python.version: "3.12"
python.version: "3.13"
DEPENDENCIES_VERSION: "pre-release"
TEST_TYPE: "strict-warning"
minimum_versions:
python.version: "3.10"
python.version: "3.11"
DEPENDENCIES_VERSION: "minimum"
TEST_TYPE: "coverage"
steps:
Expand Down Expand Up @@ -104,8 +104,8 @@ jobs:
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: "3.12"
displayName: "Use Python 3.12"
versionSpec: "3.13"
displayName: "Use Python 3.13"

- script: |
set -e
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test-gpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ jobs:
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.max_python_version }}
# https://github.com/cupy/cupy/issues/8651 cupy does not support python3.13 yet
python-version: "3.12"

- name: Install UV
uses: hynek/setup-cached-uv@v2
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
build:
os: ubuntu-20.04
tools:
python: "3.12"
python: "3.13"
jobs:
post_checkout:
# unshallow so version can be derived from tag
Expand Down
12 changes: 5 additions & 7 deletions ci/scripts/min-deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@

import argparse
import sys
import tomllib
from collections import deque
from contextlib import ExitStack
from functools import cached_property
from pathlib import Path
from typing import TYPE_CHECKING

if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib

from packaging.requirements import Requirement
from packaging.version import Version

Expand All @@ -39,6 +35,8 @@ def min_dep(req: Requirement) -> Requirement:
>>> min_dep(Requirement("numpy>=1.0"))
<Requirement('numpy==1.0.*')>
>>> min_dep(Requirement("numpy<3.0"))
<Requirement('numpy<3.0')>
"""
req_name = req.name
if req.extras:
Expand All @@ -48,8 +46,8 @@ def min_dep(req: Requirement) -> Requirement:
spec for spec in req.specifier if spec.operator in {"==", "~=", ">=", ">"}
]
if not filter_specs:
return Requirement(req_name)

# TODO: handle markers
return Requirement(f"{req_name}{req.specifier}")
min_version = Version("0.0.0.a1")
for spec in filter_specs:
if spec.operator in {">", ">=", "~="}:
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def setup(app: Sphinx):
"pandas.DataFrame.loc": ("py:attr", "pandas.DataFrame.loc"),
# should be fixed soon: https://github.com/tox-dev/sphinx-autodoc-typehints/pull/516
"types.EllipsisType": ("py:data", "types.EllipsisType"),
"pathlib._local.Path": "pathlib.Path",
}
autodoc_type_aliases = dict(
NDArray=":data:`~numpy.typing.NDArray`",
Expand Down
1 change: 1 addition & 0 deletions docs/release-notes/1768.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Tighten usage of {class}`scipy.sparse.spmatrix` for describing sparse matrices in types and instance checks to only {class}`scipy.sparse.csr_matrix` and {class}`scipy.sparse.csc_matrix` {user}`ilan-gold`
1 change: 1 addition & 0 deletions docs/release-notes/1768.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adopt the Scientific Python [deprecation schedule](https://scientific-python.org/specs/spec-0000/) {user}`ilan-gold`
4 changes: 2 additions & 2 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ overrides.matrix.deps.pre-install-commands = [
{ if = ["min"], value = "uv run ci/scripts/min-deps.py pyproject.toml --all-extras -o ci/min-deps.txt" },
]
overrides.matrix.deps.python = [
{ if = ["min"], value = "3.10" },
{ if = ["stable", "pre"], value = "3.12" },
{ if = ["min"], value = "3.11" },
{ if = ["stable", "pre"], value = "3.13" },
]

[[envs.hatch-test.matrix]]
Expand Down
17 changes: 8 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ requires = ["hatchling", "hatch-vcs"]
[project]
name = "anndata"
description = "Annotated data."
requires-python = ">=3.10"
requires-python = ">=3.11"
license = "BSD-3-Clause"
authors = [
{ name = "Philipp Angerer" },
Expand All @@ -29,21 +29,19 @@ classifiers = [
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Bio-Informatics",
"Topic :: Scientific/Engineering :: Visualization",
]
dependencies = [
# pandas <1.4 has pandas/issues/35446
# pandas 2.1.0rc0 has pandas/issues/54622
"pandas >=1.4, !=2.1.0rc0, !=2.1.2",
"numpy>=1.23",
"pandas >=2.0.0, !=2.1.0rc0, !=2.1.2",
"numpy>=1.25",
# https://github.com/scverse/anndata/issues/1434
"scipy >1.8",
"h5py>=3.7",
"exceptiongroup; python_version<'3.11'",
"scipy >1.11",
"h5py>=3.8",
"natsort",
"packaging>=24.2",
# array-api-compat 1.5 has https://github.com/scverse/anndata/issues/1410
Expand Down Expand Up @@ -108,7 +106,8 @@ gpu = ["cupy"]
cu12 = ["cupy-cuda12x"]
cu11 = ["cupy-cuda11x"]
# https://github.com/dask/dask/issues/11290
dask = ["dask[array]>=2022.09.2,!=2024.8.*,!=2024.9.*"]
# https://github.com/dask/dask/issues/11752
dask = ["dask[array]>=2023.5.1,!=2024.8.*,!=2024.9.*,<2025.2.0"]

[tool.hatch.version]
source = "vcs"
Expand Down
9 changes: 1 addition & 8 deletions src/anndata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,17 @@

from __future__ import annotations

import sys
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Any


from ._version import __version__

# Allowing notes to be added to exceptions. See: https://github.com/scverse/anndata/issues/868
if sys.version_info < (3, 11):
# Backport package for exception groups
import exceptiongroup # noqa: F401

from ._core.anndata import AnnData
from ._core.merge import concat
from ._core.raw import Raw
from ._settings import settings
from ._version import __version__
from ._warnings import (
ExperimentalFeatureWarning,
ImplicitModificationWarning,
Expand Down
5 changes: 2 additions & 3 deletions src/anndata/_core/aligned_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@

import numpy as np
import pandas as pd
from scipy.sparse import spmatrix

from .._warnings import ExperimentalFeatureWarning, ImplicitModificationWarning
from ..compat import AwkArray
from ..compat import AwkArray, CSArray, CSMatrix
from ..utils import (
axis_len,
convert_to_dict,
Expand All @@ -36,7 +35,7 @@
OneDIdx = Sequence[int] | Sequence[bool] | slice
TwoDIdx = tuple[OneDIdx, OneDIdx]
# TODO: pd.DataFrame only allowed in AxisArrays?
Value = pd.DataFrame | spmatrix | np.ndarray
Value = pd.DataFrame | CSMatrix | CSArray | np.ndarray

P = TypeVar("P", bound="AlignedMappingBase")
"""Parent mapping an AlignedView is based on."""
Expand Down
14 changes: 7 additions & 7 deletions src/anndata/_core/anndata.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

from .. import utils
from .._settings import settings
from ..compat import DaskArray, SpArray, ZarrArray, _move_adj_mtx, old_positionals
from ..compat import CSArray, DaskArray, ZarrArray, _move_adj_mtx, old_positionals
from ..logging import anndata_logger as logger
from ..utils import (
axis_len,
Expand Down Expand Up @@ -206,14 +206,14 @@ class AnnData(metaclass=utils.DeprecationMixinMeta):
)
def __init__(
self,
X: np.ndarray | sparse.spmatrix | pd.DataFrame | None = None,
X: ArrayDataStructureType | pd.DataFrame | None = None,
obs: pd.DataFrame | Mapping[str, Iterable[Any]] | None = None,
var: pd.DataFrame | Mapping[str, Iterable[Any]] | None = None,
uns: Mapping[str, Any] | None = None,
*,
obsm: np.ndarray | Mapping[str, Sequence[Any]] | None = None,
varm: np.ndarray | Mapping[str, Sequence[Any]] | None = None,
layers: Mapping[str, np.ndarray | sparse.spmatrix] | None = None,
layers: Mapping[str, ArrayDataStructureType] | None = None,
raw: Mapping[str, Any] | None = None,
dtype: np.dtype | type | str | None = None,
shape: tuple[int, int] | None = None,
Expand Down Expand Up @@ -571,7 +571,7 @@ def X(self) -> ArrayDataStructureType | None:
# return X

@X.setter
def X(self, value: np.ndarray | sparse.spmatrix | SpArray | None):
def X(self, value: ArrayDataStructureType | None):
if value is None:
if self.isbacked:
msg = "Cannot currently remove data matrix from backed object."
Expand Down Expand Up @@ -629,7 +629,7 @@ def X(self, value: np.ndarray | sparse.spmatrix | SpArray | None):
if sparse.issparse(self._adata_ref._X) and isinstance(
value, np.ndarray
):
if isinstance(self._adata_ref.X, SpArray):
if isinstance(self._adata_ref.X, CSArray):
memory_class = sparse.coo_array
else:
memory_class = sparse.coo_matrix
Expand Down Expand Up @@ -1173,7 +1173,7 @@ def _inplace_subset_obs(self, index: Index1D):
self._init_as_actual(adata_subset)

# TODO: Update, possibly remove
def __setitem__(self, index: Index, val: float | np.ndarray | sparse.spmatrix):
def __setitem__(self, index: Index, val: float | ArrayDataStructureType):
if self.is_view:
msg = "Object is view and cannot be accessed with `[]`."
raise ValueError(msg)
Expand Down Expand Up @@ -1720,7 +1720,7 @@ def concatenate(
# Backwards compat (some of this could be more efficient)
# obs used to always be an outer join
sparse_class = sparse.csr_matrix
if any(isinstance(a.X, SpArray) for a in all_adatas):
if any(isinstance(a.X, CSArray) for a in all_adatas):
sparse_class = sparse.csr_array
out.obs = concat(
[AnnData(sparse_class(a.shape), obs=a.obs) for a in all_adatas],
Expand Down
14 changes: 7 additions & 7 deletions src/anndata/_core/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import h5py
import numpy as np
import pandas as pd
from scipy.sparse import issparse, spmatrix
from scipy.sparse import issparse

from ..compat import AwkArray, DaskArray, SpArray
from ..compat import AwkArray, CSArray, CSMatrix, DaskArray

if TYPE_CHECKING:
from ..compat import Index, Index1D
Expand Down Expand Up @@ -69,13 +69,13 @@ def name_idx(i):
elif isinstance(indexer, str):
return index.get_loc(indexer) # int
elif isinstance(
indexer, Sequence | np.ndarray | pd.Index | spmatrix | np.matrix | SpArray
indexer, Sequence | np.ndarray | pd.Index | CSMatrix | np.matrix | CSArray
):
if hasattr(indexer, "shape") and (
(indexer.shape == (index.shape[0], 1))
or (indexer.shape == (1, index.shape[0]))
):
if isinstance(indexer, spmatrix | SpArray):
if isinstance(indexer, CSMatrix | CSArray):
indexer = indexer.toarray()
indexer = np.ravel(indexer)
if not isinstance(indexer, np.ndarray | pd.Index):
Expand Down Expand Up @@ -180,9 +180,9 @@ def _subset_dask(a: DaskArray, subset_idx: Index):
return a[subset_idx]


@_subset.register(spmatrix)
@_subset.register(SpArray)
def _subset_sparse(a: spmatrix | SpArray, subset_idx: Index):
@_subset.register(CSMatrix)
@_subset.register(CSArray)
def _subset_sparse(a: CSMatrix | CSArray, subset_idx: Index):
# Correcting for indexing behaviour of sparse.spmatrix
if len(subset_idx) > 1 and all(isinstance(x, Iterable) for x in subset_idx):
first_idx = subset_idx[0]
Expand Down
Loading