Skip to content

Commit

Permalink
Fix import of issparse (#3047)
Browse files Browse the repository at this point in the history
  • Loading branch information
flying-sheep authored May 10, 2024
1 parent 9714250 commit d2a5368
Show file tree
Hide file tree
Showing 21 changed files with 80 additions and 55 deletions.
2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ def setup(app: Sphinx):
nitpick_ignore = [
# Technical issues
("py:class", "numpy.int64"), # documented as “attribute”
("py:class", "numpy._typing._dtype_like._SupportsDType"),
("py:class", "numpy._typing._dtype_like._DTypeDict"),
# Will probably be documented
("py:class", "scanpy._settings.Verbosity"),
("py:class", "scanpy.neighbors.OnFlySymMatrix"),
Expand Down
10 changes: 5 additions & 5 deletions scanpy/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pathlib import Path

from legacy_api_wrap import legacy_api
from packaging import version
from packaging.version import Version

try:
from functools import cache
Expand Down Expand Up @@ -68,16 +68,16 @@ def __exit__(self, *_excinfo) -> None:


def pkg_metadata(package):
from importlib.metadata import metadata as m
from importlib.metadata import metadata

return m(package)
return metadata(package)


@cache
def pkg_version(package):
from importlib.metadata import version as v
from importlib.metadata import version

return version.parse(v(package))
return Version(version(package))


old_positionals = partial(legacy_api, category=FutureWarning)
12 changes: 7 additions & 5 deletions scanpy/_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from anndata import AnnData
from anndata import __version__ as anndata_version
from numpy.typing import NDArray
from packaging import version
from packaging.version import Version
from scipy import sparse
from sklearn.utils import check_random_state

Expand All @@ -47,6 +47,8 @@
from collections.abc import Mapping
from pathlib import Path

from numpy.typing import DTypeLike


class Empty(Enum):
token = 0
Expand Down Expand Up @@ -102,7 +104,7 @@ def set_igraph_random_state(random_state: int):


def check_versions():
if version.parse(anndata_version) < version.parse("0.6.10"):
if Version(anndata_version) < Version("0.6.10"):
from .. import __version__

raise ImportError(
Expand Down Expand Up @@ -712,7 +714,7 @@ def axis_sum(
X: sparse.spmatrix,
*,
axis: tuple[Literal[0, 1], ...] | Literal[0, 1] | None = None,
dtype: np.typing.DTypeLike | None = None,
dtype: DTypeLike | None = None,
) -> np.matrix: ...


Expand All @@ -721,7 +723,7 @@ def axis_sum(
X: np.ndarray,
*,
axis: tuple[Literal[0, 1], ...] | Literal[0, 1] | None = None,
dtype: np.typing.DTypeLike | None = None,
dtype: DTypeLike | None = None,
) -> np.ndarray:
return np.sum(X, axis=axis, dtype=dtype)

Expand All @@ -731,7 +733,7 @@ def _(
X: DaskArray,
*,
axis: tuple[Literal[0, 1], ...] | Literal[0, 1] | None = None,
dtype: np.typing.DTypeLike | None = None,
dtype: DTypeLike | None = None,
) -> DaskArray:
import dask.array as da

Expand Down
4 changes: 2 additions & 2 deletions scanpy/datasets/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from functools import wraps

import anndata as ad
from packaging import version
from packaging.version import Version

from .._settings import settings

Expand All @@ -26,7 +26,7 @@ def filter_oldformatwarning(f):
@wraps(f)
def wrapper(*args, **kwargs):
with warnings.catch_warnings():
if version.parse(ad.__version__).release >= (0, 8):
if Version(ad.__version__).release >= (0, 8):
warnings.filterwarnings(
"ignore", category=ad.OldFormatWarning, module="anndata"
)
Expand Down
4 changes: 2 additions & 2 deletions scanpy/external/pp/_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from typing import TYPE_CHECKING, Literal

from packaging import version
from packaging.version import Version

from ... import logging as logg
from ..._settings import settings
Expand Down Expand Up @@ -145,7 +145,7 @@ def magic(
"git+git://github.com/KrishnaswamyLab/MAGIC.git#subdirectory=python`"
)
else:
if not version.parse(__version__) >= version.parse(MIN_VERSION):
if Version(__version__) < Version(MIN_VERSION):
raise ImportError(
"scanpy requires magic-impute >= "
f"v{MIN_VERSION} (detected: v{__version__}). "
Expand Down
6 changes: 3 additions & 3 deletions scanpy/external/tl/_pypairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Collection, Mapping
from typing import TYPE_CHECKING, Union

from packaging import version
from packaging.version import Version

from ..._settings import settings
from ...testing._doctests import doctest_needs
Expand Down Expand Up @@ -154,6 +154,6 @@ def _check_import():
except ImportError:
raise ImportError("You need to install the package `pypairs`.")

min_version = version.parse("3.0.9")
if version.parse(pypairs.__version__) < min_version:
min_version = Version("3.0.9")
if Version(pypairs.__version__) < min_version:
raise ImportError(f"Please only use `pypairs` >= {min_version}")
29 changes: 20 additions & 9 deletions scanpy/preprocessing/_pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import anndata as ad
import numpy as np
from anndata import AnnData
from packaging import version
from packaging.version import Version
from scipy.sparse import issparse, spmatrix
from scipy.sparse.linalg import LinearOperator, svds
from sklearn.utils import check_array, check_random_state
Expand All @@ -22,7 +22,7 @@
from ._utils import _get_mean_var

if TYPE_CHECKING:
from numpy.typing import NDArray
from numpy.typing import DTypeLike, NDArray


@_doc_params(
Expand All @@ -39,7 +39,7 @@ def pca(
return_info: bool = False,
mask_var: NDArray[np.bool_] | str | None | Empty = _empty,
use_highly_variable: bool | None = None,
dtype: str = "float32",
dtype: DTypeLike = "float32",
copy: bool = False,
chunked: bool = False,
chunk_size: int | None = None,
Expand Down Expand Up @@ -172,7 +172,7 @@ def pca(
if data_is_AnnData:
adata = data.copy() if copy else data
else:
if pkg_version("anndata") < version.parse("0.8.0rc1"):
if pkg_version("anndata") < Version("0.8.0rc1"):
adata = AnnData(data, dtype=data.dtype)
else:
adata = AnnData(data)
Expand All @@ -195,7 +195,7 @@ def pca(

# See: https://github.com/scverse/scanpy/pull/2816#issuecomment-1932650529
if (
version.parse(ad.__version__) < version.parse("0.9")
Version(ad.__version__) < Version("0.9")
and mask_var is not None
and isinstance(X, np.ndarray)
):
Expand Down Expand Up @@ -305,7 +305,8 @@ def pca(
)
X_pca = pca_.fit_transform(X)
else:
raise Exception("This shouldn't happen. Please open a bug report.")
msg = "This shouldn’t happen. Please open a bug report."
raise AssertionError(msg)

if X_pca.dtype.descr != np.dtype(dtype).descr:
X_pca = X_pca.astype(dtype)
Expand Down Expand Up @@ -390,7 +391,14 @@ def _handle_mask_var(
return mask_var, _check_mask(adata, mask_var, "var")


def _pca_with_sparse(X, npcs, solver="arpack", mu=None, random_state=None):
def _pca_with_sparse(
X: spmatrix,
n_pcs: int,
*,
solver: str = "arpack",
mu: NDArray[np.floating] | None = None,
random_state: AnyRandom = None,
):
random_state = check_random_state(random_state)
np.random.set_state(random_state.get_state())
random_init = np.random.rand(np.min(X.shape))
Expand Down Expand Up @@ -429,8 +437,11 @@ def rmatmat(x):
rmatmat=rmatmat,
)

u, s, v = svds(XL, solver=solver, k=npcs, v0=random_init)
u, v = svd_flip(u, v)
u, s, v = svds(XL, solver=solver, k=n_pcs, v0=random_init)
# u_based_decision was changed in https://github.com/scikit-learn/scikit-learn/pull/27491
u, v = svd_flip(
u, v, u_based_decision=pkg_version("scikit-learn") < Version("1.5.0rc1")
)
idx = np.argsort(-s)
v = v[idx, :]

Expand Down
8 changes: 3 additions & 5 deletions scanpy/preprocessing/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,19 @@
from .._utils import AnyRandom, _SupportedArray, axis_sum, elem_mul

if TYPE_CHECKING:
from numpy.typing import NDArray
from numpy.typing import DTypeLike, NDArray

from .._compat import DaskArray


@singledispatch
def axis_mean(
X: DaskArray, *, axis: Literal[0, 1], dtype: np.typing.DTypeLike
) -> DaskArray:
def axis_mean(X: DaskArray, *, axis: Literal[0, 1], dtype: DTypeLike) -> DaskArray:
total = axis_sum(X, axis=axis, dtype=dtype)
return total / X.shape[axis]


@axis_mean.register(np.ndarray)
def _(X: np.ndarray, *, axis: Literal[0, 1], dtype: np.typing.DTypeLike) -> np.ndarray:
def _(X: np.ndarray, *, axis: Literal[0, 1], dtype: DTypeLike) -> np.ndarray:
return X.mean(axis=axis, dtype=dtype)


Expand Down
3 changes: 2 additions & 1 deletion scanpy/testing/_pytest/fixtures/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from collections.abc import Callable

from anndata import AnnData
from numpy.typing import DTypeLike


@pytest.fixture(
Expand Down Expand Up @@ -47,7 +48,7 @@ def _prepare_pbmc_testdata(
sparsity_func: Callable[
[np.ndarray | sparse.spmatrix], np.ndarray | sparse.spmatrix
],
dtype: str | np.dtype,
dtype: DTypeLike,
*,
small: bool,
) -> AnnData:
Expand Down
9 changes: 7 additions & 2 deletions scanpy/testing/_pytest/marks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def _next_val(name: str, start: int, count: int, last_values: list[str]) -> str:
return name.replace("_", "-")


class needs(pytest.MarkDecorator, Enum):
class QuietMarkDecorator(pytest.MarkDecorator):
def __init__(self, mark: pytest.Mark) -> None:
super().__init__(mark, _ispytest=True)


class needs(QuietMarkDecorator, Enum):
"""
Pytest skip marker evaluated at module import.
Expand Down Expand Up @@ -57,4 +62,4 @@ def __init__(self, mod: str) -> None:
if self._name_.casefold() != mod.casefold().replace("-", "_"):
reason = f"{reason} (`pip install {mod}`)"
dec = pytest.mark.skipif(not find_spec(self._name_), reason=reason)
super().__init__(dec.mark, _ispytest=True)
super().__init__(dec.mark)
Binary file modified scanpy/tests/_images/binary_pca/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scanpy/tests/_images/binary_pca_old/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions scanpy/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ def check_same_image(
tol: int,
basename: str = "",
) -> None:
__tracebackhide__ = True

def fmt_descr(descr):
return f"{descr} ({basename})" if basename else descr

Expand Down Expand Up @@ -122,6 +124,8 @@ def image_comparer(check_same_image):
from matplotlib import pyplot as plt

def save_and_compare(*path_parts: Path | os.PathLike, tol: int):
__tracebackhide__ = True

base_pth = Path(*path_parts)

if not base_pth.is_dir():
Expand Down
3 changes: 1 addition & 2 deletions scanpy/tests/test_normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from anndata import AnnData
from anndata.tests.helpers import assert_equal
from scipy import sparse
from scipy.sparse import csr_matrix
from sklearn.utils import issparse
from scipy.sparse import csr_matrix, issparse

import scanpy as sc
from scanpy._utils import axis_sum
Expand Down
12 changes: 7 additions & 5 deletions scanpy/tests/test_pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)
from packaging.version import Version
from scipy import sparse
from sklearn.utils import issparse
from scipy.sparse import issparse

import scanpy as sc
from scanpy.testing._helpers import as_dense_dask_array, as_sparse_dask_array
Expand Down Expand Up @@ -231,12 +231,14 @@ def test_pca_sparse():
implicit = sc.pp.pca(pbmc, dtype=np.float64, copy=True)
explicit = sc.pp.pca(pbmc_dense, dtype=np.float64, copy=True)

assert np.allclose(implicit.uns["pca"]["variance"], explicit.uns["pca"]["variance"])
assert np.allclose(
np.testing.assert_allclose(
implicit.uns["pca"]["variance"], explicit.uns["pca"]["variance"]
)
np.testing.assert_allclose(
implicit.uns["pca"]["variance_ratio"], explicit.uns["pca"]["variance_ratio"]
)
assert np.allclose(implicit.obsm["X_pca"], explicit.obsm["X_pca"])
assert np.allclose(implicit.varm["PCs"], explicit.varm["PCs"])
np.testing.assert_allclose(implicit.obsm["X_pca"], explicit.obsm["X_pca"])
np.testing.assert_allclose(implicit.varm["PCs"], explicit.varm["PCs"])


def test_pca_reproducible(array_type):
Expand Down
9 changes: 6 additions & 3 deletions scanpy/tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import seaborn as sns
from anndata import AnnData
from matplotlib.testing.compare import compare_images
from packaging import version
from packaging.version import Version

import scanpy as sc
from scanpy._compat import pkg_version
Expand Down Expand Up @@ -152,7 +152,7 @@ def test_heatmap(image_comparer):


@pytest.mark.skipif(
pkg_version("matplotlib") < version.parse("3.1"),
pkg_version("matplotlib") < Version("3.1"),
reason="https://github.com/mwaskom/seaborn/issues/1953",
)
@pytest.mark.parametrize(
Expand Down Expand Up @@ -1288,7 +1288,10 @@ def test_binary_scatter(image_comparer):
)
sc.pp.pca(data)
sc.pl.pca(data, color="binary")
save_and_compare_images("binary_pca")
if pkg_version("scikit-learn") >= Version("1.5.0rc1"):
save_and_compare_images("binary_pca")
else:
save_and_compare_images("binary_pca_old")


def test_scatter_specify_layer_and_raw():
Expand Down
2 changes: 1 addition & 1 deletion scanpy/tests/test_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from anndata.tests.helpers import asarray, assert_equal
from numpy.testing import assert_allclose
from scipy import sparse as sp
from sklearn.utils import issparse
from scipy.sparse import issparse

import scanpy as sc
from scanpy.testing._helpers import (
Expand Down
Loading

0 comments on commit d2a5368

Please sign in to comment.