Coverage for python/lsst/daf/butler/json.py: 53%
25 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-26 02:48 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-26 02:48 -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, Protocol, Type
35if TYPE_CHECKING:
36 from .dimensions import DimensionUniverse
37 from .registry import Registry
40class SupportsSimple(Protocol):
41 """Protocol defining the methods required to support the standard
42 serialization using "simple" methods names.
43 """
45 _serializedType: Type
47 def to_simple(self, minimal: bool) -> Any: ... 47 ↛ exitline 47 didn't jump to line 47, because
49 @classmethod
50 def from_simple( 50 ↛ exitline 50 didn't jump to the function exit
51 cls, simple: Any, universe: DimensionUniverse | None = None, registry: Registry | None = None
52 ) -> SupportsSimple: ...
55def to_json_pydantic(self: SupportsSimple, minimal: bool = False) -> str:
56 """Convert this class to JSON assuming that the ``to_simple()`` returns
57 a pydantic model.
59 Parameters
60 ----------
61 minimal : `bool`
62 Return minimal possible representation.
63 """
64 return self.to_simple(minimal=minimal).model_dump_json(exclude_defaults=True, exclude_unset=True)
67def from_json_pydantic(
68 cls_: type[SupportsSimple],
69 json_str: str,
70 universe: DimensionUniverse | None = None,
71 registry: Registry | None = None,
72) -> SupportsSimple:
73 """Convert from JSON to a pydantic model.
75 Parameters
76 ----------
77 cls_ : `type` of `SupportsSimple`
78 The Python type being created.
79 json_str : `str`
80 The JSON string representing this object.
81 universe : `DimensionUniverse` or `None`, optional
82 The universe required to instantiate some models. Required if
83 ``registry`` is `None`.
84 registry : `Registry` or `None`, optional
85 Registry from which to obtain the dimension universe if an explicit
86 universe has not been given.
88 Returns
89 -------
90 model : `SupportsSimple`
91 Pydantic model constructed from JSON and validated.
92 """
93 simple = cls_._serializedType.model_validate_json(json_str)
94 try:
95 return cls_.from_simple(simple, universe=universe, registry=registry)
96 except AttributeError as e:
97 raise AttributeError(f"JSON deserialization requires {cls_} has a from_simple() class method") from e
100def to_json_generic(self: SupportsSimple, minimal: bool = False) -> str:
101 """Convert this class to JSON form.
103 The class type is not recorded in the JSON so the JSON decoder
104 must know which class is represented.
106 Parameters
107 ----------
108 minimal : `bool`, optional
109 Use minimal serialization. Requires Registry to convert
110 back to a full type.
112 Returns
113 -------
114 json : `str`
115 The class in JSON string format.
116 """
117 # For now use the core json library to convert a dict to JSON
118 # for us.
119 return json.dumps(self.to_simple(minimal=minimal))
122def from_json_generic(
123 cls: type[SupportsSimple],
124 json_str: str,
125 universe: DimensionUniverse | None = None,
126 registry: Registry | None = None,
127) -> SupportsSimple:
128 """Return new class from JSON string.
130 Converts a JSON string created by `to_json` and return
131 something of the supplied class.
133 Parameters
134 ----------
135 json_str : `str`
136 Representation of the dimensions in JSON format as created
137 by `to_json()`.
138 universe : `DimensionUniverse`, optional
139 The special graph of all known dimensions. Passed directly
140 to `from_simple()`.
141 registry : `lsst.daf.butler.Registry`, optional
142 Registry to use to convert simple name of a DatasetType to
143 a full `DatasetType`. Passed directly to `from_simple()`.
145 Returns
146 -------
147 constructed : Any
148 Newly-constructed object.
149 """
150 simple = json.loads(json_str)
151 try:
152 return cls.from_simple(simple, universe=universe, registry=registry)
153 except AttributeError as e:
154 raise AttributeError(f"JSON deserialization requires {cls} has a from_simple() class method") from e