Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
cache: 'pip'

- name: Cache datasets
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
~/.cache
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
with: { enable-cache: false }
- id: get-envs
run: |
ENVS_JSON=$(NO_COLOR=1 uvx hatch env show --json | jq -c 'to_entries
ENVS_JSON=$(NO_COLOR=1 uvx '--with=virtualenv<21' hatch env show --json | jq -c 'to_entries
| map(
select(.key | startswith("hatch-test"))
| {
Expand Down Expand Up @@ -55,15 +55,15 @@ jobs:
python-version: ${{ matrix.env.python }}

- name: Cache downloaded data
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: .pytest_cache/d/scanpy-data
key: pytest

- name: Install dependencies
run: |
echo "::group::Install hatch"
uv tool install hatch
uv tool install hatch '--with=virtualenv<21'
echo "::endgroup::"
echo "::group::Create environment"
hatch -v env create ${{ matrix.env.name }}
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ build:
- asdf global uv latest
pre_build:
# run towncrier to preview the next version’s release notes
- ( find docs/release-notes -regex '[^.]+[.][^.]+.md' | grep -q . ) && uvx hatch run towncrier build --keep || true
- ( find docs/release-notes -regex '[^.]+[.][^.]+.md' | grep -q . ) && uvx "--with=virtualenv<21" hatch run towncrier build --keep || true
build:
html:
- uvx hatch run docs:build
- uvx "--with=virtualenv<21" hatch run docs:build
- mv docs/_build $READTHEDOCS_OUTPUT
7 changes: 5 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from datetime import datetime
from functools import partial
from importlib.metadata import version as get_version
from itertools import product
from pathlib import Path, PurePosixPath
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -262,8 +263,10 @@ def setup(app: Sphinx) -> None:
"pandas.core.series.Series": "pandas.Series",
# https://github.com/pandas-dev/pandas/issues/63810
"pandas.api.typing.aliases.AnyArrayLike": ("doc", "pandas:reference/aliases"),
"numpy.bool_": "numpy.bool", # Since numpy 2, numpy.bool is the canonical dtype
"numpy.typing.ArrayLike": ("py:data", "numpy.typing.ArrayLike"),
**{
f"numpy.{prefix}typing.{name}": ("py:data", f"numpy.typing.{name}")
for name, prefix in product(["ArrayLike", "DTypeLike"], ["", "_"])
},
}

nitpick_ignore = [
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ lint.pylint.max-positional-args = 5
"legacy_api_wrap.legacy_api".msg = "Use scanpy._compat.old_positionals instead"
"numba.jit".msg = "Use `scanpy._compat.njit` instead"
"numba.njit".msg = "Use `scanpy._compat.njit` instead"
"numpy.bool".msg = "Use `np.bool_` instead for numpy>=1.24<2 compatibility"
"numpy.bool_".msg = "Use `np.bool` instead"
"pandas.api.types.is_categorical_dtype".msg = "Use isinstance(s.dtype, CategoricalDtype) instead"
"pandas.value_counts".msg = "Use pd.Series(a).value_counts() instead"
"pytest.importorskip".msg = "Use the “@needs” decorator/mark instead"
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ def select_groups(
adata: AnnData,
groups_order_subset: Iterable[str] | Literal["all"] = "all",
key: str = "groups",
) -> tuple[list[str], NDArray[np.bool_]]:
) -> tuple[list[str], NDArray[np.bool]]:
"""Get subset of groups in adata.obs[key]."""
groups_order = adata.obs[key].cat.categories
if f"{key}_masks" in adata.uns:
Expand Down
14 changes: 7 additions & 7 deletions src/scanpy/get/_aggregated.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(
groupby: pd.Categorical,
data: Array,
*,
mask: NDArray[np.bool_] | None = None,
mask: NDArray[np.bool] | None = None,
) -> None:
self.groupby = groupby
if (missing := groupby.isna()).any():
Expand Down Expand Up @@ -188,7 +188,7 @@ def aggregate( # noqa: PLR0912
func: AggType | Iterable[AggType],
*,
axis: Literal["obs", 0, "var", 1] | None = None,
mask: NDArray[np.bool_] | str | None = None,
mask: NDArray[np.bool] | str | None = None,
dof: int = 1,
layer: str | None = None,
obsm: str | None = None,
Expand Down Expand Up @@ -337,7 +337,7 @@ def _aggregate(
by: pd.Categorical,
func: AggType | Iterable[AggType],
*,
mask: NDArray[np.bool_] | None = None,
mask: NDArray[np.bool] | None = None,
dof: int = 1,
) -> dict[AggType, np.ndarray | DaskArray]:
msg = f"Data type {type(data)} not supported for aggregation"
Expand All @@ -353,7 +353,7 @@ def aggregate_dask_mean_var(
data: DaskArray,
by: pd.Categorical,
*,
mask: NDArray[np.bool_] | None = None,
mask: NDArray[np.bool] | None = None,
dof: int = 1,
) -> MeanVarDict:
mean = aggregate_dask(data, by, "mean", mask=mask, dof=dof)["mean"]
Expand All @@ -374,7 +374,7 @@ def aggregate_dask(
by: pd.Categorical,
func: AggType | Iterable[AggType],
*,
mask: NDArray[np.bool_] | None = None,
mask: NDArray[np.bool] | None = None,
dof: int = 1,
) -> dict[AggType, DaskArray]:
if not isinstance(data._meta, CSBase | np.ndarray):
Expand Down Expand Up @@ -465,7 +465,7 @@ def aggregate_array(
by: pd.Categorical,
func: AggType | Iterable[AggType],
*,
mask: NDArray[np.bool_] | None = None,
mask: NDArray[np.bool] | None = None,
dof: int = 1,
) -> dict[AggType, np.ndarray]:
groupby = Aggregate(groupby=by, data=data, mask=mask)
Expand Down Expand Up @@ -549,7 +549,7 @@ def _combine_categories(
def sparse_indicator(
categorical: pd.Categorical,
*,
mask: NDArray[np.bool_] | None = None,
mask: NDArray[np.bool] | None = None,
weight: NDArray[np.floating] | None = None,
) -> sparse.coo_matrix:
if mask is not None and weight is None:
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/get/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ def _set_obs_rep(
raise AssertionError(msg)


def _check_mask[M: NDArray[np.bool_] | NDArray[np.floating] | pd.Series | None](
def _check_mask[M: NDArray[np.bool] | NDArray[np.floating] | pd.Series | None](
data: AnnData | np.ndarray | CSBase | DaskArray,
mask: str | M,
dim: Literal["obs", "var"],
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/metrics/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def _(val: pd.DataFrame | pd.Series) -> NDArray:

def _vals_heterogeneous[V: NDArray | CSRBase](
vals: V,
) -> tuple[V, NDArray[np.bool_] | slice, NDArray[np.float64]]:
) -> tuple[V, NDArray[np.bool] | slice, NDArray[np.float64]]:
"""Check that values wont cause issues in computation.

Returns new set of vals, and indexer to put values back into result.
Expand Down
6 changes: 3 additions & 3 deletions src/scanpy/plotting/_anndata.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,16 @@ def _check_if_annotations(
other_ax_obj, "var" if axis_name == "obs" else "obs"
).index

def is_annotation(needle: pd.Index) -> NDArray[np.bool_]:
def is_annotation(needle: pd.Index) -> NDArray[np.bool]:
return needle.isin({None}) | needle.isin(annotations) | needle.isin(names)

if not is_annotation(pd.Index([x, y])).all():
return False

color_idx = pd.Index(colors if colors is not None else [])
# Colors are valid
color_valid: NDArray[np.bool_] = np.fromiter(
map(is_color_like, color_idx), dtype=np.bool_, count=len(color_idx)
color_valid: NDArray[np.bool] = np.fromiter(
map(is_color_like, color_idx), dtype=np.bool, count=len(color_idx)
)
# Annotation names are valid too
color_valid[~color_valid] = is_annotation(color_idx[~color_valid])
Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/plotting/_tools/scatterplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def embedding( # noqa: PLR0912, PLR0913, PLR0915
basis: str,
*,
color: str | Sequence[str] | None = None,
mask_obs: NDArray[np.bool_] | str | None = None,
mask_obs: NDArray[np.bool] | str | None = None,
gene_symbols: str | None = None,
use_raw: bool | None = None,
sort_order: bool = True,
Expand Down Expand Up @@ -1204,7 +1204,7 @@ def _get_color_source_vector(
adata: AnnData,
value_to_plot: str,
*,
mask_obs: NDArray[np.bool_] | None = None,
mask_obs: NDArray[np.bool] | None = None,
use_raw: bool = False,
gene_symbols: str | None = None,
layer: str | None = None,
Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/preprocessing/_highly_variable_genes.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def in_bounds(
self,
mean: NDArray[np.floating] | DaskArray,
dispersion_norm: NDArray[np.floating] | DaskArray,
) -> NDArray[np.bool_] | DaskArray:
) -> NDArray[np.bool] | DaskArray:
return (
(mean > self.min_mean)
& (mean < self.max_mean)
Expand Down Expand Up @@ -482,7 +482,7 @@ def _subset_genes(
mean: NDArray[np.float64] | DaskArray,
dispersion_norm: NDArray[np.float64] | DaskArray,
cutoff: _Cutoffs | int,
) -> NDArray[np.bool_] | DaskArray:
) -> NDArray[np.bool] | DaskArray:
"""Get boolean mask of genes with normalized dispersion in bounds."""
if isinstance(cutoff, _Cutoffs):
dispersion_norm = np.nan_to_num(dispersion_norm) # similar to Seurat
Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/preprocessing/_pca/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def pca( # noqa: PLR0912, PLR0913, PLR0915
chunk_size: int | None = None,
random_state: _LegacyRandom = 0,
return_info: bool = False,
mask_var: NDArray[np.bool_] | str | None | Empty = _empty,
mask_var: NDArray[np.bool] | str | None | Empty = _empty,
use_highly_variable: bool | None = None,
dtype: DTypeLike = "float32",
key_added: str | None = None,
Expand Down Expand Up @@ -403,7 +403,7 @@ def pca( # noqa: PLR0912, PLR0913, PLR0915

def _handle_mask_var(
adata: AnnData,
mask_var: NDArray[np.bool_] | str | Empty | None,
mask_var: NDArray[np.bool] | str | Empty | None,
*,
obsm: str | None = None,
use_highly_variable: bool | None,
Expand Down
12 changes: 6 additions & 6 deletions src/scanpy/preprocessing/_scale.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def scale[A: _Array](
copy: bool = False,
layer: str | None = None,
obsm: str | None = None,
mask_obs: NDArray[np.bool_] | str | None = None,
mask_obs: NDArray[np.bool] | str | None = None,
) -> AnnData | A | None:
"""Scale data to unit variance and zero mean.

Expand Down Expand Up @@ -148,7 +148,7 @@ def scale_array[A: _Array](
max_value: float | None = None,
copy: bool = False,
return_mean_std: bool = False,
mask_obs: NDArray[np.bool_] | None = None,
mask_obs: NDArray[np.bool] | None = None,
) -> (
A
| tuple[
Expand All @@ -175,7 +175,7 @@ def scale_array[A: _Array](
mask_obs = (
# For CSR matrices, default to a set mask to take the `scale_array_masked` path.
# This is faster than the maskless `axis_mul_or_truediv` path.
np.ones(x.shape[0], dtype=np.bool_)
np.ones(x.shape[0], dtype=np.bool)
if isinstance(x, CSRBase) and mask_obs is None and not zero_center
else _check_mask(x, mask_obs, "obs")
)
Expand Down Expand Up @@ -219,7 +219,7 @@ def scale_array[A: _Array](

def scale_array_masked[A: _Array](
x: A,
mask_obs: NDArray[np.bool_],
mask_obs: NDArray[np.bool],
*,
zero_center: bool = True,
max_value: float | None = None,
Expand Down Expand Up @@ -268,7 +268,7 @@ def scale_and_clip_csr(
data: NDArray[np.floating],
*,
std: NDArray[np.floating],
mask_obs: NDArray[np.bool_],
mask_obs: NDArray[np.bool],
max_value: float | None,
) -> None:
for i in numba.prange(len(indptr) - 1):
Expand All @@ -289,7 +289,7 @@ def scale_anndata(
copy: bool = False,
layer: str | None = None,
obsm: str | None = None,
mask_obs: NDArray[np.bool_] | str | None = None,
mask_obs: NDArray[np.bool] | str | None = None,
) -> AnnData | None:
adata = adata.copy() if copy else adata
str_mean_std = ("mean", "std")
Expand Down
6 changes: 3 additions & 3 deletions src/scanpy/preprocessing/_scrublet/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Scrublet:

# Fields set by methods

predicted_doublets_: NDArray[np.bool_] | None = field(init=False)
predicted_doublets_: NDArray[np.bool] | None = field(init=False)
"""(shape: n_cells)
Boolean mask of predicted doublets in the observed transcriptomes.
"""
Expand Down Expand Up @@ -354,7 +354,7 @@ def _nearest_neighbor_classifier(
if use_approx_neighbors:
neighbors = neighbors[:, 1:]
# Calculate doublet score based on ratio of simulated cell neighbors vs. observed cell neighbors
doub_neigh_mask: NDArray[np.bool_] = (
doub_neigh_mask: NDArray[np.bool] = (
manifold.obs["doub_labels"].to_numpy()[neighbors] == "sim"
)
n_sim_neigh: NDArray[np.int64] = doub_neigh_mask.sum(axis=1)
Expand Down Expand Up @@ -403,7 +403,7 @@ def _nearest_neighbor_classifier(

def call_doublets(
self, *, threshold: float | None = None, verbose: bool = True
) -> NDArray[np.bool_] | None:
) -> NDArray[np.bool] | None:
"""Call trancriptomes as doublets or singlets.

Parameters
Expand Down
10 changes: 5 additions & 5 deletions src/scanpy/preprocessing/_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -853,11 +853,11 @@ def sample(
fraction: float | None = None,
*,
n: int | None = None,
rng: RNGLike | SeedLike | None = 0,
rng: RNGLike | SeedLike | None = None,
copy: Literal[False] = False,
replace: bool = False,
axis: Literal["obs", 0, "var", 1] = "obs",
p: str | NDArray[np.bool_] | NDArray[np.floating] | None = None,
p: str | NDArray[np.bool] | NDArray[np.floating] | None = None,
) -> None: ...
@overload
def sample(
Expand All @@ -869,7 +869,7 @@ def sample(
copy: Literal[True],
replace: bool = False,
axis: Literal["obs", 0, "var", 1] = "obs",
p: str | NDArray[np.bool_] | NDArray[np.floating] | None = None,
p: str | NDArray[np.bool] | NDArray[np.floating] | None = None,
) -> AnnData: ...
@overload
def sample[A: np.ndarray | CSBase | DaskArray](
Expand All @@ -881,7 +881,7 @@ def sample[A: np.ndarray | CSBase | DaskArray](
copy: bool = False,
replace: bool = False,
axis: Literal["obs", 0, "var", 1] = "obs",
p: str | NDArray[np.bool_] | NDArray[np.floating] | None = None,
p: str | NDArray[np.bool] | NDArray[np.floating] | None = None,
) -> tuple[A, NDArray[np.int64]]: ...
def sample( # noqa: PLR0912
data: AnnData | np.ndarray | CSBase | DaskArray,
Expand All @@ -892,7 +892,7 @@ def sample( # noqa: PLR0912
copy: bool = False,
replace: bool = False,
axis: Literal["obs", 0, "var", 1] = "obs",
p: str | NDArray[np.bool_] | NDArray[np.floating] | None = None,
p: str | NDArray[np.bool] | NDArray[np.floating] | None = None,
) -> AnnData | None | tuple[np.ndarray | CSBase | DaskArray, NDArray[np.int64]]:
r"""Sample observations or variables with or without replacement.

Expand Down
8 changes: 4 additions & 4 deletions src/scanpy/tools/_rank_genes_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ def _tiecorrect(rankvals: NDArray[np.number]) -> NDArray[np.float64]:
def _ranks(
x: NDArray[np.number] | CSBase,
/,
mask_obs: NDArray[np.bool_] | None = None,
mask_obs_rest: NDArray[np.bool_] | None = None,
mask_obs: NDArray[np.bool] | None = None,
mask_obs_rest: NDArray[np.bool] | None = None,
) -> Generator[tuple[NDArray[np.float64], int, int], None, None]:
n_genes = x.shape[1]

Expand Down Expand Up @@ -125,7 +125,7 @@ def __init__(
groups: Iterable[str] | Literal["all"],
groupby: str,
*,
mask_var: NDArray[np.bool_] | None = None,
mask_var: NDArray[np.bool] | None = None,
reference: Literal["rest"] | str = "rest",
use_raw: bool = True,
layer: str | None = None,
Expand Down Expand Up @@ -507,7 +507,7 @@ def rank_genes_groups( # noqa: PLR0912, PLR0913, PLR0915
adata: AnnData,
groupby: str,
*,
mask_var: NDArray[np.bool_] | str | None = None,
mask_var: NDArray[np.bool] | str | None = None,
use_raw: bool | None = None,
groups: Literal["all"] | Iterable[str] = "all",
reference: str = "rest",
Expand Down
Loading
Loading