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
6 changes: 3 additions & 3 deletions src/spatialdata/_core/spatialdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ def validate_table_in_spatialdata(self, table: AnnData) -> None:
else:
dtype = element.index.dtype
instance_dtype = self.get_instance_key_column(table).dtype
if dtype != instance_dtype and (
pd.api.types.is_string_dtype(dtype) or pd.api.types.is_string_dtype(instance_dtype)
):
# Only a string vs non-string mismatch is an error: string ids may be stored as `object` or
# as a pandas string dtype (the default with pandas>=3) depending on the reader.
if pd.api.types.is_string_dtype(dtype) != pd.api.types.is_string_dtype(instance_dtype):
raise TypeError(
f"Table instance_key column ({instance_key}) has a dtype "
f"({instance_dtype}) that does not match the dtype of the indices of "
Expand Down
23 changes: 22 additions & 1 deletion tests/datasets/test_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

from pathlib import Path

import pandas as pd
import pooch
import pytest

from spatialdata import SpatialData
from spatialdata import SpatialData, read_zarr
from spatialdata.datasets import _cache_dir, _shipped_registry, blobs, cells, raccoon


Expand Down Expand Up @@ -70,3 +71,23 @@ def test_cells_download(tmp_path) -> None:
assert len(sdata.shapes["nucleus_boundaries"]) == 94
assert len(sdata.points["transcripts"].compute()) == 19479
assert sdata.tables["table"].shape == (94, 5101)


@pytest.mark.network
def test_cells_string_instance_key_dtype(tmp_path) -> None:
# Regression: the `cell_boundaries` index is read as the pandas>=3 `str` dtype while the table's `cell_id`
# column is read as `object`; both hold string ids, so annotating by `cell_id` must validate and round-trip.
sdata = cells(path=str(tmp_path / "cache"))
table = sdata.tables["table"]
table.obs["region"] = pd.Categorical(["cell_boundaries"] * table.n_obs)
sdata.set_table_annotates_spatialelement("table", region="cell_boundaries", instance_key="cell_id")
sdata.validate_table_in_spatialdata(table)

sdata.write(tmp_path / "data.zarr")
sdata_read = read_zarr(tmp_path / "data.zarr")
assert sdata_read.tables["table"].uns["spatialdata_attrs"]["instance_key"] == "cell_id"

# a string vs integer mismatch is still an error
sdata.set_table_annotates_spatialelement("table", region="cell_boundaries", instance_key="cell_labels")
with pytest.raises(TypeError, match="does not match the dtype"):
sdata.validate_table_in_spatialdata(table)
Loading