Coverage for python/lsst/verify/metaquery.py: 27%

30 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-12-23 01:45 -0800

1# This file is part of verify. 

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__all__ = ['MetadataQuery'] 

22 

23from .jsonmixin import JsonSerializationMixin 

24 

25 

26class MetadataQuery(JsonSerializationMixin): 

27 """Query of `lsst.verify.Job.meta` metadata. 

28 

29 Parameters 

30 ---------- 

31 terms : `dict`, optional 

32 A mapping of key-value query terms. In the default query mode, the 

33 user-provided job metadata must have all these terms, and matching 

34 values, to pass the query. 

35 

36 Examples 

37 -------- 

38 A MetadataQuery returns `True` if all key-value terms found in 

39 `MetadataQuery.terms` are equal to key-value metadata items. 

40 

41 >>> metadata = {'filter': 'r', 'camera': 'MegaCam'} 

42 

43 An example of a query with a conflicting term: 

44 

45 >>> query1 = MetadataQuery({'filter': 'r', 'camera': 'SDSS'}) 

46 >>> query1(metadata) 

47 False 

48 

49 A query with matching terms (albeit, a subset of the metadata): 

50 

51 >>> query2 = MetadataQuery({'filter': 'r'}) 

52 >>> query2(metadata) 

53 True 

54 

55 A query that overconstrains the available metadata: 

56 

57 >>> query3 = MetadataQuery({'filter': 'r', 'camera': 'MegaCam', 

58 ... 'photometric': True}) 

59 >>> query3(metadata) 

60 False 

61 

62 The ``arg_driven=True`` mode reverses the matching logic so that all terms 

63 in the user-provided metadata must be in the MetadataQuery: 

64 

65 >>> query3(metadata, arg_driven=True) 

66 True 

67 >>> query2(metadata, arg_driven=True) 

68 False 

69 """ 

70 

71 terms = None 

72 """Term mapping (`dict`). Metadata must have all keys and corresponding 

73 values. 

74 """ 

75 

76 def __init__(self, terms=None): 

77 self.terms = terms or dict() 

78 

79 def __call__(self, metadata, arg_driven=False): 

80 """Determine if a metadata set matches the query terms. 

81 

82 Parameters 

83 ---------- 

84 metadata : `dict` or `lsst.verify.Metadata` 

85 Metadata mapping. Typically this is a job's 

86 `lsst.verify.Job.meta`. 

87 

88 arg_driven : `bool`, optional 

89 If `False` (default), ``metadata`` matches the ``MetadataQuery`` 

90 if ``metadata`` has all the terms defined in ``MetadataQuery``, 

91 and those terms match. If ``metadata`` has more terms than 

92 ``MetadataQuery``, it can still match. 

93 

94 If `True`, the orientation of the matching is reversed. Now 

95 ``metadata`` matches the ``MetadataQuery`` if ``MetadataQuery`` 

96 has all the terms defined in ``metadata`` and those terms match. 

97 If ``MetadataQuery`` has more terms than ``metadata``, it can 

98 still match. 

99 

100 Returns 

101 ------- 

102 match : `bool` 

103 `True` if the metadata matches the query terms; `False` otherwise. 

104 """ 

105 if arg_driven: 

106 # Match if self.terms has all the terms defined in metadata 

107 for arg_term, arg_term_value in metadata.items(): 

108 if arg_term not in self.terms: 

109 return False 

110 

111 # If metadata can be floats, may need to do more sophisticated 

112 # comparison 

113 if arg_term_value != self.terms[arg_term]: 

114 return False 

115 else: 

116 # Match if metadata has all the terms defined in this MetadataQuery 

117 for term_key, term_value in self.terms.items(): 

118 if term_key not in metadata: 

119 return False 

120 

121 # If metadata can be floats, may need to do more sophisticated 

122 # comparison 

123 if term_value != metadata[term_key]: 

124 return False 

125 

126 return True 

127 

128 def __eq__(self, other): 

129 return self.terms == other.terms 

130 

131 def __str__(self): 

132 return str(self.terms) 

133 

134 def __repr__(self): 

135 template = 'MetadataQuery({0!r})' 

136 return template.format(self.terms) 

137 

138 @property 

139 def json(self): 

140 """A JSON-serializable dict. 

141 

142 Keys are metadata keys. Values are the associated metadata values 

143 of the query term. 

144 """ 

145 return self.jsonify_dict(self.terms)