Coverage for python / felis / types.py: 91%

44 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-14 23:37 +0000

1"""Define the supported Felis datatypes.""" 

2 

3# This file is part of felis. 

4# 

5# Developed for the LSST Data Management System. 

6# This product includes software developed by the LSST Project 

7# (https://www.lsst.org). 

8# See the COPYRIGHT file at the top-level directory of this distribution 

9# for details of code ownership. 

10# 

11# This program is free software: you can redistribute it and/or modify 

12# it under the terms of the GNU General Public License as published by 

13# the Free Software Foundation, either version 3 of the License, or 

14# (at your option) any later version. 

15# 

16# This program is distributed in the hope that it will be useful, 

17# but WITHOUT ANY WARRANTY; without even the implied warranty of 

18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19# GNU General Public License for more details. 

20# 

21# You should have received a copy of the GNU General Public License 

22# along with this program. If not, see <https://www.gnu.org/licenses/>. 

23 

24from __future__ import annotations 

25 

26from typing import Any 

27 

28__all__ = [ 

29 "Binary", 

30 "Boolean", 

31 "Byte", 

32 "Char", 

33 "Double", 

34 "FelisType", 

35 "Float", 

36 "Int", 

37 "Long", 

38 "Short", 

39 "String", 

40 "Text", 

41 "Timestamp", 

42 "Unicode", 

43] 

44 

45 

46class FelisType: 

47 """Base class for a representation of Felis column types. 

48 

49 Notes 

50 ----- 

51 This class plays a role of a metaclass without being an actual metaclass. 

52 It provides a method to retrieve a class (type) given Felis type name. 

53 There should be no instances of this class (or sub-classes), the utility 

54 of the class hierarchy is in the type system itself. 

55 """ 

56 

57 felis_name: str 

58 """Name of the type as defined in the Felis schema.""" 

59 

60 votable_name: str 

61 """Name of the type as defined in VOTable.""" 

62 

63 is_numeric: bool 

64 """Flag indicating if the type is numeric.""" 

65 

66 is_sized: bool 

67 """Flag indicating if the type is sized, meaning it requires a length.""" 

68 

69 is_timestamp: bool 

70 """Flag indicating if the type is a timestamp.""" 

71 

72 _types: dict[str, type[FelisType]] = {} 

73 """Dictionary of all known Felis types.""" 

74 

75 @classmethod 

76 def __init_subclass__( 

77 cls, 

78 /, 

79 felis_name: str, 

80 votable_name: str, 

81 is_numeric: bool = False, 

82 is_sized: bool = False, 

83 is_timestamp: bool = False, 

84 **kwargs: Any, 

85 ): 

86 """Register a new Felis type. 

87 

88 Parameters 

89 ---------- 

90 felis_name 

91 Name of the type. 

92 votable_name 

93 Name of the type as defined in VOTable. 

94 is_numeric 

95 Flag indicating if the type is numeric. 

96 is_sized 

97 Flag indicating if the type is sized. 

98 is_timestamp 

99 Flag indicating if the type is a timestamp. 

100 kwargs 

101 Additional keyword arguments. 

102 """ 

103 super().__init_subclass__(**kwargs) 

104 cls.felis_name = felis_name 

105 cls.votable_name = votable_name 

106 cls.is_numeric = is_numeric 

107 cls.is_sized = is_sized 

108 cls.is_timestamp = is_timestamp 

109 cls._types[felis_name] = cls 

110 

111 @classmethod 

112 def felis_type(cls, felis_name: str) -> type[FelisType]: 

113 """Return specific Felis type for a given name. 

114 

115 Parameters 

116 ---------- 

117 felis_name 

118 Name of the felis type as defined in felis schema. 

119 

120 Returns 

121 ------- 

122 `type` [ `FelisType` ] 

123 A specific Felis type class. 

124 

125 Raises 

126 ------ 

127 TypeError 

128 Raised if ``felis_name`` does not correspond to a known type. 

129 """ 

130 try: 

131 return cls._types[felis_name] 

132 except KeyError: 

133 raise TypeError(f"Unknown felis type {felis_name!r}") from None 

134 

135 

136class Boolean(FelisType, felis_name="boolean", votable_name="boolean", is_numeric=False): 

137 """Felis definition of boolean type.""" 

138 

139 

140class Byte(FelisType, felis_name="byte", votable_name="unsignedByte", is_numeric=True): 

141 """Felis definition of byte type.""" 

142 

143 

144class Short(FelisType, felis_name="short", votable_name="short", is_numeric=True): 

145 """Felis definition of short integer type.""" 

146 

147 

148class Int(FelisType, felis_name="int", votable_name="int", is_numeric=True): 

149 """Felis definition of integer type.""" 

150 

151 

152class Long(FelisType, felis_name="long", votable_name="long", is_numeric=True): 

153 """Felis definition of long integer type.""" 

154 

155 

156class Float(FelisType, felis_name="float", votable_name="float", is_numeric=True): 

157 """Felis definition of single precision floating point type.""" 

158 

159 

160class Double(FelisType, felis_name="double", votable_name="double", is_numeric=True): 

161 """Felis definition of double precision floating point type.""" 

162 

163 

164class Char(FelisType, felis_name="char", votable_name="char", is_sized=True): 

165 """Felis definition of character type.""" 

166 

167 

168class String(FelisType, felis_name="string", votable_name="char", is_sized=True): 

169 """Felis definition of string type.""" 

170 

171 

172class Unicode(FelisType, felis_name="unicode", votable_name="unicodeChar", is_sized=True): 

173 """Felis definition of unicode string type.""" 

174 

175 

176class Text(FelisType, felis_name="text", votable_name="char"): 

177 """Felis definition of text type.""" 

178 

179 

180class Binary(FelisType, felis_name="binary", votable_name="unsignedByte", is_sized=True): 

181 """Felis definition of binary type.""" 

182 

183 

184class Timestamp(FelisType, felis_name="timestamp", votable_name="char", is_timestamp=True): 

185 """Felis definition of timestamp type."""