diff --git a/pyproject.toml b/pyproject.toml index ab8d499..6fc7791 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,6 +134,12 @@ lint.pydocstyle.convention = "numpy" addopts = [ "--import-mode=importlib", # allow using test files with same name ] +filterwarnings = [ + "error", + "ignore:Writing zarr v2 data will no longer be the default", + "ignore:Only some AnnData objects have `.raw` attribute", + "ignore::scipy.sparse.SparseEfficiencyWarning", +] strict = true testpaths = [ "tests" ] diff --git a/src/mudata/_core/mudata.py b/src/mudata/_core/mudata.py index f34b9e8..5577902 100644 --- a/src/mudata/_core/mudata.py +++ b/src/mudata/_core/mudata.py @@ -1405,7 +1405,7 @@ def _pull_attr( # prepend modality prefix to column names if requested via arguments and there are no skipped modalities with # the same column name (prefixing those columns may cause problems with future pulls or pushes) - mod_df.rename( + mod_df = mod_df.rename( columns={ col.derived_name: col.name for col in modcols @@ -1420,8 +1420,7 @@ def _pull_attr( ) and derived_name_count[col.derived_name] == col.count ) - }, - inplace=True, + } ) # reorder modality DF to conform to global order diff --git a/tests/test_accessors.py b/tests/test_accessors.py index a70d740..6d3620e 100644 --- a/tests/test_accessors.py +++ b/tests/test_accessors.py @@ -1,6 +1,6 @@ import json from dataclasses import fields -from importlib import resources +from importlib import metadata, resources from urllib.request import urlopen import anndata as ad @@ -13,7 +13,7 @@ import mudata as md -if Version(ad.__version__) < Version("0.13dev0"): +if Version(metadata.version("anndata")) < Version("0.13dev0"): pytest.skip("anndata version too old, no accessor support", allow_module_level=True) from mudata.acc import A diff --git a/tests/test_from_to.py b/tests/test_from_to.py index 514caf5..c0beefc 100644 --- a/tests/test_from_to.py +++ b/tests/test_from_to.py @@ -25,6 +25,6 @@ def test_from_anndata(rng: np.random.Generator): adata.var["feature_types"] = rng.choice(["mod1", "mod2", "mod3"], size=adata.n_vars) mdata = MuData(adata) assert mdata.n_mod == 3 - assert sorted(mdata.mod_names) == ["mod1", "mod2", "mod3"] + assert sorted(mdata.mod.keys()) == ["mod1", "mod2", "mod3"] for m, mod in mdata.mod.items(): assert (mod.var_names == adata.var_names[adata.var.feature_types == m]).all() diff --git a/tests/test_io.py b/tests/test_io.py index 2c22ddc..78bd6d0 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -108,7 +108,7 @@ def test_h5mu_backed_to_memory(mdata: md.MuData, filepath_h5mu: str | Path): mdata_.filename = None assert not mdata_.isbacked - for modname in mdata.mod_names: + for modname in mdata.mod: assert isinstance(mdata_.mod[modname].X, np.ndarray) or issparse(mdata_.mod[modname].X) assert (mdata_.mod[modname].X == mdata.mod[modname].X).all() diff --git a/tests/test_merge.py b/tests/test_merge.py index 92893e5..828af1b 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -14,7 +14,7 @@ def test_merge(mdata_nouniqueobs: md.MuData, filepath_h5mu: str | Path, roundtri mdata_.write_h5mu(filepath_h5mu) mdata_ = md.read_h5mu(filepath_h5mu) assert list(mdata_.mod.keys()) == ["mod1", "mod2"] - for m in mdata_.mod_names: + for m in mdata_.mod: assert mdata_.mod[m].shape == mdata_nouniqueobs.mod[m].shape assert np.array_equal(mdata_.mod["mod1"].X, mdata_nouniqueobs.mod["mod1"].X) assert np.array_equal(mdata_.mod["mod2"].X, mdata_nouniqueobs.mod["mod2"].X) diff --git a/tests/test_obs_var.py b/tests/test_obs_var.py index 3057c50..0e6dddf 100644 --- a/tests/test_obs_var.py +++ b/tests/test_obs_var.py @@ -42,6 +42,7 @@ def test_set_obs_names(mdata: md.MuData): # https://github.com/scverse/mudata/i mdata.obs = pd.DataFrame() +@pytest.mark.filterwarnings("ignore:.*obs_vector.*deprecated:FutureWarning") def test_obs_vector(mdata: md.MuData): assert (mdata.obs["arange"] == mdata.obs_vector("arange")).all() with pytest.raises(KeyError, match="There is no key foo in MuData"): @@ -97,6 +98,7 @@ def test_set_var_names(mdata: md.MuData): # https://github.com/scverse/mudata/i mdata.var = pd.DataFrame() +@pytest.mark.filterwarnings("ignore:.*var_vector.*deprecated:FutureWarning") def test_var_vector(rng: np.random.Generator, mdata: md.MuData): mdata.var["test"] = rng.uniform(size=mdata.n_vars) assert (mdata.var["test"] == mdata.var_vector("test")).all() @@ -117,7 +119,7 @@ def test_names_make_unique(mdata: md.MuData): namesattr = f"{oattr}_names" namesfun = getattr(mdata, f"{oattr}_names_make_unique") - mods = mdata.mod_names + mods = list(mdata.mod.keys()) names = getattr(mdata.mod[mods[0]], namesattr) nameslist = names.to_list() nameslist[1] = nameslist[0] diff --git a/tests/test_pull_push.py b/tests/test_pull_push.py index 25a19bd..d0c2abe 100644 --- a/tests/test_pull_push.py +++ b/tests/test_pull_push.py @@ -47,6 +47,8 @@ def mdata( i1 = i + 1 m = f"mod{i1}" mods[m] = AnnData(X=rng.normal(size=1000 * i1).reshape(-1, 10 * i1)) + mods[m].obs_names = f"{m}-" + mods[m].obs_names + mods[m].var_names = f"{m}-" + mods[m].var_names mods[m].obs["mod"] = m mods[m].var["mod"] = m mods[m].obs["assert-bool"] = True diff --git a/tests/test_repr.py b/tests/test_repr.py index 633f15b..277ec24 100644 --- a/tests/test_repr.py +++ b/tests/test_repr.py @@ -12,10 +12,10 @@ def test_repr(mdata: md.MuData): assert rep[1].lstrip().startswith("obs:") for col in mdata.obs.columns: - if not any(col.startswith(f"{mod}:") for mod in mdata.mod_names): + if not any(col.startswith(f"{mod}:") for mod in mdata.mod): assert col in rep[1] for col in mdata.var.columns: - if not any(col.startswith(f"{mod}:") for mod in mdata.mod_names): + if not any(col.startswith(f"{mod}:") for mod in mdata.mod): assert col in rep[2] assert rep[2].strip() == f"{mdata.n_mod} modalities" diff --git a/tests/test_update.py b/tests/test_update.py index 318ff49..8f0a876 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -13,6 +13,12 @@ type Axis = Literal[0, 1] +pytestmark = [ + pytest.mark.filterwarnings(r"ignore:(obs|var)_names.*not unique"), + pytest.mark.filterwarnings(r"ignore:Duplicated (obs|var)_names should not be present in different modalities"), +] + + @pytest.fixture(params=(0, 1)) def axis(request: pytest.FixtureRequest) -> Axis: return request.param @@ -60,30 +66,29 @@ def modalities( if across != "intersecting": raise NotImplementedError("Tests for non-intersecting obs_names are not implemented") - if mod: - if mod == "duplicated": - obsnames2 = mods["mod2"].obs_names.to_numpy() - obsnames3 = mods["mod3"].obs_names.to_numpy() - varnames2 = mods["mod2"].var_names.to_numpy() - varnames3 = mods["mod3"].var_names.to_numpy() - obsnames2[0] = obsnames2[1] = obsnames3[1] = "testobs" - varnames2[0] = varnames2[1] = varnames3[1] = "testvar" - mods["mod2"].obs_names = obsnames2 - mods["mod3"].obs_names = obsnames3 - mods["mod2"].var_names = varnames2 - mods["mod3"].var_names = varnames3 - elif mod == "extreme_duplicated": # integer overflow: https://github.com/scverse/mudata/issues/107 - obsnames2 = mods["mod2"].obs_names.to_numpy() - varnames2 = mods["mod2"].var_names.to_numpy() - obsnames2[:-1] = obsnames2[0] = "testobs" - varnames2[:-1] = varnames2[0] = "testvar" - mods["mod2"].obs_names = obsnames2 - mods["mod2"].var_names = varnames2 + if mod == "duplicated": + obsnames2 = mods["mod2"].obs_names.to_numpy() + obsnames3 = mods["mod3"].obs_names.to_numpy() + varnames2 = mods["mod2"].var_names.to_numpy() + varnames3 = mods["mod3"].var_names.to_numpy() + obsnames2[0] = obsnames2[1] = obsnames3[1] = "testobs" + varnames2[0] = varnames2[1] = varnames3[1] = "testvar" + mods["mod2"].obs_names = obsnames2 + mods["mod3"].obs_names = obsnames3 + mods["mod2"].var_names = varnames2 + mods["mod3"].var_names = varnames3 + elif mod == "extreme_duplicated": # integer overflow: https://github.com/scverse/mudata/issues/107 + obsnames2 = mods["mod2"].obs_names.to_numpy() + varnames2 = mods["mod2"].var_names.to_numpy() + obsnames2[:-1] = obsnames2[0] = "testobs" + varnames2[:-1] = varnames2[0] = "testvar" + mods["mod2"].obs_names = obsnames2 + mods["mod2"].var_names = varnames2 return mods -def add_mdata_global_columns(md: MuData, rng: np.random.Generator): +def add_mdata_global_columns(md: MuData, rng: np.random.Generator) -> MuData: md.obs["batch"] = rng.choice(["a", "b", "c"], size=md.shape[0]) md.var["batch"] = rng.choice(["d", "e", "f"], size=md.shape[1]) @@ -130,7 +135,7 @@ def assert_dtypes(df: pd.DataFrame): assert pd.api.types.is_integer_dtype(df["dtype-int"]) assert pd.api.types.is_float_dtype(df["dtype-float"]) assert pd.api.types.is_bool_dtype(df["dtype-bool"]) - assert pd.api.types.is_categorical_dtype(df["dtype-categorical"]) + assert isinstance(df["dtype-categorical"].array, pd.Categorical) assert pd.api.types.is_string_dtype(df["batch"]) or df["batch"].dtype == object diff --git a/tests/test_view_copy.py b/tests/test_view_copy.py index 8f17b0f..ebd7c38 100644 --- a/tests/test_view_copy.py +++ b/tests/test_view_copy.py @@ -203,6 +203,7 @@ def _test_view_after_setattr(mdata: md.MuData, mdata_ref: md.MuData, skip: Seque assert (v.columns == mdata_ref.varm[k].columns).all() +@pytest.mark.filterwarnings("ignore::anndata.ImplicitModificationWarning") def test_view_setattr(mdata_with_obsp: md.MuData): view = mdata_with_obsp[:42, :] view.obs_names = [f"foo_{i}" for i in range(len(view))]