Skip to content

Commit 5a85a74

Browse files
committed
accessors: make resolving behavior match AnnData's more closely
1 parent e9112a8 commit 5a85a74

2 files changed

Lines changed: 34 additions & 33 deletions

File tree

src/mudata/acc/__init__.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
MultiMapAcc,
2222
RefAcc,
2323
)
24-
from anndata.acc._parse_str import _check_vec
2524
from anndata.compat import XVariable
2625
from anndata.typing import InMemoryArray
2726

@@ -273,30 +272,19 @@ def resolve(
273272

274273
firstdot = spec.find(".")
275274
if firstdot < 0:
276-
firstdot = None
275+
raise ValueError(f"Cannot parse accessor {spec!r} that is not period-separated.")
277276
firstattr = spec[:firstdot]
278277
match firstattr:
279278
case "mod":
280-
do_vec = firstdot is not None
281-
if not do_vec:
282-
_check_vec(spec, vec=vec, actual=do_vec)
283-
return self.mod
284-
285279
modend = spec.find(".", firstdot + 1)
286-
do_vec = modend >= 0
287-
if not do_vec:
288-
modend = None
289-
_check_vec(spec, vec=vec, actual=do_vec)
290280
mod = spec[firstdot + 1 : modend]
291281
if not mod:
292282
raise ValueError(f"Cannot parse accessor{spec!r} that has an empty modality.")
293283
acc = self.mod[mod]
294-
return super().resolve.__func__(acc, spec[modend + 1 :], strict=strict, vec=vec) if do_vec else acc
284+
return super().resolve.__func__(acc, spec[modend + 1 :], strict=strict, vec=vec)
295285
case "obsmap" | "varmap":
296-
do_vec = firstdot is not None and firstdot < len(spec)
297-
_check_vec(spec, vec=vec, actual=do_vec)
298-
if not do_vec:
299-
return getattr(self, firstattr)
286+
if firstdot == len(spec):
287+
raise ValueError(f"Cannot parse accessor{spec!r} that has an empty modality.")
300288
mod = spec[firstdot + 1 :]
301289
return getattr(self, firstattr)[mod]
302290
case _:

tests/test_accessors.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22
from collections.abc import Mapping
3-
from contextlib import nullcontext
43
from dataclasses import fields
54
from importlib import metadata, resources
65
from urllib.request import urlopen
@@ -140,31 +139,45 @@ def test_no_data():
140139
assert field.name not in ("X", "layers")
141140

142141

143-
@pytest.mark.parametrize("vec", [None, True, False])
144-
def test_resolve_vec_true(vec: bool):
145-
with pytest.raises(ValueError, match="refers to a vector/") if vec is False else nullcontext():
146-
assert A.resolve("mod.rna.X[:, ACT1]", vec=vec) == A.mod["rna"].X[:, "ACT1"]
147-
assert A.resolve("obsmap.rna", vec=vec) == A.obsmap["rna"]
142+
def test_resolve():
143+
assert A.resolve("mod.rna.X[:, ACT1]") == A.mod["rna"].X[:, "ACT1"]
144+
assert A.resolve("obsmap.rna") == A.obsmap["rna"]
148145

149-
150-
@pytest.mark.parametrize("vec", [None, True, False])
151-
def test_resolve_vec_false(vec: bool):
152-
with pytest.raises(ValueError, match="refers to a whole container") if vec is True else nullcontext():
153-
assert A.resolve("mod.rna.X", vec=vec) == A.mod["rna"].X
154-
assert A.resolve("mod.rna", vec=vec) == A.mod["rna"]
155-
assert A.resolve("mod", vec=vec) == A.mod
156-
assert A.resolve("obsmap", vec=vec) == A.obsmap
157-
158-
159-
def test_resolve_raises():
160146
with pytest.raises(ValueError, match="Unknown accessor"):
161147
A.resolve("rna.X[:, :]")
148+
162149
with pytest.raises(ValueError, match="empty modality"):
163150
A.resolve("mod..X[:, :]")
151+
164152
with pytest.raises(ValueError, match="period-separated"):
165153
A.resolve("abcd")
166154

167155

156+
@pytest.mark.parametrize("vec", [None, True])
157+
def test_resolve_vec_true(vec):
158+
assert A.resolve("mod.rna.X[:, ACT1]", vec=vec) == A.mod["rna"].X[:, "ACT1"]
159+
assert A.resolve("mod.rna.X[:, :]", vec=vec) == A.mod["rna"].X[:, :]
160+
assert A.resolve("obsm.test.2", vec=vec) == A.obsm["test"][2]
161+
162+
163+
@pytest.mark.parametrize("vec", [None, False])
164+
def test_resolve_vec_false(vec):
165+
assert A.resolve("mod.rna.X", vec=vec) == A.mod["rna"].X
166+
assert A.resolve("obsm.test") == A.obsm["test"]
167+
168+
169+
def test_resolve_vec_mismatch():
170+
with pytest.raises(ValueError, match="refers to a whole container"):
171+
A.resolve("mod.rna.X", vec=True)
172+
A.resolve("mod.rna.X[:, :]", vec=True)
173+
A.resolve("obsm.test", vec=True)
174+
with pytest.raises(ValueError, match="refers to a vector"):
175+
A.resolve("mod.rna.X", vec=False)
176+
A.resolve("mod.rna.X[:, ACT1]", vec=False)
177+
A.resolve("mod.rna.X[:, :]", vec=False)
178+
A.resolve("obsm.test.2", vec=False)
179+
180+
168181
@pytest.mark.parametrize("acc", [path[0] for path in PATHS if isinstance(path[0], ad.acc.AdRef)])
169182
def test_to_from_json(mudata_json_schema, anndata_schema_registry, acc):
170183
serialized = A.to_json(acc)

0 commit comments

Comments
 (0)