Coverage for python / lsst / images / serialization / _common.py: 88%
41 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-14 08:07 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-14 08:07 +0000
1# This file is part of lsst-images.
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# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
12from __future__ import annotations
14__all__ = (
15 "ArchiveReadError",
16 "ArchiveTree",
17 "ButlerInfo",
18 "JsonRef",
19 "MetadataValue",
20 "OpaqueArchiveMetadata",
21 "ReadResult",
22 "no_header_updates",
23)
25import operator
26from abc import ABC, abstractmethod
27from typing import TYPE_CHECKING, Any, NamedTuple, Protocol, Self
29import astropy.table
30import astropy.units
31import pydantic
33from .._geom import Box
34from ..utils import is_none
36try:
37 from lsst.daf.butler import DatasetProvenance, SerializedDatasetRef
38except ImportError:
39 type DatasetProvenance = Any # type: ignore[no-redef]
40 type SerializedDatasetRef = Any # type: ignore[no-redef]
42if TYPE_CHECKING:
43 import astropy.io.fits
45 from ._input_archive import InputArchive
48type MetadataValue = (
49 pydantic.StrictInt | pydantic.StrictFloat | pydantic.StrictStr | pydantic.StrictBool | None
50)
53class ButlerInfo(pydantic.BaseModel):
54 """Information about a butler dataset."""
56 dataset: SerializedDatasetRef
57 provenance: DatasetProvenance = pydantic.Field(default_factory=DatasetProvenance)
60class JsonRef(pydantic.BaseModel, serialize_by_alias=True):
61 """Pydantic model for JSON Reference / Pointer (IETF RFC 6901).
63 Notes
64 -----
65 This model does not do any of the escaping or special-character
66 interpretation required by the spec; it assumes that's already been done,
67 so its job is *just* putting a ``$ref`` field inside another model.
68 """
70 ref: str = pydantic.Field(alias="$ref")
73class ArchiveTree(
74 pydantic.BaseModel, ABC, ser_json_inf_nan="constants", ser_json_bytes="base64", val_json_bytes="base64"
75):
76 """An intermediate base class of `pydantic.BaseModel` that should be used
77 for all objects that may be used as the top-level tree models written to
78 archives.
79 """
81 metadata: dict[str, MetadataValue] = pydantic.Field(
82 default_factory=dict, description="Additional unstructured metadata.", exclude_if=operator.not_
83 )
84 butler_info: ButlerInfo | None = pydantic.Field(
85 default=None,
86 description="Information about the butler dataset backed by this file.",
87 exclude_if=is_none,
88 )
89 indirect: list[Any] = pydantic.Field(
90 default_factory=list,
91 description="Serialized nested objects that may be saved or read more than once.",
92 exclude_if=operator.not_,
93 )
95 @abstractmethod
96 def deserialize(self, archive: InputArchive[Any]) -> Any:
97 """Return the in-memory object that was serialized to this tree."""
98 raise NotImplementedError()
101class ReadResult[T: Any](NamedTuple):
102 """A struct that can be used to return both a deserialized object and
103 metadata associated with it, even when the in-memory type cannot hold
104 metadata.
105 """
107 deserialized: T
108 """The deserialized object itself."""
110 metadata: dict[str, MetadataValue]
111 """Additional flexible metadata stored with the object."""
113 butler_info: ButlerInfo | None
114 """Butler provenance information for the dataset this file backs."""
117class ArchiveReadError(RuntimeError):
118 """Exception raised when the contents of an archive cannot be read."""
121class OpaqueArchiveMetadata(Protocol):
122 """Interface for opaque archive metadata.
124 In addition to implementing the methods defined here, all implementations
125 must be pickleable.
126 """
128 def copy(self) -> Self | None:
129 """Copy, reference, or discard metadata when its holding object is
130 copied.
131 """
132 ...
134 def subset(self, bbox: Box) -> Self | None:
135 """Copy, reference, or discard metadata when a subset of its its
136 holding object is extracted.
137 """
138 ...
141def no_header_updates(header: astropy.io.fits.Header) -> None:
142 """Do not make any modifications to the given FITS header."""