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
9 changes: 1 addition & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,10 @@ minimum_pre_commit_version: 2.16.0
ci:
skip: []
repos:
- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.4.2
hooks:
- id: prettier
- repo: https://github.com/asottile/blacken-docs
rev: 1.19.1
hooks:
- id: blacken-docs
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1
hooks:
Expand All @@ -31,3 +23,4 @@ repos:
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
1 change: 0 additions & 1 deletion benchmarks/spatialdata_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ def time_map_blocks(self, _):


class TimeQueries:

params = ([100, 1_000, 10_000], [True, False], [100, 1_000])
param_names = ["length", "filter_table", "n_transcripts_per_cell"]

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- function run_benchmark is used to run the benchmarks.

Performant dataset generation functions so the benchmarks run fast even for large artificial datasets.
The object is to generate a dataset containing many cells. By copying the same cell values instead of
The object is to generate a dataset containing many cells. By copying the same cell values instead of
doing gaussian blur on the whole image, we can generate the same dataset in a fraction of the time.
- function labeled_particles is used to generate labeled blobs.
- function _generate_ball is used to generate a ball of given radius and dimension.
Expand Down
2 changes: 1 addition & 1 deletion docs/extensions/typed_returns.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def _process_return(lines):
m = re.fullmatch(r"(?P<param>\w+)\s+:\s+(?P<type>[\w.]+)", line)
if m:
# Once this is in scanpydoc, we can use the fancy hover stuff
yield f'-{m["param"]} (:class:`~{m["type"]}`)'
yield f"-{m['param']} (:class:`~{m['type']}`)"
else:
yield line

Expand Down
22 changes: 1 addition & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,27 +103,6 @@ filterwarnings = [
# "ignore:.*U.*mode is deprecated:DeprecationWarning",
]

[tool.black]
line-length = 120
target-version = ['py310']
include = '\.pyi?$'
exclude = '''
(
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
)
'''

[tool.jupytext]
formats = "ipynb,md"

Expand All @@ -148,6 +127,7 @@ exclude = [
"docs/_build",
"dist",
"setup.py",

]
line-length = 120
target-version = "py310"
Expand Down
10 changes: 5 additions & 5 deletions src/spatialdata/_core/operations/aggregate.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ def aggregate(
ONES_KEY = None
if value_key is None:
ONES_KEY = "__ones_column_aggregate"
assert (
ONES_KEY not in values_.columns
), f"Column {ONES_KEY} is reserved for internal use and cannot be already present in values_"
assert ONES_KEY not in values_.columns, (
f"Column {ONES_KEY} is reserved for internal use and cannot be already present in values_"
)
values_[ONES_KEY] = 1
value_key = ONES_KEY

Expand Down Expand Up @@ -384,10 +384,10 @@ def _aggregate_shapes(
"agg_func='sum' instead."
)
assert not isinstance(values.iloc[0].geometry, Point), (
"Fractions cannot be computed when values are points. " "Please use fractions=False."
"Fractions cannot be computed when values are points. Please use fractions=False."
)
assert not (categorical and agg_func == "mean"), (
"Incompatible choice: aggregating a categorical column with " "agg_func='mean'"
"Incompatible choice: aggregating a categorical column with agg_func='mean'"
)

# we need to add a column of ones to the values dataframe to be able to count the number of instances in each zone
Expand Down
6 changes: 3 additions & 3 deletions src/spatialdata/_core/operations/rasterize.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,9 +678,9 @@ def rasterize_shapes_points(
elif isinstance(agg_func, str):
AGGREGATIONS = ["sum", "count", "count_cat", "first"]

assert np.isin(
agg_func, AGGREGATIONS
), f"Aggregation function must be one of {', '.join(AGGREGATIONS)}. Found {agg_func}"
assert np.isin(agg_func, AGGREGATIONS), (
f"Aggregation function must be one of {', '.join(AGGREGATIONS)}. Found {agg_func}"
)

assert agg_func == "count" or value_key is not None, f"value_key cannot be done for agg_func={agg_func}"

Expand Down
6 changes: 3 additions & 3 deletions src/spatialdata/_core/operations/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,9 @@ def _(
if transformation is None and to_coordinate_system is not None:
return data.transform_to_coordinate_system(target_coordinate_system=to_coordinate_system)
raise RuntimeError(ERROR_MSG_AFTER_0_0_15)
assert bool(transformation is None) != bool(
to_coordinate_system is None
), "When maintain_positioning is True, only one of transformation and to_coordinate_system can be None"
assert bool(transformation is None) != bool(to_coordinate_system is None), (
"When maintain_positioning is True, only one of transformation and to_coordinate_system can be None"
)
new_elements: dict[str, dict[str, Any]] = {}
for element_type in ["images", "labels", "points", "shapes"]:
d = getattr(data, element_type)
Expand Down
4 changes: 2 additions & 2 deletions src/spatialdata/_core/operations/vectorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def _(element: GeoDataFrame, **kwargs: Any) -> GeoDataFrame:
return _make_circles(element, obs)
if isinstance(element.geometry.iloc[0], Point):
return element
raise RuntimeError("Unsupported geometry type: " f"{type(element.geometry.iloc[0])}")
raise RuntimeError(f"Unsupported geometry type: {type(element.geometry.iloc[0])}")


@to_circles.register(DaskDataFrame)
Expand Down Expand Up @@ -281,7 +281,7 @@ def _(gdf: GeoDataFrame, buffer_resolution: int = 16) -> GeoDataFrame:
return buffered_df
assert isinstance(gdf.geometry.iloc[0], Polygon | MultiPolygon)
return gdf
raise RuntimeError("Unsupported geometry type: " f"{type(gdf.geometry.iloc[0])}")
raise RuntimeError(f"Unsupported geometry type: {type(gdf.geometry.iloc[0])}")


@to_polygons.register(DaskDataFrame)
Expand Down
6 changes: 3 additions & 3 deletions src/spatialdata/_core/query/relational_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ def _filter_table_by_elements(
"""
assert set(elements_dict.keys()).issubset({"images", "labels", "shapes", "points"})
assert len(elements_dict) > 0, "elements_dict must not be empty"
assert any(
len(elements) > 0 for elements in elements_dict.values()
), "elements_dict must contain at least one dict which contains at least one element"
assert any(len(elements) > 0 for elements in elements_dict.values()), (
"elements_dict must contain at least one dict which contains at least one element"
)
if table is None:
return None
to_keep = np.zeros(len(table), dtype=bool)
Expand Down
8 changes: 3 additions & 5 deletions src/spatialdata/_core/spatialdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ def __init__(
"For renaming, please see the discussion here https://github.com/scverse/spatialdata/discussions/707 .",
exc_type=(ValueError, KeyError),
) as collect_error:

if images is not None:
for k, v in images.items():
with collect_error(location=("images", k)):
Expand Down Expand Up @@ -1715,7 +1714,6 @@ def get_attrs(
"""

def _flatten_mapping(m: Mapping[str, Any], parent_key: str = "", sep: str = "_") -> dict[str, Any]:

items: list[tuple[str, Any]] = []
for k, v in m.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
Expand Down Expand Up @@ -2007,7 +2005,7 @@ def h(s: str) -> str:
descr += f"{h('empty_line')}"
descr_class = v.__class__.__name__
if attr == "shapes":
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class} " f"shape: {v.shape} (2D shapes)"
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class} shape: {v.shape} (2D shapes)"
elif attr == "points":
length: int | None = None
if len(v.dask) == 1:
Expand Down Expand Up @@ -2037,7 +2035,7 @@ def h(s: str) -> str:
+ ", ".join([str(dim) if not isinstance(dim, Delayed) else "<Delayed>" for dim in v.shape])
+ ")"
)
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class} " f"with shape: {shape_str} {dim_string}"
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class} with shape: {shape_str} {dim_string}"
elif attr == "tables":
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class} {v.shape}"
else:
Expand All @@ -2055,7 +2053,7 @@ def h(s: str) -> str:
if dims is None:
dims = "".join(vv.dims)
shapes.append(shape)
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class}[{dims}] " f"{', '.join(map(str, shapes))}"
descr += f"{h(attr + 'level1.1')}{k!r}: {descr_class}[{dims}] {', '.join(map(str, shapes))}"
else:
raise TypeError(f"Unknown type {type(v)}")
if last_attr is True:
Expand Down
5 changes: 2 additions & 3 deletions src/spatialdata/_io/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def ome_zarr_logger(level: Any) -> Generator[None, None, None]:


def _get_transformations_from_ngff_dict(
list_of_encoded_ngff_transformations: list[dict[str, Any]]
list_of_encoded_ngff_transformations: list[dict[str, Any]],
) -> MappingToCoordinateSystem_t:
list_of_ngff_transformations = [NgffBaseTransformation.from_dict(d) for d in list_of_encoded_ngff_transformations]
list_of_transformations = [BaseTransformation.from_ngff(t) for t in list_of_ngff_transformations]
Expand Down Expand Up @@ -118,8 +118,7 @@ def overwrite_channel_names(group: zarr.Group, element: DataArray | DataTree) ->
multiscales_meta = group.attrs["multiscales"]
if len(multiscales_meta) != 1:
raise ValueError(
f"Multiscale metadata must be of length one but got length {len(multiscales_meta)}. Data might"
f"be corrupted."
f"Multiscale metadata must be of length one but got length {len(multiscales_meta)}. Data mightbe corrupted."
)
multiscales_meta[0]["metadata"]["omero"]["channels"] = channel_metadata
group.attrs["multiscales"] = multiscales_meta
Expand Down
6 changes: 3 additions & 3 deletions src/spatialdata/dataloader/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ def _validate(
raise ValueError("`table_name` must be provided if `return_annotations` is not `None`.")

# check that the regions specified in the two dicts are the same
assert set(regions_to_images.keys()) == set(
regions_to_coordinate_systems.keys()
), "The keys in `regions_to_images` and `regions_to_coordinate_systems` must be the same."
assert set(regions_to_images.keys()) == set(regions_to_coordinate_systems.keys()), (
"The keys in `regions_to_images` and `regions_to_coordinate_systems` must be the same."
)
self.regions = list(regions_to_coordinate_systems.keys()) # all regions for the dataloader

cs_region_image: list[tuple[str, str, str]] = [] # list of tuples (coordinate_system, region, image)
Expand Down
6 changes: 3 additions & 3 deletions src/spatialdata/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ def assert_elements_are_identical(
if check_transformations:
assert transformations0.keys() == transformations1.keys()
for key in transformations0:
assert (
transformations0[key] == transformations1[key]
), f"transformations0[{key}] != transformations1[{key}]"
assert transformations0[key] == transformations1[key], (
f"transformations0[{key}] != transformations1[{key}]"
)

# compare the elements
if isinstance(element0, AnnData):
Expand Down
2 changes: 1 addition & 1 deletion src/spatialdata/transformations/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def set_transformation(
_set_transformations(element, transformations)
else:
assert isinstance(transformation, dict), (
"If set_all=True, transformation must be of type " "dict[str, BaseTransformation]."
"If set_all=True, transformation must be of type dict[str, BaseTransformation]."
)
assert to_coordinate_system is None, "If set_all=True, to_coordinate_system must be None."
_set_transformations(element, transformation)
Expand Down
3 changes: 1 addition & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ def full_sdata() -> SpatialData:

@pytest.fixture(
# params=["labels"]
params=["full", "empty"]
+ ["images", "labels", "points", "table_single_annotation", "table_multiple_annotations"]
params=["full", "empty"] + ["images", "labels", "points", "table_single_annotation", "table_multiple_annotations"]
# + ["empty_" + x for x in ["table"]] # TODO: empty table not supported yet
)
def sdata(request) -> SpatialData:
Expand Down
2 changes: 1 addition & 1 deletion tests/core/operations/test_rasterize_bins.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def _get_sdata(n: int):
table.obs["region"] = regions
with pytest.raises(
ValueError,
match="Found multiple regions annotated by the table: " "points, shapes.",
match="Found multiple regions annotated by the table: points, shapes.",
):
_ = rasterize_bins(
sdata=sdata,
Expand Down
7 changes: 5 additions & 2 deletions tests/core/query/test_spatial_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,11 @@ def test_query_raster(
model = (
Labels3DModel
if is_labels and is_3d
else Labels2DModel if is_labels else Image3DModel if is_3d else Image2DModel
else Labels2DModel
if is_labels
else Image3DModel
if is_3d
else Image2DModel
)

image_element = model.parse(image)
Expand Down Expand Up @@ -420,7 +424,6 @@ def test_query_polygons(is_bb_3d: bool, with_polygon_query: bool, multiple_boxes
assert isinstance(polygons_result, list)
assert len(polygons_result) == 2
if box_outside_polygon:

assert polygons_result[0] is None
assert polygons_result[1].index[0] == 3
else:
Expand Down
3 changes: 1 addition & 2 deletions tests/io/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ def test_validate_can_write_metadata_on_element(full_sdata, element_name):
# trying to save metadata before writing the data
with pytest.warns(
UserWarning,
match="The SpatialData object appears not to be backed by a Zarr storage, so metadata cannot be "
"written.",
match="The SpatialData object appears not to be backed by a Zarr storage, so metadata cannot be written.",
):
full_sdata._validate_can_write_metadata_on_element(element_name)

Expand Down
2 changes: 1 addition & 1 deletion tests/io/test_multi_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def test_set_table_annotates_spatialelement(self, full_sdata, tmp_path):
tmpdir = Path(tmp_path) / "tmp.zarr"
del full_sdata["table"].uns[TableModel.ATTRS_KEY]
with pytest.raises(
TypeError, match="No current annotation metadata found. " "Please specify both region_key and instance_key."
TypeError, match="No current annotation metadata found. Please specify both region_key and instance_key."
):
full_sdata.set_table_annotates_spatialelement("table", "labels2d", region_key="non_existent")
with pytest.raises(ValueError, match="Instance key column 'non_existent' not found in table.obs."):
Expand Down
6 changes: 3 additions & 3 deletions tests/models/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ def test_labels_model_with_multiscales(self, model):
assert actual.scale0.image.dtype == image.dtype
assert actual.scale1.image.dtype == image.dtype
assert set(np.unique(image)) == set(np.unique(actual.scale0.image)), "Scale0 should be preserved"
assert set(np.unique(image)) >= set(
np.unique(actual.scale1.image)
), "Subsequent scales should not have interpolation artifacts"
assert set(np.unique(image)) >= set(np.unique(actual.scale1.image)), (
"Subsequent scales should not have interpolation artifacts"
)

@pytest.mark.parametrize("model", [ShapesModel])
@pytest.mark.parametrize("path", [POLYGON_PATH, MULTIPOLYGON_PATH, POINT_PATH])
Expand Down
2 changes: 1 addition & 1 deletion tests/transformations/test_transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ def test_get_affine_for_element(images):
np.array(
[
# fmt: off
#c y x # noqa: E265
# c y x # noqa: E265
[1, 0, 0, 0], # c
[0, 0, 1, 1], # x
[0, 1, 0, 2], # y
Expand Down
Loading