Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of astro_metadata_translator. 

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 LICENSE file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12"""Represent a collection of translated headers""" 

13 

14__all__ = ("ObservationGroup",) 

15 

16import logging 

17from collections.abc import MutableSequence 

18 

19from .observationInfo import ObservationInfo 

20 

21log = logging.getLogger(__name__) 

22 

23 

24class ObservationGroup(MutableSequence): 

25 """A collection of `ObservationInfo` headers. 

26 

27 Parameters 

28 ---------- 

29 members : iterable of `ObservationInfo` or `dict`-like 

30 `ObservationInfo` to seed the group membership. If `dict`-like 

31 values are used they will be passed to the `ObservationInfo` 

32 constructor. 

33 translator_class : `MetadataTranslator`-class, optional 

34 If any of the members is not an `ObservationInfo`, translator class 

35 to pass to the `ObservationInfo` constructor. If `None` the 

36 translation class will be determined automatically. 

37 pedantic : `bool`, optional 

38 If any of the members is not an `ObservationInfo`, passed to the 

39 `ObservationInfo` constructor to control whether 

40 a failed translation is fatal or not. `None` indicates that the 

41 `ObservationInfo` constructor default should be used. 

42 """ 

43 

44 def __init__(self, members, translator_class=None, pedantic=None): 

45 self._members = [self._coerce_value(m, translator_class=translator_class, pedantic=pedantic) 

46 for m in members] 

47 

48 # Cache of members in time order 

49 self._sorted = None 

50 

51 def __len__(self): 

52 return len(self._members) 

53 

54 def __delitem__(self, index): 

55 del self._members[index] 

56 self._sorted = None 

57 

58 def __getitem__(self, index): 

59 return self._members[index] 

60 

61 def __str__(self): 

62 results = [] 

63 for obs_info in self._members: 

64 results.append(f"({obs_info.instrument}, {obs_info.datetime_begin})") 

65 return "[" + ", ".join(results) + "]" 

66 

67 def _coerce_value(self, value, translator_class=None, pedantic=None): 

68 """Given a value, ensure it is an `ObservationInfo`. 

69 

70 Parameters 

71 ---------- 

72 value : `ObservationInfo` or `dict`-like 

73 Either an `ObservationInfo` or something that can be passed to 

74 an `ObservationInfo` constructor. 

75 translator_class : `MetadataTranslator`-class, optional 

76 If value is not an `ObservationInfo`, translator class to pass to 

77 the `ObservationInfo` constructor. If `None` the 

78 translation class will be determined automatically. 

79 pedantic : `bool`, optional 

80 If value is not an `ObservationInfo`, passed to the 

81 `ObservationInfo` constructor to control whether 

82 a failed translation is fatal or not. `None` indicates that the 

83 `ObservationInfo` constructor default should be used. 

84 

85 Raises 

86 ------ 

87 ValueError 

88 Raised if supplied value is not an `ObservationInfo` and can 

89 not be turned into one. 

90 """ 

91 if value is None: 

92 raise ValueError("An ObservationGroup cannot contain 'None'") 

93 

94 if not isinstance(value, ObservationInfo): 

95 try: 

96 kwargs = {"translator_class": translator_class} 

97 if pedantic is not None: 

98 kwargs["pedantic"] = pedantic 

99 value = ObservationInfo(value, **kwargs) 

100 except Exception as e: 

101 raise ValueError("Could not convert value to ObservationInfo") from e 

102 

103 return value 

104 

105 def __iter__(self): 

106 return iter(self._members) 

107 

108 def __eq__(self, other): 

109 """Compares equal if all the members are equal in the same order. 

110 """ 

111 for info1, info2 in zip(self, other): 

112 if info1 != info2: 

113 return False 

114 return True 

115 

116 def __setitem__(self, index, value): 

117 """Store item in group. 

118 

119 Item must be an `ObservationInfo` or something that can be passed 

120 to an `ObservationInfo` constructor. 

121 """ 

122 value = self._coerce_value(value) 

123 self._members[index] = value 

124 self._sorted = None 

125 

126 def insert(self, index, value): 

127 value = self._coerce_value(value) 

128 self._members.insert(index, value) 

129 self._sorted = None 

130 

131 def reverse(self): 

132 self._members.reverse() 

133 

134 def sort(self, key=None, reverse=False): 

135 self._members.sort(key=key, reverse=reverse) 

136 if key is None and not reverse and self._sorted is None: 

137 # Store sorted order in cache 

138 self._sorted = self._members.copy() 

139 

140 def extremes(self): 

141 """Return the oldest observation in the group and the newest. 

142 

143 If there is only one member of the group, the newest and oldest 

144 can be the same observation. 

145 

146 Returns 

147 ------- 

148 oldest : `ObservationInfo` 

149 Oldest observation. 

150 newest : `ObservationInfo` 

151 Newest observation. 

152 """ 

153 if self._sorted is None: 

154 self._sorted = sorted(self._members) 

155 return self._sorted[0], self._sorted[-1] 

156 

157 def newest(self): 

158 """Return the newest observation in the group. 

159 

160 Returns 

161 ------- 

162 newest : `ObservationInfo` 

163 The newest `ObservationInfo` in the `ObservationGroup`. 

164 """ 

165 return self.extremes()[1] 

166 

167 def oldest(self): 

168 """Return the oldest observation in the group. 

169 

170 Returns 

171 ------- 

172 oldest : `ObservationInfo` 

173 The oldest `ObservationInfo` in the `ObservationGroup`. 

174 """ 

175 return self.extremes()[0] 

176 

177 def property_values(self, property): 

178 """Return a set of values associated with the specified property. 

179 

180 Parameters 

181 ---------- 

182 property : `str` 

183 Property of an `ObservationInfo` 

184 

185 Returns 

186 ------- 

187 values : `set` 

188 All the distinct values for that property within this group. 

189 """ 

190 return {getattr(obs_info, property) for obs_info in self}