Coverage for python/lsst/meas/extensions/scarlet/io/model_data.py: 42%
40 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-21 01:42 -0800
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-21 01:42 -0800
1# This file is part of meas_extensions_scarlet.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22from __future__ import annotations
24from typing import Any
26import numpy as np
27from numpy.typing import DTypeLike
29import lsst.scarlet.lite as scl
31from .source_data import IsolatedSourceData
33CURRENT_SCHEMA = "1.0.0"
34SCARLET_LITE_SCHEMA = "1.0.0"
35MODEL_TYPE = "lsst"
36scl.io.migration.MigrationRegistry.set_current(MODEL_TYPE, CURRENT_SCHEMA)
38# Ensure that the ScarletModelData from scarlet lite hasn't changed.
39if scl.io.model_data.CURRENT_SCHEMA != SCARLET_LITE_SCHEMA: 39 ↛ 40line 39 didn't jump to line 40 because the condition on line 39 was never true
40 raise RuntimeError(
41 "Version mismatch between meas_extensions_scarlet and scarlet lite. "
42 "This requires updating SCARLET_LITE_SCHEMA, CURRENT_SCHEMA, and a migration step "
43 f"to match the ScarletModelData schema version {scl.io.model_data.CURRENT_SCHEMA}."
44 )
47class LsstScarletModelData(scl.io.ScarletModelData):
48 """A ScarletModelData that includes isolated sources.
50 Attributes
51 ----------
52 isolated : dict[int, IsolatedSourceData]
53 A mapping of isolated source IDs to their data.
54 version : dict[int, scl.io.ScarletBlendBaseData]
55 The schema version of the serialized data.
56 """
57 isolated: dict[int, IsolatedSourceData]
58 version: str = CURRENT_SCHEMA
60 def __init__(
61 self,
62 isolated: dict[int, IsolatedSourceData] | None = None,
63 blends: dict[int, scl.io.ScarletBlendBaseData] | None = None,
64 metadata: dict[str, Any] | None = None,
65 ):
66 super().__init__(blends=blends, metadata=metadata)
67 self.isolated = isolated if isolated is not None else {}
69 def as_dict(self) -> dict[str, Any]:
70 """Convert to a dictionary for serialization
72 Returns
73 -------
74 result : dict[str, Any]
75 The object encoded as a JSON-compatible dictionary.
76 """
77 data = super().as_dict()
78 # Ensure that the we are not trying to serialize with an
79 # incompatible schema.
80 if data["version"] != SCARLET_LITE_SCHEMA:
81 raise RuntimeError(
82 f"Cannot serialize scarlet model with schema {data['version']}, "
83 f"expected {SCARLET_LITE_SCHEMA}. "
84 "This requires updating SCARLET_LITE_SCHEMA, CURRENT_SCHEMA, and a migration step."
85 )
86 data.update(
87 {
88 "isolated": {k: v.as_dict() for k, v in self.isolated.items()},
89 "version": self.version,
90 }
91 )
92 return data
94 @classmethod
95 def from_dict(cls, data: dict, dtype: DTypeLike = np.float32) -> LsstScarletModelData:
96 """Reconstruct `LsstScarletModelData` from JSON compatible dict.
98 Parameters
99 ----------
100 data : dict
101 Dictionary representation of the object
102 dtype : DTypeLike
103 Datatype of the resulting model.
105 Returns
106 -------
107 result : LsstScarletModelData
108 The reconstructed object
109 """
110 data = scl.io.migration.MigrationRegistry.migrate(MODEL_TYPE, data)
111 isolated: dict[int, IsolatedSourceData] = {}
112 for sid, source_data in data.get("isolated", {}).items():
113 isolated[int(sid)] = IsolatedSourceData.from_dict(source_data, dtype=dtype)
114 if "metadata" not in data:
115 data["metadata"] = None
116 return super().from_dict(data, dtype=dtype, isolated=isolated)
119@scl.io.migration.migration(MODEL_TYPE, scl.io.migration.PRE_SCHEMA)
120def _to_1_0_0(data: dict) -> dict:
121 """Migrate a pre-schema model to schema version 1.0.0
123 There were no changes to this data model in v1.0.0 but we need
124 to provide a way to migrate pre-schema data.
126 Parameters
127 ----------
128 data : dict
129 The data to migrate.
130 Returns
131 -------
132 result : dict
133 The migrated data.
134 """
135 # Ensure that the model type and version are set and add an
136 # empty isolated sources dictionary.
137 if "model_type" not in data:
138 data["model_type"] = MODEL_TYPE
139 data["isolated"] = {}
140 data["version"] = "1.0.0"
141 return data