Coverage for python/lsst/daf/butler/core/json.py: 52%

27 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-10-02 08:00 +0000

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/>. 

27 

28from __future__ import annotations 

29 

30__all__ = ("to_json_generic", "from_json_generic", "to_json_pydantic", "from_json_pydantic") 

31 

32import json 

33from typing import TYPE_CHECKING, Any, Protocol, Type 

34 

35if TYPE_CHECKING: 

36 from ..registry import Registry 

37 from .dimensions import DimensionUniverse 

38 

39 

40class SupportsSimple(Protocol): 

41 """Protocol defining the methods required to support the standard 

42 serialization using "simple" methods names. 

43 """ 

44 

45 _serializedType: Type 

46 

47 def to_simple(self, minimal: bool) -> Any: 

48 ... 

49 

50 @classmethod 

51 def from_simple( 

52 cls, simple: Any, universe: DimensionUniverse | None = None, registry: Registry | None = None 

53 ) -> SupportsSimple: 

54 ... 

55 

56 

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. 

60 

61 """ 

62 return self.to_simple(minimal=minimal).model_dump_json(exclude_defaults=True, exclude_unset=True) 

63 

64 

65def from_json_pydantic( 

66 cls: type[SupportsSimple], 

67 json_str: str, 

68 universe: DimensionUniverse | None = None, 

69 registry: Registry | None = None, 

70) -> SupportsSimple: 

71 """Convert from JSON to a pydantic model.""" 

72 simple = cls._serializedType.model_validate_json(json_str) 

73 try: 

74 return cls.from_simple(simple, universe=universe, registry=registry) 

75 except AttributeError as e: 

76 raise AttributeError(f"JSON deserialization requires {cls} has a from_simple() class method") from e 

77 

78 

79def to_json_generic(self: SupportsSimple, minimal: bool = False) -> str: 

80 """Convert this class to JSON form. 

81 

82 The class type is not recorded in the JSON so the JSON decoder 

83 must know which class is represented. 

84 

85 Parameters 

86 ---------- 

87 minimal : `bool`, optional 

88 Use minimal serialization. Requires Registry to convert 

89 back to a full type. 

90 

91 Returns 

92 ------- 

93 json : `str` 

94 The class in JSON string format. 

95 """ 

96 # For now use the core json library to convert a dict to JSON 

97 # for us. 

98 return json.dumps(self.to_simple(minimal=minimal)) 

99 

100 

101def from_json_generic( 

102 cls: type[SupportsSimple], 

103 json_str: str, 

104 universe: DimensionUniverse | None = None, 

105 registry: Registry | None = None, 

106) -> SupportsSimple: 

107 """Return new class from JSON string. 

108 

109 Converts a JSON string created by `to_json` and return 

110 something of the supplied class. 

111 

112 Parameters 

113 ---------- 

114 json_str : `str` 

115 Representation of the dimensions in JSON format as created 

116 by `to_json()`. 

117 universe : `DimensionUniverse`, optional 

118 The special graph of all known dimensions. Passed directly 

119 to `from_simple()`. 

120 registry : `lsst.daf.butler.Registry`, optional 

121 Registry to use to convert simple name of a DatasetType to 

122 a full `DatasetType`. Passed directly to `from_simple()`. 

123 

124 Returns 

125 ------- 

126 constructed : Any 

127 Newly-constructed object. 

128 """ 

129 simple = json.loads(json_str) 

130 try: 

131 return cls.from_simple(simple, universe=universe, registry=registry) 

132 except AttributeError as e: 

133 raise AttributeError(f"JSON deserialization requires {cls} has a from_simple() class method") from e