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

30 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-22 02:05 -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 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 <http://www.gnu.org/licenses/>. 

21 

22from __future__ import annotations 

23 

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

25 

26import json 

27from typing import TYPE_CHECKING, Any, Optional, Protocol, Type 

28 

29if TYPE_CHECKING: 29 ↛ 30line 29 didn't jump to line 30, because the condition on line 29 was never true

30 from ..registry import Registry 

31 from .dimensions import DimensionUniverse 

32 

33 

34class SupportsSimple(Protocol): 

35 _serializedType: Type 

36 

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

38 ... 

39 

40 @classmethod 

41 def from_simple( 

42 cls, simple: Any, universe: Optional[DimensionUniverse] = None, registry: Optional[Registry] = None 

43 ) -> SupportsSimple: 

44 ... 

45 

46 

47def to_json_pydantic(self: SupportsSimple, minimal: bool = False) -> str: 

48 """Convert this class to JSON assuming that the ``to_simple()`` returns 

49 a pydantic model. 

50 

51 """ 

52 return self.to_simple(minimal=minimal).json(exclude_defaults=True, exclude_unset=True) 

53 

54 

55def from_json_pydantic( 

56 cls: Type[SupportsSimple], 

57 json_str: str, 

58 universe: Optional[DimensionUniverse] = None, 

59 registry: Optional[Registry] = None, 

60) -> SupportsSimple: 

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

62 simple = cls._serializedType.parse_raw(json_str) 

63 try: 

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

65 except AttributeError as e: 

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

67 

68 

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

70 """Convert this class to JSON form. 

71 

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

73 must know which class is represented. 

74 

75 Parameters 

76 ---------- 

77 minimal : `bool`, optional 

78 Use minimal serialization. Requires Registry to convert 

79 back to a full type. 

80 

81 Returns 

82 ------- 

83 json : `str` 

84 The class in JSON string format. 

85 """ 

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

87 # for us. 

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

89 

90 

91def from_json_generic( 

92 cls: Type[SupportsSimple], 

93 json_str: str, 

94 universe: Optional[DimensionUniverse] = None, 

95 registry: Optional[Registry] = None, 

96) -> SupportsSimple: 

97 """Return new class from JSON string. 

98 

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

100 something of the supplied class. 

101 

102 Parameters 

103 ---------- 

104 json_str : `str` 

105 Representation of the dimensions in JSON format as created 

106 by `to_json()`. 

107 universe : `DimensionUniverse`, optional 

108 The special graph of all known dimensions. Passed directly 

109 to `from_simple()`. 

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

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

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

113 

114 Returns 

115 ------- 

116 constructed : Any 

117 Newly-constructed object. 

118 """ 

119 simple = json.loads(json_str) 

120 try: 

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

122 except AttributeError as e: 

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