thyra 3.7.2__tar.gz → 3.7.3__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.
- {thyra-3.7.2 → thyra-3.7.3}/.gitignore +2 -0
- {thyra-3.7.2 → thyra-3.7.3}/PKG-INFO +2 -1
- {thyra-3.7.2 → thyra-3.7.3}/README.md +1 -0
- {thyra-3.7.2 → thyra-3.7.3}/pyproject.toml +1 -1
- {thyra-3.7.2 → thyra-3.7.3}/thyra/__init__.py +1 -1
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/base_spatialdata_converter.py +55 -3
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/__init__.py +4 -0
- thyra-3.7.3/thyra/metadata/uns_compat.py +57 -0
- {thyra-3.7.2 → thyra-3.7.3}/LICENSE +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/__main__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/alignment/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/alignment/affine.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/alignment/teaching_points.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/config.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/convert.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/_chunking.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/converter.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/spatialdata_2d_converter.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/spatialdata_3d_converter.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/converters/spatialdata/streaming_converter.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/core/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/core/base_converter.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/core/base_extractor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/core/base_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/core/registry.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/extractors/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/extractors/bruker_extractor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/extractors/imzml_extractor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/extractors/phi_extractor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/extractors/waters_extractor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/ontology/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/ontology/_ims.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/ontology/_ms.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/ontology/_uo.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/ontology/cache.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/builder.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/cli.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/generate.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/metaspace.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/models.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/msi_metadata.linkml.yaml +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/msi_metadata_schema_v0_1.json +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/store_io.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/validate.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/schema/vocab.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/types.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/metadata/validator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/preview.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/base_bruker_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/folder_structure.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/mis_parser.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/rapiflex/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/rapiflex/rapiflex_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/dll/LICENCE-BRUKER.txt +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/dll/README.md +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/dll/timsdata.dll +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/dll/timsdata.so +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/dll_manager.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/platform_detector.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/sdk/sdk_functions.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/timstof_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/utils/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/utils/batch_processor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/utils/coordinate_cache.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/utils/mass_axis_builder.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/bruker/timstof/utils/memory_manager.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/imzml/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/imzml/imzml_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/phi/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/phi/event_stream.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/phi/mass_axis.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/phi/phi_header.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/phi/phi_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/imaging_grid.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/lib/MLReader.dll +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/lib/MassLynxRaw.dll +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/lib/libMLReader.so +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/lib/libMassLynxRaw.so +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/masslynx_lib.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/readers/waters/waters_reader.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/common_axis.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/constants.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/data_characteristics.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/decision_tree.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/gaps.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/instrument_detectors.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/base_generator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/fticr_generator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/linear_generator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/linear_tof_generator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/orbitrap_generator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/mass_axis/reflector_tof_generator.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/strategies/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/strategies/base.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/strategies/nearest_neighbor.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/strategies/tic_preserving.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/tic.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/resampling/types.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/tools/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/tools/check_ontology.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/tools/make_example_data.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/utils/__init__.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/utils/bruker_exceptions.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/utils/logging_config.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/utils/pyimzml_direct.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/utils/windows_paths.py +0 -0
- {thyra-3.7.2 → thyra-3.7.3}/thyra/utils/zarr_atomic_write.py +0 -0
|
@@ -53,6 +53,8 @@ Archive/
|
|
|
53
53
|
# ...except documentation notebooks, which are published as part of the docs
|
|
54
54
|
# site and must be committed with their outputs.
|
|
55
55
|
!docs/*.ipynb
|
|
56
|
+
# ...and the shared workflow notebooks (e.g. the Colab validation workflow).
|
|
57
|
+
!notebooks/*.ipynb
|
|
56
58
|
|
|
57
59
|
# Temporary files
|
|
58
60
|
temp_*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: thyra
|
|
3
|
-
Version: 3.7.
|
|
3
|
+
Version: 3.7.3
|
|
4
4
|
Summary: A modern Python library for converting Mass Spectrometry Imaging (MSI) data into SpatialData/Zarr format - your portal to spatial omics
|
|
5
5
|
Project-URL: Homepage, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra
|
|
6
6
|
Project-URL: Repository, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra
|
|
@@ -60,6 +60,7 @@ Description-Content-Type: text/markdown
|
|
|
60
60
|
[](https://opensource.org/licenses/MIT)
|
|
61
61
|
[](https://github.com/psf/black)
|
|
62
62
|
[](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra)
|
|
63
|
+
[](https://colab.research.google.com/github/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/notebooks/Thyra_Validation_Workflow.ipynb)
|
|
63
64
|
|
|
64
65
|
**Thyra** (from Greek thyra, meaning "door" or "portal") -- a modern Python library for converting Mass Spectrometry Imaging (MSI) data into the standardized **SpatialData/Zarr format**, serving as your portal to spatial omics analysis workflows.
|
|
65
66
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://github.com/psf/black)
|
|
10
10
|
[](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra)
|
|
11
|
+
[](https://colab.research.google.com/github/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/notebooks/Thyra_Validation_Workflow.ipynb)
|
|
11
12
|
|
|
12
13
|
**Thyra** (from Greek thyra, meaning "door" or "portal") -- a modern Python library for converting Mass Spectrometry Imaging (MSI) data into the standardized **SpatialData/Zarr format**, serving as your portal to spatial omics analysis workflows.
|
|
13
14
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "thyra"
|
|
7
|
-
version = "3.7.
|
|
7
|
+
version = "3.7.3"
|
|
8
8
|
description = "A modern Python library for converting Mass Spectrometry Imaging (MSI) data into SpatialData/Zarr format - your portal to spatial omics"
|
|
9
9
|
authors = [{ name = "Theodoros Visvikis", email = "t.visvikis@maastrichtuniversity.nl" }]
|
|
10
10
|
maintainers = [{ name = "Theodoros Visvikis", email = "t.visvikis@maastrichtuniversity.nl" }]
|
|
@@ -46,6 +46,49 @@ def _suppress_upstream_warnings():
|
|
|
46
46
|
yield
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
def _numeric_only(value: Any) -> bool:
|
|
50
|
+
"""True when a list round-trips through AnnData/zarr as a numeric array."""
|
|
51
|
+
if isinstance(value, list):
|
|
52
|
+
return all(_numeric_only(item) for item in value)
|
|
53
|
+
if isinstance(value, np.ndarray):
|
|
54
|
+
return value.dtype.kind in "iufb"
|
|
55
|
+
return isinstance(value, (bool, int, float, np.integer, np.floating, np.bool_))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _json_fallback(obj: Any) -> Any:
|
|
59
|
+
"""Last-resort encoder for values ``json.dumps`` does not know."""
|
|
60
|
+
if isinstance(obj, np.ndarray):
|
|
61
|
+
return obj.tolist()
|
|
62
|
+
if isinstance(obj, np.generic):
|
|
63
|
+
return obj.item()
|
|
64
|
+
return str(obj)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _jsonify_string_lists(obj: Any) -> Any:
|
|
68
|
+
"""Replace any list that is not purely numeric with its JSON encoding.
|
|
69
|
+
|
|
70
|
+
AnnData/zarr cannot round-trip such lists: a list of dicts is
|
|
71
|
+
stringified entry by entry into Python ``repr`` strings, and any list
|
|
72
|
+
of strings comes back as a numpy string array -- whose ``deepcopy``
|
|
73
|
+
segfaults outright on numpy 2.1-2.2 (numpy#28609). Since every table
|
|
74
|
+
copy deepcopies ``uns`` (``AnnData.copy``, spatial queries, joins),
|
|
75
|
+
one such array in ``uns`` kills the reader's process with no
|
|
76
|
+
traceback. JSON side-steps both: it stores a single scalar string,
|
|
77
|
+
and hands consumers the actual structure back through
|
|
78
|
+
``json.loads`` instead of ``repr`` output.
|
|
79
|
+
|
|
80
|
+
Purely numeric lists (nested included) are kept: they become plain
|
|
81
|
+
numeric arrays, which are safe and more useful as arrays.
|
|
82
|
+
"""
|
|
83
|
+
if isinstance(obj, dict):
|
|
84
|
+
return {key: _jsonify_string_lists(value) for key, value in obj.items()}
|
|
85
|
+
if isinstance(obj, list):
|
|
86
|
+
if _numeric_only(obj):
|
|
87
|
+
return obj
|
|
88
|
+
return json.dumps(obj, default=_json_fallback)
|
|
89
|
+
return obj
|
|
90
|
+
|
|
91
|
+
|
|
49
92
|
def _resolve_config_enum(raw: Any, by_name: Dict[str, Any], key: str) -> Any:
|
|
50
93
|
"""Resolve one resampling-config value to its enum member.
|
|
51
94
|
|
|
@@ -792,15 +835,24 @@ class BaseSpatialDataConverter(BaseMSIConverter, ABC):
|
|
|
792
835
|
}
|
|
793
836
|
|
|
794
837
|
def _collect_optional_sections(self, uns: Dict[str, Any], comp_meta: Any) -> None:
|
|
795
|
-
"""Add the vendor sections the reader actually populated.
|
|
838
|
+
"""Add the vendor sections the reader actually populated.
|
|
839
|
+
|
|
840
|
+
Lists that are not purely numeric (imzML ``cvParams``, or any
|
|
841
|
+
string list a vendor extractor reports) are stored as JSON
|
|
842
|
+
strings -- see :func:`_jsonify_string_lists` for why letting
|
|
843
|
+
them reach the writer as lists corrupts them and crashes
|
|
844
|
+
readers on numpy 2.1-2.2.
|
|
845
|
+
"""
|
|
796
846
|
for key in ("format_specific", "acquisition_params", "instrument_info"):
|
|
797
847
|
value = getattr(comp_meta, key, None)
|
|
798
848
|
if value:
|
|
799
|
-
uns[key] = self._serialize_for_zarr(value)
|
|
849
|
+
uns[key] = _jsonify_string_lists(self._serialize_for_zarr(value))
|
|
800
850
|
|
|
801
851
|
raw_metadata = getattr(comp_meta, "raw_metadata", None)
|
|
802
852
|
if raw_metadata:
|
|
803
|
-
uns["raw_metadata"] =
|
|
853
|
+
uns["raw_metadata"] = _jsonify_string_lists(
|
|
854
|
+
self._serialize_for_zarr(raw_metadata)
|
|
855
|
+
)
|
|
804
856
|
|
|
805
857
|
def _collect_region_info(self, uns: Dict[str, Any]) -> None:
|
|
806
858
|
"""Add the acquisition region summary as JSON.
|
|
@@ -53,6 +53,9 @@ from .extractors import (
|
|
|
53
53
|
# Core data types
|
|
54
54
|
from .types import ComprehensiveMetadata, EssentialMetadata
|
|
55
55
|
|
|
56
|
+
# Read-side compatibility for stores written by earlier versions
|
|
57
|
+
from .uns_compat import sanitize_uns_string_arrays
|
|
58
|
+
|
|
56
59
|
# Base classes - import delayed to avoid circular imports
|
|
57
60
|
|
|
58
61
|
|
|
@@ -67,6 +70,7 @@ __all__ = [
|
|
|
67
70
|
# Utility functions
|
|
68
71
|
"get_extractor_for_format",
|
|
69
72
|
"list_supported_formats",
|
|
73
|
+
"sanitize_uns_string_arrays",
|
|
70
74
|
]
|
|
71
75
|
|
|
72
76
|
# Version information for the metadata system
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# thyra/metadata/uns_compat.py
|
|
2
|
+
"""Read-side defense for ``uns`` blocks written by earlier Thyra versions.
|
|
3
|
+
|
|
4
|
+
Stores written before the JSON rule in
|
|
5
|
+
``BaseSpatialDataConverter._collect_optional_sections`` carry string
|
|
6
|
+
lists in ``uns`` (notably ``raw_metadata["cvParams"]``) that materialize
|
|
7
|
+
as numpy ``StringDType`` arrays when read back through AnnData/zarr.
|
|
8
|
+
``copy.deepcopy`` of such an array segfaults the process on numpy
|
|
9
|
+
2.1.x-2.2.x (numpy#28609, fixed in 2.3.0) -- and every table copy
|
|
10
|
+
deepcopies ``uns``: ``AnnData.copy``, ``spatialdata.polygon_query``,
|
|
11
|
+
``bounding_box_query``, and the join paths behind them.
|
|
12
|
+
|
|
13
|
+
New stores no longer contain these arrays. This module exists for
|
|
14
|
+
already-written stores read in an environment pinned to the affected
|
|
15
|
+
numpy range.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from collections.abc import Mapping
|
|
19
|
+
from typing import Any, Dict
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
__all__ = ["sanitize_uns_string_arrays"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def sanitize_uns_string_arrays(uns: Mapping[str, Any]) -> Dict[str, Any]:
|
|
27
|
+
"""Return ``uns`` with numpy string arrays replaced by plain lists.
|
|
28
|
+
|
|
29
|
+
Recurses through nested dicts and lists; every other value is kept
|
|
30
|
+
as-is, so the result is safe to assign straight back::
|
|
31
|
+
|
|
32
|
+
import spatialdata as sd
|
|
33
|
+
from thyra.metadata import sanitize_uns_string_arrays
|
|
34
|
+
|
|
35
|
+
sdata = sd.read_zarr("store.zarr")
|
|
36
|
+
for table in sdata.tables.values():
|
|
37
|
+
table.uns = sanitize_uns_string_arrays(table.uns)
|
|
38
|
+
|
|
39
|
+
Needed only for stores written by Thyra versions that stored string
|
|
40
|
+
lists in ``uns`` as arrays, read under numpy 2.1.x-2.2.x, where
|
|
41
|
+
deepcopying a ``StringDType`` array kills the process (see module
|
|
42
|
+
docstring). Calling it anywhere else is harmless.
|
|
43
|
+
"""
|
|
44
|
+
return {key: _sanitize(value) for key, value in uns.items()}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _sanitize(value: Any) -> Any:
|
|
48
|
+
if isinstance(value, Mapping):
|
|
49
|
+
return {key: _sanitize(item) for key, item in value.items()}
|
|
50
|
+
if isinstance(value, list):
|
|
51
|
+
return [_sanitize(item) for item in value]
|
|
52
|
+
# ``kind == "T"`` is StringDType, the one dtype whose deepcopy is
|
|
53
|
+
# broken. On numpy builds without StringDType no array has this
|
|
54
|
+
# kind, so the walk is a no-op there.
|
|
55
|
+
if isinstance(value, np.ndarray) and value.dtype.kind == "T":
|
|
56
|
+
return value.tolist()
|
|
57
|
+
return value
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|