diff --git a/anndata/_io/h5ad.py b/anndata/_io/h5ad.py index bfddc6504..337f13f92 100644 --- a/anndata/_io/h5ad.py +++ b/anndata/_io/h5ad.py @@ -29,6 +29,7 @@ ) from ..experimental import read_dispatched from .specs import read_elem, write_elem +from .specs.registry import IOSpec, write_spec from .utils import ( H5PY_V3, _read_legacy_raw, @@ -110,6 +111,7 @@ def write_h5ad( @report_write_key_on_error +@write_spec(IOSpec("array", "0.2.0")) def write_sparse_as_dense(f, key, value, dataset_kwargs=MappingProxyType({})): real_key = None # Flag for if temporary key was used if key in f: diff --git a/anndata/_io/utils.py b/anndata/_io/utils.py index e6bccde01..964f94811 100644 --- a/anndata/_io/utils.py +++ b/anndata/_io/utils.py @@ -165,24 +165,22 @@ def _get_parent(elem): return parent -def re_raise_error(e, elem, key, op=Literal["read", "writ"]): +def add_key_note(e: BaseException, elem, key, op=Literal["read", "writ"]) -> None: if any( f"Error raised while {op}ing key" in note for note in getattr(e, "__notes__", []) ): - raise - else: - parent = _get_parent(elem) - add_note( - e, - f"Error raised while {op}ing key {key!r} of {type(elem)} to " f"{parent}", - ) - raise e + return + parent = _get_parent(elem) + add_note( + e, + f"Error raised while {op}ing key {key!r} of {type(elem)} to " f"{parent}", + ) def report_read_key_on_error(func): """\ - A decorator for zarr element reading which makes keys involved in errors get reported. + A decorator for hdf5/zarr element reading which makes keys involved in errors get reported. Example ------- @@ -206,14 +204,15 @@ def func_wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: - re_raise_error(e, elem, elem.name, "read") + add_key_note(e, elem, elem.name, "read") + raise return func_wrapper def report_write_key_on_error(func): """\ - A decorator for zarr element reading which makes keys involved in errors get reported. + A decorator for hdf5/zarr element writing which makes keys involved in errors get reported. Example ------- @@ -239,7 +238,8 @@ def func_wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: - re_raise_error(e, elem, key, "writ") + add_key_note(e, elem, key, "writ") + raise return func_wrapper diff --git a/anndata/tests/test_hdf5_backing.py b/anndata/tests/test_hdf5_backing.py index 61c0c905c..03e65d7b4 100644 --- a/anndata/tests/test_hdf5_backing.py +++ b/anndata/tests/test_hdf5_backing.py @@ -81,6 +81,7 @@ def as_dense(request): # TODO: Check to make sure obs, obsm, layers, ... are written and read correctly as well +@pytest.mark.filterwarnings("error") def test_read_write_X(tmp_path, mtx_format, backed_mode, as_dense): base_pth = Path(tmp_path) orig_pth = base_pth / "orig.h5ad" @@ -89,11 +90,11 @@ def test_read_write_X(tmp_path, mtx_format, backed_mode, as_dense): orig = ad.AnnData(mtx_format(asarray(sparse.random(10, 10, format="csr")))) orig.write(orig_pth) - backed = ad.read(orig_pth, backed=backed_mode) + backed = ad.read_h5ad(orig_pth, backed=backed_mode) backed.write(backed_pth, as_dense=as_dense) backed.file.close() - from_backed = ad.read(backed_pth) + from_backed = ad.read_h5ad(backed_pth) assert np.all(asarray(orig.X) == asarray(from_backed.X)) diff --git a/docs/release-notes/0.10.2.md b/docs/release-notes/0.10.2.md index b9f5d27d0..edd005e0f 100644 --- a/docs/release-notes/0.10.2.md +++ b/docs/release-notes/0.10.2.md @@ -7,6 +7,8 @@ Note that this API is *deprecated* and new code should use {class}`~anndata.experimental.CSRDataset`, {class}`~anndata.experimental.CSCDataset`, and {func}`~anndata.experimental.sparse_dataset` instead. {pr}`1185` {user}`ivirshup` * Handle deprecation warning from `pd.Categorical.map` thrown during `anndata.concat` {pr}`1189` {user}`flying-sheep` {user}`ivirshup` +* Fixed extra steps being included in IO tracebacks {pr}`1193` {user}`flying-sheep` +* `as_dense` argument of `write_h5ad` no longer writes an array without encoding metadata {pr}`1193` {user}`flying-sheep` ```{rubric} Documentation ```