Skip to content

Commit 136c041

Browse files
Backport PR #2399 on branch 0.12.x (fix: disallow transpose for "raw" backed array objects) (#2400)
1 parent 6f6ed3f commit 136c041

3 files changed

Lines changed: 30 additions & 0 deletions

File tree

docs/release-notes/2399.fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Disallow {meth}`anndata.AnnData.transpose` when `X` or `layers` contains {class}`h5py.Dataset`, {class}`zarr.Array` ,{class}`anndata.abc.CSRDataset`, or {class}`anndata.abc.CSCDataset` {user}`ilan-gold`.

src/anndata/_core/anndata.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,12 @@ def transpose(self) -> AnnData:
13111311
"which is currently not implemented. Call `.copy()` before transposing."
13121312
)
13131313
raise ValueError(msg)
1314+
if any(
1315+
isinstance(elem, ZarrArray | BaseCompressedSparseDataset | h5py.Dataset)
1316+
for elem in (self.X, *self.layers.values())
1317+
):
1318+
msg = "Cannot transpose anndata object that has raw zarr arrays or h5py arrays backing X or layers"
1319+
raise ValueError(msg)
13141320

13151321
return AnnData(
13161322
X=_safe_transpose(X) if X is not None else None,

tests/test_base.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@
66
from itertools import product
77
from typing import TYPE_CHECKING
88

9+
import h5py
910
import numpy as np
1011
import pandas as pd
1112
import pytest
13+
import zarr
1214
from numpy import ma
1315
from scipy import sparse as sp
1416
from scipy.sparse import csr_matrix, issparse
1517

1618
import anndata as ad
1719
from anndata import AnnData, ImplicitModificationWarning
1820
from anndata._core.raw import Raw
21+
from anndata._core.sparse_dataset import sparse_dataset
1922
from anndata._settings import settings
2023
from anndata.tests.helpers import (
2124
GEN_ADATA_NO_XARRAY_ARGS,
@@ -768,3 +771,23 @@ def test_create_adata_from_single_axis_elem(
768771
in_memory.write_h5ad(tmp_path / "adata.h5ad")
769772
from_disk = ad.read_h5ad(tmp_path / "adata.h5ad")
770773
assert_equal(from_disk, in_memory)
774+
775+
776+
@pytest.mark.parametrize("in_x", [True, False], ids=["X", "layers"])
777+
@pytest.mark.parametrize("is_sparse", [True, False], ids=["sparse", "dense"])
778+
@pytest.mark.parametrize("storage", ["h5ad", "zarr"])
779+
def test_transpose_errors_with_backed_arrays(
780+
tmp_path: Path, storage: str, *, is_sparse: bool, in_x: bool
781+
):
782+
adata = AnnData(X=csr_matrix(np.ones((3, 4))) if is_sparse else np.ones((3, 4)))
783+
path = tmp_path / f"test.{storage}"
784+
getattr(adata, f"write_{storage}")(path)
785+
f = (h5py.File if storage == "h5ad" else zarr.open)(path)
786+
raw_array = sparse_dataset(f["X"]) if is_sparse else f["X"]
787+
788+
adata = AnnData(**({"X": raw_array} if in_x else {"layers": {"test": raw_array}}))
789+
790+
with pytest.raises(ValueError, match=r"Cannot transpose anndata object"):
791+
adata.transpose()
792+
if storage == "h5ad":
793+
f.close()

0 commit comments

Comments
 (0)