From 53f65c716b50f5cf55073390f38da3dce27e0fd0 Mon Sep 17 00:00:00 2001 From: Jan Gleixner Date: Mon, 9 Nov 2026 16:02:27 +0100 Subject: [PATCH 1/3] ci: check docstring parameters against signatures with pydoclint (SIT-422) Add pydoclint (numpy style) as a pre-commit hook on src/, configured to check that documented parameters match the function signature (missing and stale names) and that Returns/Yields sections exist. Types, argument order and raises are not checked. Class docstrings may document __init__ parameters. Fix the drift it finds, e.g. get_extent documenting its parameters under Returns, Returns/Notes sections that did not parse, a duplicated PLACEHOLDER block in _bounding_box_mask_points, and undocumented parameters (c_coords in blobs, suppress_z_warning, sdata, zarr_path, ...). Closes #1303 --- .pre-commit-config.yaml | 5 ++ pyproject.toml | 15 ++++++ src/spatialdata/_core/centroids.py | 4 ++ src/spatialdata/_core/data_extent.py | 47 ++++--------------- src/spatialdata/_core/operations/aggregate.py | 8 ++++ src/spatialdata/_core/operations/rasterize.py | 2 + .../_core/query/relational_query.py | 8 +++- src/spatialdata/_core/query/spatial_query.py | 16 +++---- src/spatialdata/_core/spatialdata.py | 22 ++++----- src/spatialdata/_core/validation.py | 4 ++ src/spatialdata/_io/_utils.py | 6 +-- src/spatialdata/_io/io_raster.py | 10 +++- src/spatialdata/_io/io_shapes.py | 8 ++++ src/spatialdata/_io/io_zarr.py | 2 + src/spatialdata/_utils.py | 6 +-- src/spatialdata/dataloader/datasets.py | 4 -- src/spatialdata/datasets.py | 5 +- src/spatialdata/models/_utils.py | 4 ++ src/spatialdata/models/models.py | 6 +-- src/spatialdata/transformations/_utils.py | 7 ++- .../transformations/ngff/_utils.py | 3 ++ .../ngff/ngff_coordinate_system.py | 10 +++- .../ngff/ngff_transformations.py | 10 +++- src/spatialdata/transformations/operations.py | 5 ++ 24 files changed, 135 insertions(+), 82 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7aea57181..9108a90fd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,6 +24,11 @@ repos: args: [--fix, --exit-non-zero-on-fix] - id: ruff-format groups: [format] + - repo: https://github.com/jsh9/pydoclint + rev: 0.12.0 + hooks: + - id: pydoclint + files: ^src/ - repo: local hooks: - id: mypy diff --git a/pyproject.toml b/pyproject.toml index 19af17e7d..f01175a10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -276,9 +276,24 @@ lint.per-file-ignores."tests/*" = [ "B024", "D", "PT" ] lint.per-file-ignores."tests/conftest.py" = [ "E402" ] lint.per-file-ignores."tests/test_models/test_models.py" = [ "NPY002" ] lint.unfixable = [ "B", "BLE", "C4", "RET", "T20", "UP" ] +lint.external = [ "DOC1" ] # pydoclint parameter checks, see [tool.pydoclint] lint.isort.required-imports = [ "from __future__ import annotations" ] lint.pydocstyle.convention = "numpy" +[tool.pydoclint] +# Check that documented parameters match the function signature (missing or stale names, #1303), +# and that Returns/Yields sections exist. Types (they live in the signatures), order and raises are not checked. +# Docstrings with only a summary (no Parameters section) are skipped. +style = "numpy" +allow-init-docstring = true +arg-type-hints-in-docstring = false +check-return-types = false +check-yield-types = false +skip-checking-raises = true +check-class-attributes = false +check-arg-order = false +omit-stars-when-documenting-varargs = true + [tool.mypy] # TODO: extend to "tests" once the test suite carries type annotations. files = [ "src" ] diff --git a/src/spatialdata/_core/centroids.py b/src/spatialdata/_core/centroids.py index 9979b9f20..906b817e3 100644 --- a/src/spatialdata/_core/centroids.py +++ b/src/spatialdata/_core/centroids.py @@ -47,6 +47,10 @@ def get_centroids( return_background If True, the centroid of the background label (0) is included in the output. + Returns + ------- + The centroids, as a points element (Dask DataFrame) in the given coordinate system. + Notes ----- For :class:`~shapely.Multipolygon`s, the centroids are the average of the centroids of the polygons that constitute diff --git a/src/spatialdata/_core/data_extent.py b/src/spatialdata/_core/data_extent.py index 32f05834b..267d2bba0 100644 --- a/src/spatialdata/_core/data_extent.py +++ b/src/spatialdata/_core/data_extent.py @@ -116,17 +116,8 @@ def get_extent( ---------- e The SpatialData object or SpatialElement to compute the extent of. - - Returns - ------- - The bounding box description. - - min_coordinate - The minimum coordinate of the bounding box. - max_coordinate - The maximum coordinate of the bounding box. - axes - The names of the dimensions of the bounding box. + coordinate_system + The coordinate system in which the extent is computed. exact Whether the extent is computed exactly or not. @@ -145,6 +136,10 @@ def get_extent( elements If not `None`, only the elements with the given names are included in the computation of the extent. + Returns + ------- + The bounding box description: a dictionary mapping each axis name to its `(min, max)` extent. + Notes ----- The extent of a `SpatialData` object is the extent of the union of the extents of all its elements. @@ -178,20 +173,7 @@ def _( has_shapes: bool = True, elements: list[str] | None = None, ) -> BoundingBoxDescription: - """ - Get the extent (bounding box) of a SpatialData object. - - The resulting extent is the union of the extents of all its elements. - - Parameters - ---------- - e - The SpatialData object. - - Returns - ------- - The bounding box description. - """ + """Get the extent of a SpatialData object (the union of the extents of its elements); see :func:`get_extent`.""" new_min_coordinates_dict: dict[str, list[float]] = defaultdict(list) new_max_coordinates_dict: dict[str, list[float]] = defaultdict(list) mask = [has_images, has_labels, has_points, has_shapes] @@ -256,20 +238,7 @@ def _get_extent_of_shapes(e: GeoDataFrame) -> BoundingBoxDescription: @get_extent.register def _(e: GeoDataFrame, coordinate_system: str = "global", exact: bool = True) -> BoundingBoxDescription: - """ - Get the extent (bounding box) of a SpatialData object. - - The resulting extent is the union of the extents of all its elements. - - Parameters - ---------- - e - The SpatialData object. - - Returns - ------- - The bounding box description. - """ + """Get the extent of a shapes element; see :func:`get_extent`.""" _check_element_has_coordinate_system(element=e, coordinate_system=coordinate_system) if not exact: extent = _get_extent_of_shapes(e) diff --git a/src/spatialdata/_core/operations/aggregate.py b/src/spatialdata/_core/operations/aggregate.py index b4772df1b..974753f5e 100644 --- a/src/spatialdata/_core/operations/aggregate.py +++ b/src/spatialdata/_core/operations/aggregate.py @@ -366,6 +366,14 @@ def _aggregate_shapes( Aggregation function to apply over grouped values. Passed to pandas.DataFrame.groupby.agg. table_name Name of the table optionally containing the value_key column. + fractions + Whether to weight the values by the fraction of the `values` region overlapping the `by` region. + buffer_resolution + Resolution parameter passed to the `.buffer()` method when converting circles to polygons. + + Returns + ------- + An AnnData object with one row per region in `by` and the aggregated values as columns. """ from spatialdata._core.operations.vectorize import to_polygons from spatialdata.models import points_dask_dataframe_to_geopandas diff --git a/src/spatialdata/_core/operations/rasterize.py b/src/spatialdata/_core/operations/rasterize.py index d47f4bfca..72bb87a63 100644 --- a/src/spatialdata/_core/operations/rasterize.py +++ b/src/spatialdata/_core/operations/rasterize.py @@ -409,6 +409,8 @@ def _get_xarray_data_to_rasterize( The maximum coordinates of the bounding box for the data to be rasterized. target_sizes A dictionary containing the target size (in pixels) of each axis after rasterization. + target_coordinate_system + The coordinate system in which `min_coordinate` and `max_coordinate` are expressed. Returns ------- diff --git a/src/spatialdata/_core/query/relational_query.py b/src/spatialdata/_core/query/relational_query.py index 1a672eefc..da244a6b1 100644 --- a/src/spatialdata/_core/query/relational_query.py +++ b/src/spatialdata/_core/query/relational_query.py @@ -189,7 +189,7 @@ def _get_joined_table_indices( Returns ------- - The indices that of the table that match the SpatialElement indices. + The indices of the table that match the SpatialElement indices. """ mask = np.isin(table_instance_key_column.to_numpy(), element_indices) if joined_indices is None: @@ -891,6 +891,10 @@ def match_sdata_to_table( unfiltered and warns, ``False`` leaves them unfiltered silently. See :func:`spatialdata.join_spatialelement_table` for details. + Returns + ------- + A new SpatialData object containing the table and the matched elements. + Notes ----- For a graphical representation of the join operations, see the @@ -965,7 +969,7 @@ def filter_by_table_query( Returns ------- - The filtered SpatialData object. + The filtered SpatialData object. Notes ----- diff --git a/src/spatialdata/_core/query/spatial_query.py b/src/spatialdata/_core/query/spatial_query.py index f0360c310..90abc7908 100644 --- a/src/spatialdata/_core/query/spatial_query.py +++ b/src/spatialdata/_core/query/spatial_query.py @@ -65,9 +65,9 @@ def _get_bounding_box_corners_in_intrinsic_coordinates( axes The axes that min_coordinate and max_coordinate refer to. min_coordinate - {min_coordinate_docs} + {min_coordinate_docs} max_coordinate - {max_coordinate_docs} + {max_coordinate_docs} target_coordinate_system The coordinate system the bounding box is defined in. @@ -406,15 +406,9 @@ def _bounding_box_mask_points( axes The axes that min_coordinate and max_coordinate refer to. min_coordinate - PLACEHOLDER - The upper left hand corners of the bounding boxes (i.e., minimum coordinates along all dimensions). - Shape: (n_boxes, n_axes) or (n_axes,) for a single box. - {min_coordinate_docs} + {min_coordinate_docs} max_coordinate - The lower right hand corners of the bounding boxes (i.e., the maximum coordinates along all dimensions). - Shape: (n_boxes, n_axes) or (n_axes,) for a single box. - {max_coordinate_docs} - + {max_coordinate_docs} Returns ------- @@ -517,6 +511,8 @@ def bounding_box_query( return_request_only If `True`, the function returns the bounding box coordinates in the target coordinate system. Only valid with `DataArray` and `DataTree` elements. + kwargs + Additional keyword arguments passed to the implementation for the specific element type. Returns ------- diff --git a/src/spatialdata/_core/spatialdata.py b/src/spatialdata/_core/spatialdata.py index 1b6a17127..d941cb4aa 100644 --- a/src/spatialdata/_core/spatialdata.py +++ b/src/spatialdata/_core/spatialdata.py @@ -2098,7 +2098,7 @@ def _gen_repr( Returns ------- - The string representation of the SpatialData object. + The string representation of the SpatialData object. """ from spatialdata._utils import _natural_keys @@ -2247,10 +2247,9 @@ def _gen_spatial_element_values(self) -> Generator[SpatialElement, None, None]: """ Generate spatial element objects contained in the SpatialData instance. - Returns - ------- - Generator[SpatialElement, None, None] - A generator that yields spatial element objects contained in the SpatialData instance. + Yields + ------ + The spatial element objects contained in the SpatialData instance. """ for _, _, element in self._gen_spatial_elements(): @@ -2260,9 +2259,9 @@ def _gen_spatial_elements(self) -> Generator[tuple[str, str, SpatialElement], No """ Generate the images, labels, points and shapes contained in the SpatialData instance. - Returns - ------- - A generator object that returns a tuple containing the type of the element, its name, and the element itself. + Yields + ------ + Tuples containing the type of the element, its name, and the element itself. """ for element_type, elements in ( ("images", self.images), @@ -2284,10 +2283,9 @@ def _gen_elements( include_tables Whether to also generate table elements. - Returns - ------- - A generator object that returns a tuple containing the type of the element, its name, and the element - itself. + Yields + ------ + Tuples containing the type of the element, its name, and the element itself. """ yield from self._gen_spatial_elements() if include_tables: diff --git a/src/spatialdata/_core/validation.py b/src/spatialdata/_core/validation.py index dc2e4bf65..cbdd77912 100644 --- a/src/spatialdata/_core/validation.py +++ b/src/spatialdata/_core/validation.py @@ -295,6 +295,10 @@ def __call__( Tuple of strings identifying the parent element expected_exception The class of the exception to catch. Other exceptions are raised. + + Returns + ------- + The collector itself, to be used as a context manager. """ if isinstance(location, str): location = (location,) diff --git a/src/spatialdata/_io/_utils.py b/src/spatialdata/_io/_utils.py index ba10405bd..6ae9bfa92 100644 --- a/src/spatialdata/_io/_utils.py +++ b/src/spatialdata/_io/_utils.py @@ -59,12 +59,12 @@ def overwrite_coordinate_transformations_non_raster( Parameters ---------- - group: zarr.Group + group The zarr group containing the non-raster element for which to write the transformations, e.g. the zarr group containing sdata['points']. - axes: tuple[ValidAxis_t, ...] + axes The list with axes names in the same order as the coordinates of the non-raster element. - transformations: MappingToCoordinateSystem_t + transformations Mapping between names of the coordinate system and the transformations. """ _validate_mapping_to_coordinate_system_type(transformations) diff --git a/src/spatialdata/_io/io_raster.py b/src/spatialdata/_io/io_raster.py index 3806fabf7..9a73af5ef 100644 --- a/src/spatialdata/_io/io_raster.py +++ b/src/spatialdata/_io/io_raster.py @@ -69,6 +69,10 @@ def _is_regular_dask_chunk_grid(chunk_grid: Sequence[Sequence[int]]) -> bool: chunk_grid Per-axis tuple of chunk sizes, for instance as returned by ``dask_array.chunks``. + Returns + ------- + Whether the chunk grid is regular. + Examples -------- Triggers ``continue`` on the first ``if`` (single or empty axis): @@ -319,7 +323,7 @@ def _write_raster( The raster data to write. group The zarr group in the 'image' or 'labels' zarr group to write the raster data to. - name: str + name The name of the raster element. raster_format The format used to write the raster data. @@ -561,6 +565,10 @@ def _write_raster_datatree( Compression settings as a len-1 dictionary with a single key-value {compression: compression level} pair metadata Additional metadata for the raster element + + Returns + ------- + The zarr group the raster data was written to. """ write_multi_scale_ngff = write_multiscale_ngff if raster_type == "image" else write_multiscale_labels_ngff data = get_pyramid_levels(raster_data, attr="data") diff --git a/src/spatialdata/_io/io_shapes.py b/src/spatialdata/_io/io_shapes.py index 833406d39..77df6ee75 100644 --- a/src/spatialdata/_io/io_shapes.py +++ b/src/spatialdata/_io/io_shapes.py @@ -146,6 +146,10 @@ def _write_shapes_v01(shapes: GeoDataFrame, group: zarr.Group, element_format: S The zarr group in the 'shapes' zarr group to write the shapes element to. element_format The format of the shapes element used to store it. + + Returns + ------- + The attributes (metadata) to write for the shapes element. """ # np.array() creates a writable copy, needed for pandas 3.0 CoW compatibility # https://github.com/geopandas/geopandas/issues/3697 @@ -186,6 +190,10 @@ def _write_shapes_v02_v03( geometry_encoding Whether to use the WKB or geoarrow encoding for GeoParquet. See :meth:`geopandas.GeoDataFrame.to_parquet` for details. + + Returns + ------- + The attributes (metadata) to write for the shapes element. """ from spatialdata.models._utils import TRANSFORM_KEY diff --git a/src/spatialdata/_io/io_zarr.py b/src/spatialdata/_io/io_zarr.py index 186d7c974..4b546dfc3 100644 --- a/src/spatialdata/_io/io_zarr.py +++ b/src/spatialdata/_io/io_zarr.py @@ -324,6 +324,8 @@ def _group_for_element_exists(zarr_path: Path, element_type: str, element_name: Parameters ---------- + zarr_path + Path to the Zarr store. element_type type of the element; must be in ["images", "labels", "points", "polygons", "shapes", "tables"]. element_name diff --git a/src/spatialdata/_utils.py b/src/spatialdata/_utils.py index a0086b7b2..e3b4c4e3f 100644 --- a/src/spatialdata/_utils.py +++ b/src/spatialdata/_utils.py @@ -200,9 +200,9 @@ def iterate_pyramid_levels( If `None`, return the data of the pyramid level as a `DataArray`, if not None, return the specified attribute within the `DataArray` data. - Returns - ------- - A generator to iterate over the pyramid levels. + Yields + ------ + The pyramid levels. """ scale0 = data["scale0"] assert isinstance(scale0, DataTree) diff --git a/src/spatialdata/dataloader/datasets.py b/src/spatialdata/dataloader/datasets.py index b34ad5bf5..82037a2df 100644 --- a/src/spatialdata/dataloader/datasets.py +++ b/src/spatialdata/dataloader/datasets.py @@ -101,10 +101,6 @@ class ImageTilesDataset(Dataset[Any]): Keyword arguments passed to :func:`spatialdata.rasterize` if `rasterize` is `True`. This argument can be used in particular to choose the pixel dimension of the produced image tiles; please refer to the :func:`spatialdata.rasterize` documentation for this use case. - - Returns - ------- - :class:`torch.utils.data.Dataset` for loading tiles from a :class:`spatialdata.SpatialData`. """ INSTANCE_KEY = "instance_id" diff --git a/src/spatialdata/datasets.py b/src/spatialdata/datasets.py index fb57a28b1..299cb4d81 100644 --- a/src/spatialdata/datasets.py +++ b/src/spatialdata/datasets.py @@ -59,7 +59,8 @@ def blobs( Extra coordinate space on top of the standard global coordinate space. Will have only identity transform. n_channels Number of channels of the image - + c_coords + Channel names of the image. If given, overrides `n_channels`. Returns ------- @@ -189,6 +190,8 @@ def __init__( Extra coordinate space on top of the standard global coordinate space. Will have only identity transform. n_channels Number of channels of the image + c_coords + Channel names of the image. If given, overrides `n_channels`. """ self.length = length self.n_points = n_points diff --git a/src/spatialdata/models/_utils.py b/src/spatialdata/models/_utils.py index 972e2d9be..36a33f60f 100644 --- a/src/spatialdata/models/_utils.py +++ b/src/spatialdata/models/_utils.py @@ -202,6 +202,8 @@ def points_dask_dataframe_to_geopandas(points: DaskDataFrame, suppress_z_warning points Dask DataFrame with columns "x" and "y". Eventually, it can contain a column "z" that will be not included in the geometry column. + suppress_z_warning + If `True`, do not warn that the "z" column is not included in the geometry. Returns ------- @@ -241,6 +243,8 @@ def points_geopandas_to_dask_dataframe(gdf: GeoDataFrame, suppress_z_warning: bo ---------- gdf GeoDataFrame with a geometry column that contains 2D or 3D points. + suppress_z_warning + If `True`, do not warn about the z coordinate being taken from a separate column. Returns ------- diff --git a/src/spatialdata/models/models.py b/src/spatialdata/models/models.py index b0a6c16f6..a0d336b5e 100644 --- a/src/spatialdata/models/models.py +++ b/src/spatialdata/models/models.py @@ -143,7 +143,7 @@ def parse( Dimensions of the data (e.g. ['c', 'y', 'x'] for 2D image data). If the data is a :class:`xarray.DataArray`, the dimensions can also be inferred from the data. If the dimensions are not in the order (c)(z)yx, the data will be transposed to match the order. - c_coords : str | list[str] | None + c_coords Channel names of image data. Must be equal to the length of dimension 'c'. Only supported for `Image` models. transformations @@ -622,7 +622,7 @@ def parse(cls, data: Any, **kwargs: Any) -> GeoDataFrame: Returns ------- :class:`geopandas.GeoDataFrame` - """ + """ # noqa: DOC102, DOC103 (parameters of the registered implementations) raise TypeError(f"ShapesModel.parse() does not support the type {type(data)}") @parse.register(np.ndarray) @@ -788,7 +788,7 @@ def parse(cls, data: Any, **kwargs: Any) -> DaskDataFrame: ----- The order of the columns of the dataframe returned by the parser is not guaranteed to be the same as the order of the columns in the dataframe passed as an argument. - """ + """ # noqa: DOC102, DOC103 (parameters of the registered implementations) raise TypeError(f"PointsModel.parse() does not support the type {type(data)}") @parse.register(np.ndarray) diff --git a/src/spatialdata/transformations/_utils.py b/src/spatialdata/transformations/_utils.py index 032c89c13..c0cf1484f 100644 --- a/src/spatialdata/transformations/_utils.py +++ b/src/spatialdata/transformations/_utils.py @@ -60,12 +60,13 @@ def _set_transformations_to_element(element: Any, transformations: MappingToCoor def _set_transformations(e: SpatialElement, transformations: MappingToCoordinateSystem_t) -> None: """ Set the transformation of a SpatialElement *only in memory*. + Parameters ---------- e SpatialElement - t - transformation + transformations + Mapping from coordinate system names to transformations. Notes ----- @@ -276,6 +277,8 @@ def convert_transformations_to_affine(sdata: SpatialData, coordinate_system: str Parameters ---------- + sdata + The SpatialData object whose elements' transformations are converted. coordinate_system The coordinate system to convert to. diff --git a/src/spatialdata/transformations/ngff/_utils.py b/src/spatialdata/transformations/ngff/_utils.py index 07dff152c..c3f0a795a 100644 --- a/src/spatialdata/transformations/ngff/_utils.py +++ b/src/spatialdata/transformations/ngff/_utils.py @@ -46,6 +46,9 @@ def get_default_coordinate_system(dims: tuple[str, ...]) -> NgffCoordinateSystem The dimension names to get the corresponding axes of the defeault coordinate system for. Names should be in ['x', 'y', 'z', 'c']. + Returns + ------- + The default coordinate system with the axes corresponding to `dims`. """ axes = [] for c in dims: diff --git a/src/spatialdata/transformations/ngff/ngff_coordinate_system.py b/src/spatialdata/transformations/ngff/ngff_coordinate_system.py index fb5a24882..56424d6e1 100644 --- a/src/spatialdata/transformations/ngff/ngff_coordinate_system.py +++ b/src/spatialdata/transformations/ngff/ngff_coordinate_system.py @@ -15,7 +15,7 @@ class NgffAxis: """ Representation of an axis, following the NGFF specification. - Attributes + Parameters ---------- name name of the axis. @@ -181,6 +181,10 @@ def has_axis(self, name: str) -> bool: ---------- name name of the axis. + + Returns + ------- + Whether the coordinate system has an axis with the given name. """ return any(axis.name == name for axis in self._axes) @@ -206,6 +210,10 @@ def merge( new_name name of the new coordinate system + + Returns + ------- + The merged coordinate system. """ # common axes need to be the identical otherwise no merge is made common_axes = set(coord_sys1.axes_names).intersection(coord_sys2.axes_names) diff --git a/src/spatialdata/transformations/ngff/ngff_transformations.py b/src/spatialdata/transformations/ngff/ngff_transformations.py index 1758159bf..f73744b59 100644 --- a/src/spatialdata/transformations/ngff/ngff_transformations.py +++ b/src/spatialdata/transformations/ngff/ngff_transformations.py @@ -85,6 +85,10 @@ def from_dict(cls, d: Transformation_t) -> NgffBaseTransformation: ---------- d the Python dict representing the transformation. + + Returns + ------- + The transformation. """ # d = MappingProxyType(d) type = d["type"] @@ -118,7 +122,7 @@ def _update_dict_with_input_output_cs(self, d: Transformation_t) -> None: The dictionary to be updated. Notes - ------- + ----- Use of this helper function. A transformation is saved to disk as a json string. When loaded this is represented by a dictionary. We allow transformations to be defined even when the input and output coordinate systems are not @@ -365,6 +369,10 @@ def _affine_matrix_from_input_and_output_axes( the input axes. output_axes the output axes. + + Returns + ------- + The affine matrix. """ from spatialdata.models import C, X, Y, Z diff --git a/src/spatialdata/transformations/operations.py b/src/spatialdata/transformations/operations.py index 9091cec38..bc7d0d1ab 100644 --- a/src/spatialdata/transformations/operations.py +++ b/src/spatialdata/transformations/operations.py @@ -223,12 +223,17 @@ def get_transformation_between_coordinate_systems( Parameters ---------- + sdata + The SpatialData object containing the elements and their transformations. source_coordinate_system The source coordinate system. Can be a SpatialElement (intrinsic coordinate system) or a string (extrinsic coordinate system). target_coordinate_system The target coordinate system. Can be a SpatialElement (intrinsic coordinate system) or a string (extrinsic coordinate system). + intermediate_coordinate_systems + If multiple paths exist between source and target, only consider those passing through this coordinate system + (a SpatialElement for an intrinsic one, or a string for an extrinsic one). shortest_path Whether to return the shortest paths when multiple paths are found between the coordinate systems and a single shortest path is found. If `False`, an error is raised when multiple paths exist. From a27c079556148299126e7cc42b584303a7e6a457 Mon Sep 17 00:00:00 2001 From: Jan Gleixner Date: Mon, 9 Nov 2026 16:10:39 +0100 Subject: [PATCH 2/3] docs: clarify iterate_pyramid_levels yields --- src/spatialdata/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spatialdata/_utils.py b/src/spatialdata/_utils.py index e3b4c4e3f..d33786bef 100644 --- a/src/spatialdata/_utils.py +++ b/src/spatialdata/_utils.py @@ -202,7 +202,7 @@ def iterate_pyramid_levels( Yields ------ - The pyramid levels. + The pyramid levels (or their attribute `attr`, if given). """ scale0 = data["scale0"] assert isinstance(scale0, DataTree) From 2eb977e6752695aa4db4677386590428436d2c50 Mon Sep 17 00:00:00 2001 From: Jan Gleixner Date: Mon, 9 Nov 2026 16:30:21 +0100 Subject: [PATCH 3/3] docs: don't document bounding_box_query's dispatch-only **kwargs --- src/spatialdata/_core/query/spatial_query.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/spatialdata/_core/query/spatial_query.py b/src/spatialdata/_core/query/spatial_query.py index 90abc7908..db3b3139b 100644 --- a/src/spatialdata/_core/query/spatial_query.py +++ b/src/spatialdata/_core/query/spatial_query.py @@ -511,8 +511,6 @@ def bounding_box_query( return_request_only If `True`, the function returns the bounding box coordinates in the target coordinate system. Only valid with `DataArray` and `DataTree` elements. - kwargs - Additional keyword arguments passed to the implementation for the specific element type. Returns ------- @@ -523,7 +521,7 @@ def bounding_box_query( ----- If the object has `points` element, depending on the number of points, it MAY suffer from performance issues. Please consider filtering the object before calling this function by calling the `subset()` method of `SpatialData`. - """ + """ # noqa: DOC101, DOC103 (**kwargs only exists for singledispatch; nothing extra is accepted) raise RuntimeError("Unsupported type for bounding_box_query: " + str(type(element)) + ".")