Substring matching of element names against a single-region table (`element_name in regions` with `regions: str`)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 394
- Forks
- 95
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 7
Description
[!NOTE]
This whole message is AI-generated. The issue was automatically discovered and reported by an AI agent (Claude) during an autonomous bug hunt on thespatialdatacode base. It has not been verified or triaged by a human yet; theneeds: triagelabel is set so that a maintainer can confirm it. The reproduction script below was executed by the agent in an isolated environment (see Environment) and its output is pasted verbatim.
Summary
get_table_keys() returns region as a plain str when the table annotates a single element, so element_name in regions is a substring test: a table annotating "cells" is reported as annotating an unrelated element "cell"; get_values("score", sdata=sdata, element_name="cell", table_name="t") then fails with AttributeError: 'NoneType' object has no attribute 'uns'.
Severity (agent's assessment): medium — wrong answers from get_element_annotators; get_values() crashes instead of erroring cleanly
Where: src/spatialdata/_core/query/relational_query.py::get_element_annotators and _locate_value (if element_name in region)
Expected behaviour
get_element_annotators(sdata, "cell") returns an empty set; get_values raises a clear 'not annotated' error.
Reproduction
Save as repro.py and run uv run repro.py (the PEP 723 header pins spatialdata to the commit the bug was found on; replace the URL fragment with @main to test the current main branch).
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "spatialdata @ git+https://github.com/scverse/spatialdata.git@ccf1ea048d054b6624214bf618008a9f9ae223e0",
# ]
# ///
"""`element_name in regions` is a substring test when the table annotates a single region (regions is a str)."""
import warnings
import numpy as np
import pandas as pd
import geopandas as gpd
from anndata import AnnData
from shapely.geometry import Point
from spatialdata import SpatialData, get_element_annotators, get_values
from spatialdata.models import ShapesModel, TableModel
warnings.simplefilter("ignore")
cells = ShapesModel.parse(gpd.GeoDataFrame({"geometry": [Point(0, 0), Point(1, 1)], "radius": [1.0, 1.0]}, index=[0, 1]))
cell = ShapesModel.parse(gpd.GeoDataFrame({"geometry": [Point(0, 0), Point(1, 1)], "radius": [1.0, 1.0]}, index=[0, 1]))
obs = pd.DataFrame({"region": pd.Categorical(["cells"] * 2), "instance_id": [0, 1], "score": [1.0, 2.0]})
table = TableModel.parse(AnnData(X=np.zeros((2, 1)), obs=obs), region="cells", region_key="region", instance_key="instance_id")
sdata = SpatialData(shapes={"cells": cells, "cell": cell}, tables={"t": table})
print("table region metadata:", repr(table.uns["spatialdata_attrs"]["region"]))
annotators_cell = get_element_annotators(sdata, "cell")
print("get_element_annotators(sdata, 'cell') ->", annotators_cell, "(expected: set(), 'cell' is not annotated)")
try:
v = get_values("score", sdata=sdata, element_name="cell", table_name="t")
print("get_values('score', element_name='cell') ->", v.to_dict())
except Exception as e: # noqa: BLE001
print("get_values('score', element_name='cell') ->", type(e).__name__, str(e)[:80], "(expected: a clear 'not annotated' error)")
bug = annotators_cell == {"t"}
print("VERDICT:", "BUG REPRODUCED" if bug else "NOT REPRODUCED")
Observed output
table region metadata: 'cells'
get_element_annotators(sdata, 'cell') -> {'t'} (expected: set(), 'cell' is not annotated)
get_values('score', element_name='cell') -> AttributeError 'NoneType' object has no attribute 'uns' (expected: a clear 'not annotated' error)
VERDICT: BUG REPRODUCED
Possible fix direction (unverified)
Normalise to a list right after get_table_keys() (if isinstance(regions, str): regions = [regions], as the join functions already do), or make get_table_keys always return a list; grep for other in region(s) uses.
Environment
uv run repro.py with the PEP 723 metadata in the script (fresh, isolated environment; spatialdata built from main @ ccf1ea0 (2026-08-28); Python 3.13, latest releases of the dependencies at run time: pandas 3.0, anndata 0.13, zarr 3.3, dask 2026.8, numpy 2.5, geopandas 1.1, shapely 2.1). macOS (arm64). Also reproduced in a second environment with pandas 2.3.3 / anndata 0.12.11 / numpy 2.4.4 / zarr 3.2.1.
Automatically generated; discovered by an AI agent (Claude) and not yet reviewed by a human.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/spatialdata/_core/query/relational_query.py, especially get_element_annotators and _locate_value, then run the provided repro.py with uv. Check how get_table_keys() represents a single region and compare this with the join functions' normalization. Done means an unrelated element is not reported as annotated and get_values() raises a clear not-annotated error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100