spatialdata 0.7.3a1__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spatialdata-0.8.0/.claude/skills/memray/SKILL.md +37 -0
- spatialdata-0.8.0/.claude/skills/profimp/SKILL.md +30 -0
- spatialdata-0.8.0/.claude/skills/pyspy/SKILL.md +45 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/workflows/test.yaml +8 -8
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.gitignore +9 -2
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.mypy.ini +1 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.pre-commit-config.yaml +3 -3
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/PKG-INFO +12 -8
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/README.md +6 -2
- spatialdata-0.8.0/_version.py +24 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/benchmarks/README.md +26 -0
- spatialdata-0.8.0/benchmarks/benchmark_dataloader.py +75 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/models_utils.md +1 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/index.md +7 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/pyproject.toml +42 -6
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/_elements.py +3 -22
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/_utils.py +3 -3
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/centroids.py +22 -37
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/concatenate.py +0 -8
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/rasterize_bins.py +4 -8
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/transform.py +35 -12
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/query/_utils.py +5 -6
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/query/relational_query.py +188 -133
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/query/spatial_query.py +119 -120
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/spatialdata.py +44 -22
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/validation.py +4 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/_utils.py +65 -13
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/io_points.py +2 -3
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/io_raster.py +124 -17
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/io_shapes.py +2 -3
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/io_table.py +1 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_types.py +2 -2
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/dataloader/__init__.py +3 -5
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/dataloader/datasets.py +35 -17
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/datasets.py +4 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/models/__init__.py +2 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/models/_utils.py +3 -2
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/models/chunks_utils.py +2 -2
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/models/models.py +58 -5
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/conftest.py +95 -22
- spatialdata-0.8.0/tests/core/operations/conftest.py +1 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_rasterize_bins.py +0 -18
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_spatialdata_operations.py +22 -18
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_transform.py +75 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_vectorize.py +25 -22
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/query/test_relational_query.py +39 -3
- spatialdata-0.8.0/tests/core/query/test_relational_query_match_sdata_to_table.py +235 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/query/test_spatial_query.py +101 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/test_data_extent.py +13 -9
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/test_get_attrs.py +5 -9
- spatialdata-0.8.0/tests/dataloader/conftest.py +1 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_attrs_io.py +2 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_format.py +2 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_metadata.py +5 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_multi_table.py +1 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_partial_read.py +47 -25
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_pyramids_performance.py +22 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_readwrite.py +115 -15
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/test_utils.py +24 -1
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/models/test_models.py +14 -13
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/utils/test_sanitize.py +16 -0
- spatialdata-0.7.3a1/_version.py +0 -34
- spatialdata-0.7.3a1/docs/_templates/.gitkeep +0 -0
- spatialdata-0.7.3a1/docs/_templates/autosummary/base.rst +0 -5
- spatialdata-0.7.3a1/docs/_templates/autosummary/class.rst +0 -61
- spatialdata-0.7.3a1/docs/_templates/autosummary/function.rst +0 -5
- spatialdata-0.7.3a1/tests/core/query/test_relational_query_match_sdata_to_table.py +0 -146
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.bumpversion.cfg +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.editorconfig +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/codecov.yml +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/release.yml +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/workflows/build_image.yml +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.github/workflows/release.yaml +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.gitmodules +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/.readthedocs.yaml +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/CHANGELOG.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/Dockerfile +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/LICENSE +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/asv.conf.json +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/benchmarks/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/benchmarks/benchmark_imports.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/benchmarks/spatialdata_benchmark.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/benchmarks/utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/Makefile +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/_static/.gitkeep +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/_static/css/custom.css +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/_static/img/spatialdata_horizontal.png +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/SpatialData.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/data_formats.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/dataloader.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/datasets.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/io.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/models.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/operations.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/testing.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/transformations.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api/transformations_utils.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/api.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/changelog.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/conf.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/contributing.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/design_doc.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/extensions/typed_returns.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/glossary.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/installation.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/references.bib +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/references.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/docs/user_guide.md +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/__main__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_bridges/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/_deepcopy.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/data_extent.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/aggregate.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/map.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/rasterize.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/operations/vectorize.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_core/query/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_docs.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/format.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_io/io_zarr.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_logging.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/config.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/io/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/models/_accessor.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/models/pyramids_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/testing.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/ngff/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/ngff/_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/ngff/ngff_coordinate_system.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/ngff/ngff_transformations.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/operations.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/src/spatialdata/transformations/transformations.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_aggregations.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_map.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/operations/test_rasterize.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/query/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/test_centroids.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/test_deepcopy.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/core/test_validation.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/data/multipolygon.json +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/data/points.json +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/data/polygon.json +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/dataloader/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/dataloader/test_datasets.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/datasets/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/datasets/test_datasets.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/io/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/models/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/models/test_accessor.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/models/test_chunks_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/models/test_pyramids_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/test_init.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/ngff/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/ngff/conftest.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/ngff/test_ngff_coordinate_system.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/ngff/test_ngff_transformations.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/test_transformations.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/transformations/test_transformations_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/utils/__init__.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/utils/test_element_utils.py +0 -0
- {spatialdata-0.7.3a1 → spatialdata-0.8.0}/tests/utils/test_testing.py +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memray
|
|
3
|
+
description: Profile the memory usage of a Python script using memray and visualize a temporal flamegraph in the browser. Use when the user wants to investigate memory consumption, find leaks, or understand allocation patterns.
|
|
4
|
+
compatibility: Requires the pixi profiling environment (pixi run -e profiling). Supports Linux and macOS.
|
|
5
|
+
allowed-tools: Bash(pixi run -e profiling memray-run:*) Bash(pixi run -e profiling memray-flame:*) Bash(open:*) Bash(xdg-open:*) Bash(python -m webbrowser:*)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
|
|
10
|
+
1. Ask the user which script to profile (full or relative path).
|
|
11
|
+
|
|
12
|
+
2. Run the script under memray:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pixi run -e profiling memray-run script.py
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This produces a binary file named `memray-script.py.<pid>.bin` in the current directory.
|
|
19
|
+
|
|
20
|
+
3. Generate the flamegraph HTML report from the `.bin` file:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pixi run -e profiling memray-flame memray-script.py.<pid>.bin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Replace `<pid>` with the actual PID shown in the filename. This writes `memray-flamegraph-script.py.<pid>.html`.
|
|
27
|
+
|
|
28
|
+
4. Open the report in the browser:
|
|
29
|
+
- macOS: `open memray-flamegraph-script.py.<pid>.html`
|
|
30
|
+
- Linux: `xdg-open memray-flamegraph-script.py.<pid>.html`
|
|
31
|
+
- Either: `python -m webbrowser memray-flamegraph-script.py.<pid>.html`
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- The `--temporal` flag (included in `memray-flame`) shows memory over time, not just peak — use this to spot leaks and allocation bursts.
|
|
36
|
+
- To find the `.bin` file if unsure of the name: `ls memray-*.bin`
|
|
37
|
+
- To compare runs, save the previous report: `cp memray-flamegraph-script.py.<pid>.html memray-flamegraph-before.html`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: profimp
|
|
3
|
+
description: Profile Python import time using profimp and open a waterfall HTML report. Use when investigating slow startup or wanting to identify which imports are most expensive.
|
|
4
|
+
compatibility: Requires profimp (available as a pixi dependency). macOS or Linux.
|
|
5
|
+
allowed-tools: Bash(profimp:*) Bash(open:*) Bash(xdg-open:*) Bash(python -m webbrowser:*)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
|
|
10
|
+
1. Ask what to profile. Suggest common patterns for this repo:
|
|
11
|
+
- `import spatialdata`
|
|
12
|
+
- `from spatialdata import SpatialData`
|
|
13
|
+
- `from spatialdata_io import xenium`
|
|
14
|
+
|
|
15
|
+
2. Run:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
profimp --html "<import_stmt>" > /tmp/profimp.html
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
3. Open the report:
|
|
22
|
+
- macOS: `open /tmp/profimp.html`
|
|
23
|
+
- Linux: `xdg-open /tmp/profimp.html`
|
|
24
|
+
- Either: `python -m webbrowser /tmp/profimp.html`
|
|
25
|
+
|
|
26
|
+
## Notes
|
|
27
|
+
|
|
28
|
+
- The report is a waterfall chart showing every sub-import and its timing.
|
|
29
|
+
- To compare before/after: `cp /tmp/profimp.html /tmp/profimp-before.html` before re-running.
|
|
30
|
+
- `pixi run python -m profimp` also works if `profimp` is not on PATH.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pyspy
|
|
3
|
+
description: Profile the execution time of a Python script using py-spy and visualize the result with speedscope. Use when the user wants to benchmark performance, find slow code paths, or profile CPU time.
|
|
4
|
+
compatibility: Requires the pixi profiling environment (pixi run -e profiling). Speedscope must be installed separately (npm install -g speedscope). sudo is required on macOS.
|
|
5
|
+
allowed-tools: Bash(pixi run -e profiling pyspy:*) Bash(pixi run -e profiling speedscope:*) Bash(sudo pixi run -e profiling pyspy:*)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
|
|
10
|
+
1. Ask the user which script to profile (full or relative path).
|
|
11
|
+
|
|
12
|
+
2. Run py-spy to record the profile. The output is always written to `profile.speedscope.json` in the current directory.
|
|
13
|
+
|
|
14
|
+
**Linux** (no sudo needed):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pixi run -e profiling pyspy script.py
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**macOS** (sudo required — py-spy needs to attach to the process):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
sudo pixi run -e profiling pyspy script.py
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If sudo fails to find the pixi environment, use absolute paths:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
sudo /path/to/.pixi/envs/profiling/bin/py-spy record --gil \
|
|
30
|
+
-o profile.speedscope.json --format speedscope \
|
|
31
|
+
-- /path/to/.pixi/envs/profiling/bin/python script.py
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
3. Open the result in speedscope:
|
|
35
|
+
```bash
|
|
36
|
+
pixi run -e profiling speedscope
|
|
37
|
+
```
|
|
38
|
+
This opens `profile.speedscope.json` in the browser via the local speedscope CLI.
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- If the speedscope view is blank, switch threads using the thread selector in the top-right corner.
|
|
43
|
+
- To save a profile before overwriting: `cp profile.speedscope.json profile-before.speedscope.json`
|
|
44
|
+
- `--gil` records only time when the GIL is held (Python-level CPU time). Drop it to include C extension time.
|
|
45
|
+
- speedscope must be installed globally: `npm install -g speedscope`
|
|
@@ -19,12 +19,13 @@ jobs:
|
|
|
19
19
|
fail-fast: false
|
|
20
20
|
matrix:
|
|
21
21
|
include:
|
|
22
|
-
- {os: windows-latest, python: "3.
|
|
23
|
-
- {os: windows-latest, python: "3.
|
|
24
|
-
- {os: ubuntu-latest, python: "3.
|
|
25
|
-
- {os: ubuntu-latest, python: "3.13", dask-version: "latest"
|
|
26
|
-
- {os:
|
|
27
|
-
- {os: macos-latest, python: "3.
|
|
22
|
+
- {os: windows-latest, python: "3.12", dask-version: "2026.3.0", name: "min dask"}
|
|
23
|
+
- {os: windows-latest, python: "3.14", dask-version: "latest"}
|
|
24
|
+
- {os: ubuntu-latest, python: "3.12", dask-version: "latest"}
|
|
25
|
+
- {os: ubuntu-latest, python: "3.13", dask-version: "latest"}
|
|
26
|
+
- {os: ubuntu-latest, python: "3.14", dask-version: "latest"}
|
|
27
|
+
- {os: macos-latest, python: "3.12", dask-version: "latest"}
|
|
28
|
+
- {os: macos-latest, python: "3.14", prerelease: "allow", name: "prerelease"}
|
|
28
29
|
env:
|
|
29
30
|
OS: ${{ matrix.os }}
|
|
30
31
|
PYTHON: ${{ matrix.python }}
|
|
@@ -41,7 +42,6 @@ jobs:
|
|
|
41
42
|
- name: Install dependencies
|
|
42
43
|
run: |
|
|
43
44
|
if [[ "${PRERELEASE}" == "allow" ]]; then
|
|
44
|
-
sed -i '' 's/requires-python.*//' pyproject.toml # otherwise uv complains that anndata requires python>=3.12 and we only do >=3.11 😱
|
|
45
45
|
uv add git+https://github.com/scverse/anndata.git
|
|
46
46
|
uv add pandas>=3.dev0
|
|
47
47
|
fi
|
|
@@ -59,7 +59,7 @@ jobs:
|
|
|
59
59
|
PLATFORM: ${{ matrix.os }}
|
|
60
60
|
DISPLAY: :42
|
|
61
61
|
run: |
|
|
62
|
-
uv run pytest --cov --color=yes --cov-report=xml
|
|
62
|
+
uv run pytest --cov --color=yes --cov-report=xml -n auto --dist worksteal
|
|
63
63
|
- name: Upload coverage to Codecov
|
|
64
64
|
uses: codecov/codecov-action@v5
|
|
65
65
|
with:
|
|
@@ -46,11 +46,18 @@ spatialdata-sandbox
|
|
|
46
46
|
# version file
|
|
47
47
|
_version.py
|
|
48
48
|
|
|
49
|
-
#
|
|
50
|
-
|
|
49
|
+
# agents configurations
|
|
50
|
+
.claude/settings.local.json
|
|
51
51
|
|
|
52
|
+
# benchmarking and profiling
|
|
52
53
|
.asv/
|
|
54
|
+
profile.speedscope.json
|
|
55
|
+
|
|
56
|
+
# other
|
|
57
|
+
node_modules/
|
|
53
58
|
|
|
54
59
|
.mypy_cache
|
|
55
60
|
.ruff_cache
|
|
56
61
|
uv.lock
|
|
62
|
+
pixi.lock
|
|
63
|
+
|
|
@@ -9,18 +9,18 @@ ci:
|
|
|
9
9
|
skip: []
|
|
10
10
|
repos:
|
|
11
11
|
- repo: https://github.com/rbubley/mirrors-prettier
|
|
12
|
-
rev: v3.8.
|
|
12
|
+
rev: v3.8.4
|
|
13
13
|
hooks:
|
|
14
14
|
- id: prettier
|
|
15
15
|
exclude: ^.github/workflows/test.yaml
|
|
16
16
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
17
|
-
rev:
|
|
17
|
+
rev: v2.1.0
|
|
18
18
|
hooks:
|
|
19
19
|
- id: mypy
|
|
20
20
|
additional_dependencies: [numpy, types-requests]
|
|
21
21
|
exclude: tests/|docs/
|
|
22
22
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
23
|
-
rev: v0.15.
|
|
23
|
+
rev: v0.15.18
|
|
24
24
|
hooks:
|
|
25
25
|
- id: ruff
|
|
26
26
|
args: [--fix, --exit-non-zero-on-fix]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spatialdata
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Spatial data format.
|
|
5
5
|
Project-URL: Documentation, https://spatialdata.scverse.org/en/latest
|
|
6
6
|
Project-URL: Source, https://github.com/scverse/spatialdata.git
|
|
@@ -37,21 +37,21 @@ License: BSD 3-Clause License
|
|
|
37
37
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
38
38
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
39
39
|
License-File: LICENSE
|
|
40
|
-
Requires-Python: >=3.
|
|
41
|
-
Requires-Dist: anndata>=0.
|
|
40
|
+
Requires-Python: >=3.12
|
|
41
|
+
Requires-Dist: anndata>=0.9.1
|
|
42
42
|
Requires-Dist: annsel>=0.1.2
|
|
43
43
|
Requires-Dist: click
|
|
44
44
|
Requires-Dist: dask-image
|
|
45
|
-
Requires-Dist: dask
|
|
45
|
+
Requires-Dist: dask>=2026.3.0
|
|
46
46
|
Requires-Dist: datashader
|
|
47
|
-
Requires-Dist: distributed
|
|
47
|
+
Requires-Dist: distributed>=2026.3.0
|
|
48
48
|
Requires-Dist: fsspec[http,s3]
|
|
49
49
|
Requires-Dist: geopandas>=0.14
|
|
50
50
|
Requires-Dist: multiscale-spatial-image==2.0.3
|
|
51
51
|
Requires-Dist: networkx
|
|
52
52
|
Requires-Dist: numba>=0.55.0
|
|
53
53
|
Requires-Dist: numpy
|
|
54
|
-
Requires-Dist: ome-zarr>=0.
|
|
54
|
+
Requires-Dist: ome-zarr>=0.16.0
|
|
55
55
|
Requires-Dist: pandas
|
|
56
56
|
Requires-Dist: pooch
|
|
57
57
|
Requires-Dist: pyarrow
|
|
@@ -82,7 +82,7 @@ Description-Content-Type: text/markdown
|
|
|
82
82
|
[](https://results.pre-commit.ci/latest/github/scverse/spatialdata/main)
|
|
83
83
|
[](https://codecov.io/gh/scverse/spatialdata)
|
|
84
84
|
[](https://spatialdata.scverse.org/en/latest/)
|
|
85
|
-
[](https://doi.org/10.5281/zenodo.20056407)
|
|
86
86
|
[](https://pepy.tech/project/spatialdata)
|
|
87
87
|
[](https://github.com/scverse/spatialdata/actions/workflows/release.yaml)
|
|
88
88
|
[![Documentation][badge-pypi]][link-pypi]
|
|
@@ -91,11 +91,15 @@ Description-Content-Type: text/markdown
|
|
|
91
91
|
[badge-pypi]: https://badge.fury.io/py/spatialdata.svg
|
|
92
92
|
[link-pypi]: https://pypi.org/project/spatialdata/
|
|
93
93
|
|
|
94
|
-
SpatialData is a data framework
|
|
94
|
+
SpatialData is a data framework, a schema and a serialization format for uni- and multi-modal spatial omics datasets. It is supported by a growing suite of software libraries for performant access, manipulation and analysis in multiple languages, including Python, R and JavaScript.
|
|
95
|
+
|
|
96
|
+
This repository contains the core spatialdata library. See the links below to learn more about other packages in the SpatialData ecosystem.
|
|
95
97
|
|
|
96
98
|
- [spatialdata-io](https://github.com/scverse/spatialdata-io): load data from common spatial omics technologies into spatialdata.
|
|
97
99
|
- [spatialdata-plot](https://github.com/scverse/spatialdata-plot): Static plotting library for spatialdata.
|
|
98
100
|
- [napari-spatialdata](https://github.com/scverse/napari-spatialdata): napari plugin for interactive exploration and annotation of spatial data.
|
|
101
|
+
- [SpatialData (R)](https://github.com/HelenaLC/SpatialData): R implementation of the SpatialData framework.
|
|
102
|
+
- [SpatialData.js](https://github.com/Taylor-CCB-Group/SpatialData.js): JavaScript/TypeScript implementation of the SpatialData framework.
|
|
99
103
|
|
|
100
104
|
[//]: # "numfocus-fiscal-sponsor-attribution"
|
|
101
105
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://results.pre-commit.ci/latest/github/scverse/spatialdata/main)
|
|
7
7
|
[](https://codecov.io/gh/scverse/spatialdata)
|
|
8
8
|
[](https://spatialdata.scverse.org/en/latest/)
|
|
9
|
-
[](https://doi.org/10.5281/zenodo.20056407)
|
|
10
10
|
[](https://pepy.tech/project/spatialdata)
|
|
11
11
|
[](https://github.com/scverse/spatialdata/actions/workflows/release.yaml)
|
|
12
12
|
[![Documentation][badge-pypi]][link-pypi]
|
|
@@ -15,11 +15,15 @@
|
|
|
15
15
|
[badge-pypi]: https://badge.fury.io/py/spatialdata.svg
|
|
16
16
|
[link-pypi]: https://pypi.org/project/spatialdata/
|
|
17
17
|
|
|
18
|
-
SpatialData is a data framework
|
|
18
|
+
SpatialData is a data framework, a schema and a serialization format for uni- and multi-modal spatial omics datasets. It is supported by a growing suite of software libraries for performant access, manipulation and analysis in multiple languages, including Python, R and JavaScript.
|
|
19
|
+
|
|
20
|
+
This repository contains the core spatialdata library. See the links below to learn more about other packages in the SpatialData ecosystem.
|
|
19
21
|
|
|
20
22
|
- [spatialdata-io](https://github.com/scverse/spatialdata-io): load data from common spatial omics technologies into spatialdata.
|
|
21
23
|
- [spatialdata-plot](https://github.com/scverse/spatialdata-plot): Static plotting library for spatialdata.
|
|
22
24
|
- [napari-spatialdata](https://github.com/scverse/napari-spatialdata): napari plugin for interactive exploration and annotation of spatial data.
|
|
25
|
+
- [SpatialData (R)](https://github.com/HelenaLC/SpatialData): R implementation of the SpatialData framework.
|
|
26
|
+
- [SpatialData.js](https://github.com/Taylor-CCB-Group/SpatialData.js): JavaScript/TypeScript implementation of the SpatialData framework.
|
|
23
27
|
|
|
24
28
|
[//]: # "numfocus-fiscal-sponsor-attribution"
|
|
25
29
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.8.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 8, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -65,6 +65,32 @@ git checkout - && git stash pop
|
|
|
65
65
|
asv compare main HEAD
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
### Dataloader benchmarks
|
|
69
|
+
|
|
70
|
+
Dataloader benchmarks live in `benchmarks/benchmark_dataloader.py`. They use a synthetic in-memory `SpatialData` (2048×2048 image, 500 circle regions) and compute two metrics:
|
|
71
|
+
|
|
72
|
+
- `time_init` — constructing `ImageTilesDataset` (includes bounding-box pre-computation).
|
|
73
|
+
- `time_fetch` — iterating over all 500 tiles once (pure `__getitem__` calls, no `DataLoader` overhead).
|
|
74
|
+
|
|
75
|
+
Run both in your current environment:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
asv run --python=same --show-stderr -b TimeDataloader
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Or a single method:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
asv run --python=same --show-stderr -b TimeDataloader.time_init
|
|
85
|
+
asv run --python=same --show-stderr -b TimeDataloader.time_fetch
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Compare against `main` in one shot:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
asv continuous --show-stderr -v -b TimeDataloader main HEAD
|
|
92
|
+
```
|
|
93
|
+
|
|
68
94
|
### Querying benchmarks
|
|
69
95
|
|
|
70
96
|
Querying using a bounding box without a spatial index is highly impacted by large amounts of points (transcripts), more than table rows (cells).
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# type: ignore
|
|
2
|
+
"""Benchmarks for ImageTilesDataset: init time and iteration time."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import anndata as ad
|
|
7
|
+
import geopandas as gpd
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
10
|
+
from shapely.geometry import Point
|
|
11
|
+
|
|
12
|
+
import spatialdata as sd
|
|
13
|
+
from spatialdata.dataloader import ImageTilesDataset
|
|
14
|
+
from spatialdata.models import Image2DModel, ShapesModel, TableModel
|
|
15
|
+
from spatialdata.transformations import Identity
|
|
16
|
+
|
|
17
|
+
_RNG = np.random.default_rng(42)
|
|
18
|
+
|
|
19
|
+
_IMAGE_SIZE = 2048
|
|
20
|
+
_N_CIRCLES = 500
|
|
21
|
+
_N_CHANNELS = 3
|
|
22
|
+
|
|
23
|
+
_DATASET_KWARGS = {
|
|
24
|
+
"regions_to_images": {"circles": "image"},
|
|
25
|
+
"regions_to_coordinate_systems": {"circles": "global"},
|
|
26
|
+
"table_name": "table",
|
|
27
|
+
"return_annotations": "instance_id",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _make_sdata() -> sd.SpatialData:
|
|
32
|
+
img_data = _RNG.integers(0, 256, size=(_N_CHANNELS, _IMAGE_SIZE, _IMAGE_SIZE), dtype=np.uint8).astype(np.float32)
|
|
33
|
+
image = Image2DModel.parse(img_data, dims=["c", "y", "x"], transformations={"global": Identity()})
|
|
34
|
+
|
|
35
|
+
radius = 32.0
|
|
36
|
+
cx = _RNG.uniform(radius, _IMAGE_SIZE - radius, size=_N_CIRCLES)
|
|
37
|
+
cy = _RNG.uniform(radius, _IMAGE_SIZE - radius, size=_N_CIRCLES)
|
|
38
|
+
geom = gpd.GeoDataFrame({"geometry": [Point(x, y) for x, y in zip(cx, cy, strict=True)]})
|
|
39
|
+
geom["radius"] = radius
|
|
40
|
+
circles = ShapesModel.parse(geom, transformations={"global": Identity()})
|
|
41
|
+
|
|
42
|
+
table = ad.AnnData(
|
|
43
|
+
_RNG.random((_N_CIRCLES, 10)).astype(np.float32),
|
|
44
|
+
obs=pd.DataFrame(
|
|
45
|
+
{
|
|
46
|
+
"region": pd.Categorical(["circles"] * _N_CIRCLES),
|
|
47
|
+
"instance_id": np.arange(_N_CIRCLES, dtype=np.int64),
|
|
48
|
+
},
|
|
49
|
+
index=[str(i) for i in range(_N_CIRCLES)],
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
table = TableModel.parse(table, region="circles", region_key="region", instance_key="instance_id")
|
|
53
|
+
|
|
54
|
+
return sd.SpatialData(images={"image": image}, shapes={"circles": circles}, tables={"table": table})
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TimeDataloader:
|
|
58
|
+
"""Time ImageTilesDataset construction and tile iteration."""
|
|
59
|
+
|
|
60
|
+
def setup(self):
|
|
61
|
+
self.sdata = _make_sdata()
|
|
62
|
+
self.ds = ImageTilesDataset(sdata=self.sdata, **_DATASET_KWARGS)
|
|
63
|
+
|
|
64
|
+
def teardown(self):
|
|
65
|
+
del self.ds
|
|
66
|
+
del self.sdata
|
|
67
|
+
|
|
68
|
+
def time_init(self):
|
|
69
|
+
"""Time constructing ImageTilesDataset (bounding-box pre-computation)."""
|
|
70
|
+
ImageTilesDataset(sdata=self.sdata, **_DATASET_KWARGS)
|
|
71
|
+
|
|
72
|
+
def time_fetch(self):
|
|
73
|
+
"""Time iterating over every tile once."""
|
|
74
|
+
for i in range(len(self.ds)):
|
|
75
|
+
_ = self.ds[i]
|
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
# An open and universal framework for processing spatial omics data.
|
|
8
8
|
|
|
9
|
-
SpatialData is a data framework
|
|
9
|
+
SpatialData is a data framework, a schema and a serialization format for uni- and multi-modal spatial omics datasets. It is supported by a growing suite of software libraries for performant access, manipulation and analysis in multiple languages, including Python, R and JavaScript.
|
|
10
|
+
|
|
11
|
+
This page provides documentation on how to install, use, and extend the core `spatialdata` library. See the links below to learn more about other packages in the SpatialData ecosystem.
|
|
10
12
|
|
|
11
13
|
- `spatialdata-io`: load data from common spatial omics technologies into `spatialdata` ([repository][spatialdata-io-repo], [documentation][spatialdata-io-docs]).
|
|
12
14
|
- `spatialdata-plot`: Static plotting library for `spatialdata` ([repository][spatialdata-plot-repo], [documentation][spatialdata-plot-docs]).
|
|
13
15
|
- `napari-spatialdata-repo`: napari plugin for interactive exploration and annotation of `spatialdata` ([repository][napari-spatialdata-repo], [documentation][napari-spatialdata-docs]).
|
|
16
|
+
- `SpatialData` (R): R implementation of the SpatialData framework ([repository][spatialdata-r-repo]).
|
|
17
|
+
- `SpatialData.js`: JavaScript/TypeScript implementation of the SpatialData framework ([repository][spatialdata-js-repo]).
|
|
14
18
|
|
|
15
19
|
Please see our publication {cite}`marconatoSpatialDataOpenUniversal2024` for citation and to learn more.
|
|
16
20
|
|
|
@@ -119,3 +123,5 @@ references.md
|
|
|
119
123
|
[napari-spatialdata-docs]: https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html
|
|
120
124
|
[spatialdata-io-docs]: https://spatialdata.scverse.org/projects/io/en/stable/
|
|
121
125
|
[spatialdata-plot-docs]: https://spatialdata.scverse.org/projects/plot/en/stable/api.html
|
|
126
|
+
[spatialdata-r-repo]: https://github.com/HelenaLC/SpatialData
|
|
127
|
+
[spatialdata-js-repo]: https://github.com/Taylor-CCB-Group/SpatialData.js
|
|
@@ -15,19 +15,19 @@ maintainers = [
|
|
|
15
15
|
urls.Documentation = "https://spatialdata.scverse.org/en/latest"
|
|
16
16
|
urls.Source = "https://github.com/scverse/spatialdata.git"
|
|
17
17
|
urls.Home-page = "https://github.com/scverse/spatialdata.git"
|
|
18
|
-
requires-python = ">=3.
|
|
18
|
+
requires-python = ">=3.12"
|
|
19
19
|
dynamic= [
|
|
20
20
|
"version" # allow version to be set by git tags
|
|
21
21
|
]
|
|
22
22
|
license = {file = "LICENSE"}
|
|
23
23
|
readme = "README.md"
|
|
24
24
|
dependencies = [
|
|
25
|
-
"anndata>=0.
|
|
25
|
+
"anndata>=0.9.1",
|
|
26
26
|
"annsel>=0.1.2",
|
|
27
27
|
"click",
|
|
28
28
|
"dask-image",
|
|
29
|
-
"dask>=
|
|
30
|
-
"distributed
|
|
29
|
+
"dask>=2026.3.0",
|
|
30
|
+
"distributed>=2026.3.0",
|
|
31
31
|
"datashader",
|
|
32
32
|
"fsspec[s3,http]",
|
|
33
33
|
"geopandas>=0.14",
|
|
@@ -35,7 +35,7 @@ dependencies = [
|
|
|
35
35
|
"networkx",
|
|
36
36
|
"numba>=0.55.0",
|
|
37
37
|
"numpy",
|
|
38
|
-
"ome_zarr>=0.
|
|
38
|
+
"ome_zarr>=0.16.0",
|
|
39
39
|
"pandas",
|
|
40
40
|
"pooch",
|
|
41
41
|
"pyarrow",
|
|
@@ -69,6 +69,7 @@ test = [
|
|
|
69
69
|
"pytest",
|
|
70
70
|
"pytest-cov",
|
|
71
71
|
"pytest-mock",
|
|
72
|
+
"pytest-xdist",
|
|
72
73
|
"torch",
|
|
73
74
|
]
|
|
74
75
|
docs = [
|
|
@@ -102,6 +103,7 @@ strict = true
|
|
|
102
103
|
addopts = [
|
|
103
104
|
"--import-mode=importlib", # allow using test files with same name
|
|
104
105
|
"-s", # print output from tests
|
|
106
|
+
"-p no:napari", # napari registers a pytest plugin via its entry point; disable it here since spatialdata tests don't need it
|
|
105
107
|
]
|
|
106
108
|
# These are all markers coming from xarray, dask or anndata. Added here to silence warnings.
|
|
107
109
|
markers = [
|
|
@@ -143,7 +145,7 @@ exclude = [
|
|
|
143
145
|
|
|
144
146
|
]
|
|
145
147
|
line-length = 120
|
|
146
|
-
target-version = "
|
|
148
|
+
target-version = "py312"
|
|
147
149
|
|
|
148
150
|
[tool.ruff.lint]
|
|
149
151
|
ignore = [
|
|
@@ -208,3 +210,37 @@ convention = "numpy"
|
|
|
208
210
|
|
|
209
211
|
# pyupgrade typing rewrite TODO: remove at some point from per-file ignore
|
|
210
212
|
# "UP006", "UP007"
|
|
213
|
+
|
|
214
|
+
[tool.pixi.workspace]
|
|
215
|
+
channels = ["conda-forge"]
|
|
216
|
+
platforms = ["osx-arm64", "linux-64"]
|
|
217
|
+
|
|
218
|
+
[tool.pixi.dependencies]
|
|
219
|
+
proj = "*"
|
|
220
|
+
|
|
221
|
+
[tool.pixi.tasks]
|
|
222
|
+
test = "pytest"
|
|
223
|
+
test-parallel = "pytest -n auto --dist worksteal"
|
|
224
|
+
pre-commit = "pre-commit run"
|
|
225
|
+
pre-commit-all = "pre-commit run --all-files"
|
|
226
|
+
|
|
227
|
+
[tool.pixi.feature.profiling.dependencies]
|
|
228
|
+
py-spy = "*"
|
|
229
|
+
|
|
230
|
+
[tool.pixi.feature.profiling.pypi-dependencies]
|
|
231
|
+
spatialdata = { path = ".", editable = true }
|
|
232
|
+
profimp = "*"
|
|
233
|
+
memray = "*"
|
|
234
|
+
|
|
235
|
+
[tool.pixi.feature.profiling.tasks]
|
|
236
|
+
# Usage: pixi run -e profiling pyspy script.py (prefix with sudo on macOS)
|
|
237
|
+
pyspy = "py-spy record --gil -o profile.speedscope.json --format speedscope -- python"
|
|
238
|
+
# Usage: pixi run -e profiling speedscope
|
|
239
|
+
speedscope = "npx --yes speedscope profile.speedscope.json"
|
|
240
|
+
# Usage: pixi run -e profiling memray-run script.py
|
|
241
|
+
memray-run = "memray run"
|
|
242
|
+
# Usage: pixi run -e profiling memray-flame memray-script.py.<pid>.bin
|
|
243
|
+
memray-flame = "memray flamegraph --temporal"
|
|
244
|
+
|
|
245
|
+
[tool.pixi.environments]
|
|
246
|
+
profiling = { features = ["profiling"], solve-group = "default" }
|
|
@@ -21,7 +21,6 @@ from spatialdata.models import (
|
|
|
21
21
|
PointsModel,
|
|
22
22
|
ShapesModel,
|
|
23
23
|
TableModel,
|
|
24
|
-
get_axes_names,
|
|
25
24
|
get_model,
|
|
26
25
|
)
|
|
27
26
|
|
|
@@ -50,6 +49,7 @@ class Elements(UserDict[str, T]):
|
|
|
50
49
|
raise KeyError(*e.args) from e
|
|
51
50
|
|
|
52
51
|
def __setitem__(self, key: str, value: T) -> None:
|
|
52
|
+
# note that each __setitem__ in the subclasses calls get_model(), which performs data validation
|
|
53
53
|
self._add_shared_key(key)
|
|
54
54
|
super().__setitem__(key, value)
|
|
55
55
|
|
|
@@ -72,15 +72,7 @@ class Images(Elements[DataArray | DataTree]):
|
|
|
72
72
|
schema = get_model(value)
|
|
73
73
|
if schema not in (Image2DModel, Image3DModel):
|
|
74
74
|
raise TypeError(f"Unknown element type with schema: {schema!r}.")
|
|
75
|
-
|
|
76
|
-
if ndim == 3:
|
|
77
|
-
Image2DModel.validate(value)
|
|
78
|
-
super().__setitem__(key, value)
|
|
79
|
-
elif ndim == 4:
|
|
80
|
-
Image3DModel.validate(value)
|
|
81
|
-
super().__setitem__(key, value)
|
|
82
|
-
else:
|
|
83
|
-
NotImplementedError("TODO: implement for ndim > 4.")
|
|
75
|
+
super().__setitem__(key, value)
|
|
84
76
|
|
|
85
77
|
|
|
86
78
|
class Labels(Elements[DataArray | DataTree]):
|
|
@@ -89,15 +81,7 @@ class Labels(Elements[DataArray | DataTree]):
|
|
|
89
81
|
schema = get_model(value)
|
|
90
82
|
if schema not in (Labels2DModel, Labels3DModel):
|
|
91
83
|
raise TypeError(f"Unknown element type with schema: {schema!r}.")
|
|
92
|
-
|
|
93
|
-
if ndim == 2:
|
|
94
|
-
Labels2DModel.validate(value)
|
|
95
|
-
super().__setitem__(key, value)
|
|
96
|
-
elif ndim == 3:
|
|
97
|
-
Labels3DModel.validate(value)
|
|
98
|
-
super().__setitem__(key, value)
|
|
99
|
-
else:
|
|
100
|
-
NotImplementedError("TODO: implement for ndim > 3.")
|
|
84
|
+
super().__setitem__(key, value)
|
|
101
85
|
|
|
102
86
|
|
|
103
87
|
class Shapes(Elements[GeoDataFrame]):
|
|
@@ -106,7 +90,6 @@ class Shapes(Elements[GeoDataFrame]):
|
|
|
106
90
|
schema = get_model(value)
|
|
107
91
|
if schema != ShapesModel:
|
|
108
92
|
raise TypeError(f"Unknown element type with schema: {schema!r}.")
|
|
109
|
-
ShapesModel.validate(value)
|
|
110
93
|
super().__setitem__(key, value)
|
|
111
94
|
|
|
112
95
|
|
|
@@ -116,7 +99,6 @@ class Points(Elements[DaskDataFrame]):
|
|
|
116
99
|
schema = get_model(value)
|
|
117
100
|
if schema != PointsModel:
|
|
118
101
|
raise TypeError(f"Unknown element type with schema: {schema!r}.")
|
|
119
|
-
PointsModel.validate(value)
|
|
120
102
|
super().__setitem__(key, value)
|
|
121
103
|
|
|
122
104
|
|
|
@@ -126,5 +108,4 @@ class Tables(Elements[AnnData]):
|
|
|
126
108
|
schema = get_model(value)
|
|
127
109
|
if schema != TableModel:
|
|
128
110
|
raise TypeError(f"Unknown element type with schema: {schema!r}.")
|
|
129
|
-
TableModel.validate(value)
|
|
130
111
|
super().__setitem__(key, value)
|
|
@@ -158,9 +158,9 @@ def sanitize_table(data: AnnData, inplace: bool = True) -> AnnData | None:
|
|
|
158
158
|
# Handle other attributes
|
|
159
159
|
for attr in ("obsm", "obsp", "varm", "varp", "uns", "layers"):
|
|
160
160
|
d = getattr(sanitized, attr)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
new_dict = {new_keys[old]: value for old, value in d.items()}
|
|
161
|
+
# None is a valid key in layers (anndata >= 0.13: represents X); skip sanitizing it
|
|
162
|
+
new_keys = {old: get_unique_name(old, attr) for old in d if old is not None}
|
|
163
|
+
new_dict = {(new_keys[old] if old is not None else old): value for old, value in d.items()}
|
|
164
164
|
setattr(sanitized, attr, new_dict)
|
|
165
165
|
|
|
166
166
|
return None if inplace else sanitized
|