Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python] Handle non-list/non-tuple input in tiledbsoma.io registration #3518

Merged
merged 1 commit into from
Jan 7, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@
def from_anndata_appends_on_experiment(
cls,
experiment_uri: str | None,
adatas: Sequence[ad.AnnData],
adatas: Sequence[ad.AnnData] | ad.AnnData,
*,
measurement_name: str,
obs_field_name: str,
Expand All @@ -404,6 +404,13 @@
is ``None`` then you will be computing registrations only for the input
``AnnData`` objects. If ``experiment_uri`` is not ``None`` then it is
an error if the experiment is not accessible."""
# typeguard doesn't help at runtime. Check this crucial user-facing API.
if isinstance(adatas, ad.AnnData):
adatas = [adatas]
elif not isinstance(adatas, (list, tuple)):
raise ValueError(

Check warning on line 411 in apis/python/src/tiledbsoma/io/_registration/ambient_label_mappings.py

View check run for this annotation

Codecov / codecov/patch

apis/python/src/tiledbsoma/io/_registration/ambient_label_mappings.py#L411

Added line #L411 was not covered by tests
f"adatas must be list or tuple of AnnData, or a single AnnData; got {type(adatas)}"
)

registration_data = cls._acquire_experiment_mappings(
experiment_uri,
Expand Down Expand Up @@ -455,7 +462,7 @@
def from_h5ad_appends_on_experiment(
cls,
experiment_uri: str | None,
h5ad_file_names: Sequence[str],
h5ad_file_names: Sequence[str] | str,
*,
measurement_name: str,
obs_field_name: str,
Expand All @@ -465,6 +472,13 @@
) -> Self:
"""Extends registration data from the baseline, already-written SOMA
experiment to include multiple H5AD input files."""
# typeguard doesn't help at runtime. Check this crucial user-facing API.
if isinstance(h5ad_file_names, str):
h5ad_file_names = [h5ad_file_names]
elif not isinstance(h5ad_file_names, (list, tuple)):
raise ValueError(

Check warning on line 479 in apis/python/src/tiledbsoma/io/_registration/ambient_label_mappings.py

View check run for this annotation

Codecov / codecov/patch

apis/python/src/tiledbsoma/io/_registration/ambient_label_mappings.py#L479

Added line #L479 was not covered by tests
f"h5ad_file_names must be list or tuple of string, or a single string; got {type(h5ad_file_names)}"
)

registration_data = cls._acquire_experiment_mappings(
experiment_uri,
Expand Down
4 changes: 2 additions & 2 deletions apis/python/src/tiledbsoma/io/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def __init__(
# entrypoints for append-mode soma_joinid registration.
def register_h5ads(
experiment_uri: str | None,
h5ad_file_names: Sequence[str],
h5ad_file_names: Sequence[str] | str,
*,
measurement_name: str,
obs_field_name: str,
Expand All @@ -212,7 +212,7 @@ def register_h5ads(

def register_anndatas(
experiment_uri: str | None,
adatas: Sequence[ad.AnnData],
adatas: Sequence[ad.AnnData] | ad.AnnData,
*,
measurement_name: str,
obs_field_name: str,
Expand Down
62 changes: 62 additions & 0 deletions apis/python/tests/test_registration_mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1342,3 +1342,65 @@ def test_multimodal_names(tmp_path, conftest_pbmc3k_adata):
assert exp.obs.count == len(adata_protein.obs)
assert exp.ms["RNA"].var.count == len(adata_rna.var)
assert exp.ms["protein"].var.count == len(adata_protein.var)


def test_registration_lists_and_tuples(tmp_path):
obs_field_name = "cell_id"
var_field_name = "gene_id"

exp_uri = create_soma_canned(1, obs_field_name, var_field_name)
adata = create_anndata_canned(2, obs_field_name, var_field_name)
h5ad_file_name = create_h5ad_canned(2, obs_field_name, var_field_name)

rd1 = tiledbsoma.io.register_anndatas(
experiment_uri=exp_uri,
adatas=[adata],
measurement_name="measname",
obs_field_name=obs_field_name,
var_field_name=var_field_name,
)

rd2 = tiledbsoma.io.register_anndatas(
experiment_uri=exp_uri,
adatas=(adata,),
measurement_name="measname",
obs_field_name=obs_field_name,
var_field_name=var_field_name,
)

rd3 = tiledbsoma.io.register_anndatas(
experiment_uri=exp_uri,
adatas=adata,
measurement_name="measname",
obs_field_name=obs_field_name,
var_field_name=var_field_name,
)
assert rd1 == rd2
assert rd2 == rd3

rd4 = tiledbsoma.io.register_h5ads(
experiment_uri=exp_uri,
h5ad_file_names=[h5ad_file_name],
measurement_name="measname",
obs_field_name=obs_field_name,
var_field_name=var_field_name,
)

rd5 = tiledbsoma.io.register_h5ads(
experiment_uri=exp_uri,
h5ad_file_names=(h5ad_file_name,),
measurement_name="measname",
obs_field_name=obs_field_name,
var_field_name=var_field_name,
)

rd6 = tiledbsoma.io.register_h5ads(
experiment_uri=exp_uri,
h5ad_file_names=h5ad_file_name,
measurement_name="measname",
obs_field_name=obs_field_name,
var_field_name=var_field_name,
)

assert rd4 == rd5
assert rd5 == rd6