Skip to content

Commit

Permalink
Merge branch 'no_python_313' into remote2
Browse files Browse the repository at this point in the history
  • Loading branch information
LucaMarconato committed Jan 31, 2025
2 parents ce686e4 + a9c0801 commit 5cfdaec
Show file tree
Hide file tree
Showing 22 changed files with 52 additions and 79 deletions.
11 changes: 2 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,19 @@ 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:
- id: mypy
additional_dependencies: [numpy, types-requests]
exclude: tests/|docs/
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.2
rev: v0.9.3
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
24 changes: 2 additions & 22 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ maintainers = [
urls.Documentation = "https://spatialdata.scverse.org/en/latest"
urls.Source = "https://github.com/scverse/spatialdata.git"
urls.Home-page = "https://github.com/scverse/spatialdata.git"
requires-python = ">=3.10"
requires-python = ">=3.10, <3.13" # include 3.13 once multiscale-spatial-image conflicts are resolved
dynamic= [
"version" # allow version to be set by git tags
]
Expand Down Expand Up @@ -105,27 +105,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 @@ -150,6 +129,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
13 changes: 8 additions & 5 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 Expand Up @@ -693,8 +693,11 @@ def _call_join(
raise TypeError(
f"`{match_rows}` is an invalid argument for `match_rows`. Can be either `no`, ``'left'`` or ``'right'``"
)
if how in JoinTypes.__dict__["_member_names_"]:
elements_dict, table = JoinTypes[how](elements_dict, table, match_rows)
# bug with Python 3.13 (https://github.com/scverse/spatialdata/issues/852)
# if how in JoinTypes.__dict__["_member_names_"]:
# hotfix for bug with Python 3.13:
if how in JoinTypes.__dict__:
elements_dict, table = getattr(JoinTypes, how)(elements_dict, table, match_rows)
else:
raise TypeError(f"`{how}` is not a valid type of join.")

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

0 comments on commit 5cfdaec

Please sign in to comment.