Coverage for python/lsst/afw/table/_schemaMapper.py: 22%

44 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-13 16:27 -0700

1# This file is part of afw. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://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 <https://www.gnu.org/licenses/>. 

21 

22__all__ = [] # import only for the side effects 

23 

24import lsst.pex.exceptions 

25from lsst.utils import continueClass 

26 

27from ._schema import Field, Schema 

28from ._table import SchemaMapper 

29 

30 

31@continueClass 

32class SchemaMapper: # noqa: F811 

33 

34 def addOutputField(self, field, type=None, doc=None, units="", size=None, 

35 doReplace=False, parse_strict="raise"): 

36 """Add an un-mapped field to the output Schema. 

37 

38 Parameters 

39 ---------- 

40 field : `str` or `~lsst.afw.table.Field` 

41 The string name of the `Field`, or a fully-constructed 

42 `Field` object. If the latter, all other arguments 

43 besides doReplace are ignored. 

44 type : `str` 

45 The type of field to create. Valid types are the keys of the 

46 afw.table.Field dictionary. 

47 doc : `str` 

48 Documentation for the field. 

49 unit : `str` 

50 Units for the field, or an empty string if unitless. 

51 size : `int` 

52 Size of the field; valid for string and array fields only. 

53 doReplace : `bool` 

54 If a field with this name already exists, replace it instead of 

55 raising pex.exceptions.InvalidParameterError. 

56 parse_strict : `str` 

57 One of 'raise' (default), 'warn', or 'strict', indicating how to 

58 handle unrecognized unit strings. See also astropy.units.Unit. 

59 

60 Returns 

61 ------- 

62 key : `~lsst.afw.table.Key` 

63 The key of the field added. 

64 """ 

65 if isinstance(field, str): 

66 field = Field[type](field, doc=doc, units=units, 

67 size=size, parse_strict=parse_strict) 

68 return field._addTo(self.editOutputSchema(), doReplace) 

69 

70 def addMapping(self, input, output=None, doReplace=True): 

71 """Add a mapped field to the output schema. 

72 

73 Parameters 

74 ---------- 

75 input : `~lsst.afw.table.Key` 

76 A `Key` from the input schema whose values will be mapped to the new 

77 field. 

78 output : `str` or `~lsst.afw.table.Field` 

79 A `Field` object that describes the new field to be added to the 

80 output schema, or the name of the field (with documentation and 

81 units copied from the input schema). May be None to copy everything 

82 from the input schema. 

83 doReplace : `bool` 

84 If a field with this name already exists in the output schema, 

85 replace it instead of raising `pex.exceptions.InvalidParameterError`. 

86 

87 Returns 

88 ------- 

89 key : `~lsst.afw.table.Key` 

90 The key for the new mapped field. 

91 """ 

92 # Workaround for calling positional arguments; avoids an API change during pybind11 conversion, 

93 # but we should just make that change and encourage using kwargs in the 

94 # future. 

95 if output is True or output is False: 

96 doReplace = output 

97 output = None 

98 return input._addMappingTo(self, output, doReplace) 

99 

100 def __eq__(self, other): 

101 """SchemaMappers are equal if their respective input and output 

102 schemas are identical, and they have the same mappings defined. 

103 

104 Note: It was simpler to implement equality in python than in C++. 

105 """ 

106 iSchema = self.getInputSchema() 

107 oSchema = self.getOutputSchema() 

108 if (not (iSchema.compare(other.getInputSchema(), Schema.IDENTICAL) == Schema.IDENTICAL 

109 and oSchema.compare(other.getOutputSchema(), Schema.IDENTICAL) == Schema.IDENTICAL)): 

110 return False 

111 

112 for item in iSchema: 

113 if self.isMapped(item.key) and other.isMapped(item.key): 

114 if (self.getMapping(item.key) == other.getMapping(item.key)): 

115 continue 

116 else: 

117 return False 

118 elif (not self.isMapped(item.key)) and (not other.isMapped(item.key)): 

119 continue 

120 else: 

121 return False 

122 

123 return True 

124 

125 def __reduce__(self): 

126 """To support pickle.""" 

127 mappings = {} 

128 for item in self.getInputSchema(): 

129 try: 

130 key = self.getMapping(item.key) 

131 except lsst.pex.exceptions.NotFoundError: 

132 # Not all fields may be mapped, so just continue if a mapping is not found. 

133 continue 

134 mappings[item.key] = self.getOutputSchema().find(key).field 

135 return (makeSchemaMapper, (self.getInputSchema(), self.getOutputSchema(), mappings)) 

136 

137 

138def makeSchemaMapper(input, output, mappings): 

139 """Build a mapper from two Schemas and the mapping between them. 

140 For pickle support. 

141 

142 Parameters 

143 ---------- 

144 input : `lsst.afw.table.Schema` 

145 The input schema for the mapper. 

146 output : `lsst.afw.table.Schema` 

147 The output schema for the mapper. 

148 mappings : `dict` [`lsst.afw.table.Key`, `lsst.afw.table.Key`] 

149 The mappings to define between the input and output schema. 

150 

151 Returns 

152 ------- 

153 mapper : `lsst.afw.table.SchemaMapper` 

154 The constructed SchemaMapper. 

155 """ 

156 mapper = SchemaMapper(input, output) 

157 for key, value in mappings.items(): 

158 mapper.addMapping(key, value) 

159 return mapper