Coverage for python/lsst/daf/butler/json.py: 55%
26 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-11 03:16 -0700
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-11 03:16 -0700
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://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 software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28from __future__ import annotations
30__all__ = ("to_json_generic", "from_json_generic", "to_json_pydantic", "from_json_pydantic")
32import json
33from typing import TYPE_CHECKING, Any, ClassVar, Protocol
35from pydantic import BaseModel
37if TYPE_CHECKING:
38 from .dimensions import DimensionUniverse
39 from .registry import Registry
42class SupportsSimple(Protocol):
43 """Protocol defining the methods required to support the standard
44 serialization using "simple" methods names.
45 """
47 _serializedType: ClassVar[type[BaseModel]]
49 def to_simple(self, minimal: bool) -> Any: ... 49 ↛ exitline 49 didn't jump to line 49, because
51 @classmethod
52 def from_simple( 52 ↛ exitline 52 didn't jump to the function exit
53 cls, simple: Any, universe: DimensionUniverse | None = None, registry: Registry | None = None
54 ) -> SupportsSimple: ...
57def to_json_pydantic(self: SupportsSimple, minimal: bool = False) -> str:
58 """Convert this class to JSON assuming that the ``to_simple()`` returns
59 a pydantic model.
61 Parameters
62 ----------
63 minimal : `bool`
64 Return minimal possible representation.
65 """
66 return self.to_simple(minimal=minimal).model_dump_json(exclude_defaults=True, exclude_unset=True)
69def from_json_pydantic(
70 cls_: type[SupportsSimple],
71 json_str: str,
72 universe: DimensionUniverse | None = None,
73 registry: Registry | None = None,
74) -> SupportsSimple:
75 """Convert from JSON to a pydantic model.
77 Parameters
78 ----------
79 cls_ : `type` of `SupportsSimple`
80 The Python type being created.
81 json_str : `str`
82 The JSON string representing this object.
83 universe : `DimensionUniverse` or `None`, optional
84 The universe required to instantiate some models. Required if
85 ``registry`` is `None`.
86 registry : `Registry` or `None`, optional
87 Registry from which to obtain the dimension universe if an explicit
88 universe has not been given.
90 Returns
91 -------
92 model : `SupportsSimple`
93 Pydantic model constructed from JSON and validated.
94 """
95 simple = cls_._serializedType.model_validate_json(json_str)
96 try:
97 return cls_.from_simple(simple, universe=universe, registry=registry)
98 except AttributeError as e:
99 raise AttributeError(f"JSON deserialization requires {cls_} has a from_simple() class method") from e
102def to_json_generic(self: SupportsSimple, minimal: bool = False) -> str:
103 """Convert this class to JSON form.
105 The class type is not recorded in the JSON so the JSON decoder
106 must know which class is represented.
108 Parameters
109 ----------
110 minimal : `bool`, optional
111 Use minimal serialization. Requires Registry to convert
112 back to a full type.
114 Returns
115 -------
116 json : `str`
117 The class in JSON string format.
118 """
119 # For now use the core json library to convert a dict to JSON
120 # for us.
121 return json.dumps(self.to_simple(minimal=minimal))
124def from_json_generic(
125 cls: type[SupportsSimple],
126 json_str: str,
127 universe: DimensionUniverse | None = None,
128 registry: Registry | None = None,
129) -> SupportsSimple:
130 """Return new class from JSON string.
132 Converts a JSON string created by `to_json` and return
133 something of the supplied class.
135 Parameters
136 ----------
137 json_str : `str`
138 Representation of the dimensions in JSON format as created
139 by `to_json()`.
140 universe : `DimensionUniverse`, optional
141 The special graph of all known dimensions. Passed directly
142 to `from_simple()`.
143 registry : `lsst.daf.butler.Registry`, optional
144 Registry to use to convert simple name of a DatasetType to
145 a full `DatasetType`. Passed directly to `from_simple()`.
147 Returns
148 -------
149 constructed : Any
150 Newly-constructed object.
151 """
152 simple = json.loads(json_str)
153 try:
154 return cls.from_simple(simple, universe=universe, registry=registry)
155 except AttributeError as e:
156 raise AttributeError(f"JSON deserialization requires {cls} has a from_simple() class method") from e