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
4 changes: 2 additions & 2 deletions .github/workflows/test-cpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
ENVS_JSON=$(NO_COLOR=1 uvx hatch env show --json | jq -c 'to_entries
| map(
select(.key | startswith("hatch-test"))
| { name: .key, python: .value.python }
| { name: .key, python: .value.python, args: (.value."extra-args" // [] | join(" ")) }
)')
echo "envs=${ENVS_JSON}" | tee $GITHUB_OUTPUT
test:
Expand Down Expand Up @@ -71,7 +71,7 @@ jobs:
run: uvx hatch -v env create ${{ matrix.env.name }}

- name: Run tests
run: uvx hatch run ${{ matrix.env.name }}:run-cov -v --color=yes -n auto --cov --cov-report=xml --junitxml=test-data/test-results.xml -m "${{matrix.io_mark}}"
run: uvx hatch run ${{ matrix.env.name }}:run-cov -v --color=yes -n auto --cov --cov-report=xml --junitxml=test-data/test-results.xml -m "${{ matrix.io_mark }}" ${{ matrix.env.args }}

- name: Upload coverage data
uses: codecov/codecov-action@v5
Expand Down
1 change: 1 addition & 0 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ overrides.matrix.deps.python = [
overrides.matrix.deps.features = [
{ if = [ "stable", "pre" ], value = "test" },
]
overrides.matrix.deps.extra-args = { if = [ "stable", "pre" ], value = [ "--strict-warnings" ] }

[[envs.hatch-test.matrix]]
deps = [ "stable", "pre", "min" ]
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ addopts = [
filterwarnings = [
"ignore::anndata._warnings.OldFormatWarning",
"ignore::anndata._warnings.ExperimentalFeatureWarning",
"ignore:.*first_column_names:FutureWarning:scanpy", # scanpy 1.10.x
]
# When `--strict-warnings` is used, all warnings are treated as errors, except those:
filterwarnings_when_strict = [
Expand All @@ -158,6 +159,8 @@ filterwarnings_when_strict = [
"default:The codec `vlen-utf8:UserWarning",
"default:The dtype `StringDType():UserWarning",
"default:Consolidated metadata is:UserWarning",
"default:.*Structured:zarr.core.dtype.common.UnstableSpecificationWarning",
"default:.*FixedLengthUTF32:zarr.core.dtype.common.UnstableSpecificationWarning",
]
python_files = "test_*.py"
testpaths = [
Expand Down
23 changes: 17 additions & 6 deletions src/anndata/_io/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ def read_csv(
dtype
Numpy data type.
"""
return read_text(filename, delimiter, first_column_names, dtype)
return read_text(
filename, delimiter, first_column_names=first_column_names, dtype=dtype
)


def read_excel(
Expand Down Expand Up @@ -360,18 +362,26 @@ def read_text(
Numpy data type.
"""
if not isinstance(filename, PathLike | str | bytes):
return _read_text(filename, delimiter, first_column_names, dtype)
return _read_text(
filename, delimiter, first_column_names=first_column_names, dtype=dtype
)

filename = Path(filename)
if filename.suffix == ".gz":
with gzip.open(str(filename), mode="rt") as f:
return _read_text(f, delimiter, first_column_names, dtype)
return _read_text(
f, delimiter, first_column_names=first_column_names, dtype=dtype
)
elif filename.suffix == ".bz2":
with bz2.open(str(filename), mode="rt") as f:
return _read_text(f, delimiter, first_column_names, dtype)
return _read_text(
f, delimiter, first_column_names=first_column_names, dtype=dtype
)
else:
with filename.open() as f:
return _read_text(f, delimiter, first_column_names, dtype)
return _read_text(
f, delimiter, first_column_names=first_column_names, dtype=dtype
)


def _iter_lines(file_like: Iterable[str]) -> Generator[str, None, None]:
Expand All @@ -385,7 +395,8 @@ def _iter_lines(file_like: Iterable[str]) -> Generator[str, None, None]:
def _read_text( # noqa: PLR0912, PLR0915
f: Iterator[str],
delimiter: str | None,
first_column_names: bool | None, # noqa: FBT001
*,
first_column_names: bool | None,
dtype: str,
) -> AnnData:
comments = []
Expand Down
3 changes: 1 addition & 2 deletions src/anndata/_io/specs/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,12 +695,11 @@ def write_recarray_zarr(
from anndata.compat import _to_fixed_length_strings

elem = _to_fixed_length_strings(elem)
if isinstance(f, H5Group) or is_zarr_v2():
if is_zarr_v2():
f.create_dataset(k, data=elem, shape=elem.shape, **dataset_kwargs)
else:
dataset_kwargs = dataset_kwargs.copy()
dataset_kwargs = zarr_v3_compressor_compat(dataset_kwargs)
# TODO: zarr’s on-disk format v3 doesn’t support this dtype
f.create_array(k, shape=elem.shape, dtype=elem.dtype, **dataset_kwargs)
f[k][...] = elem

Expand Down
5 changes: 4 additions & 1 deletion tests/test_readwrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,10 @@ def test_scanpy_krumsiek11(tmp_path, diskfmt, roundtrip):
import scanpy as sc

# TODO: this should be fixed in scanpy instead
with pytest.warns(UserWarning, match=r"Observation names are not unique"):
with pytest.warns(UserWarning, match=r"Observation names are not unique"): # noqa: PT031
warnings.filterwarnings(
"ignore", r".*first_column_names.*no longer positional", FutureWarning
)
orig = sc.datasets.krumsiek11()
del orig.uns["highlights"] # Can’t write int keys
# Can’t write "string" dtype: https://github.com/scverse/anndata/issues/679
Expand Down
11 changes: 10 additions & 1 deletion tests/test_structured_arrays.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from __future__ import annotations

import warnings
from itertools import combinations, product
from typing import TYPE_CHECKING

import numpy as np

import anndata as ad
from anndata import AnnData
from anndata.compat import is_zarr_v2
from anndata.tests.helpers import gen_vstr_recarray

if TYPE_CHECKING:
Expand All @@ -27,7 +29,14 @@ def assert_str_contents_equal(A, B):

def test_io(
tmp_path, diskfmt: Literal["zarr", "h5ad"], diskfmt2: Literal["zarr", "h5ad"]
):
) -> None:
if not is_zarr_v2():
from zarr.core.dtype.common import UnstableSpecificationWarning

warnings.filterwarnings( # raised by “S10” dtype in the recarray below
"default", r".*NullTerminatedBytes", UnstableSpecificationWarning
)

read1 = lambda pth: getattr(ad, f"read_{diskfmt}")(pth)
write1 = lambda adata, pth: getattr(adata, f"write_{diskfmt}")(pth)
read2 = lambda pth: getattr(ad, f"read_{diskfmt2}")(pth)
Expand Down
Loading