Coverage for python/lsst/verify/metaquery.py: 30%
30 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-16 11:07 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-16 11:07 +0000
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']
23from .jsonmixin import JsonSerializationMixin
26class MetadataQuery(JsonSerializationMixin):
27 """Query of `lsst.verify.Job.meta` metadata.
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.
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.
41 >>> metadata = {'filter': 'r', 'camera': 'MegaCam'}
43 An example of a query with a conflicting term:
45 >>> query1 = MetadataQuery({'filter': 'r', 'camera': 'SDSS'})
46 >>> query1(metadata)
47 False
49 A query with matching terms (albeit, a subset of the metadata):
51 >>> query2 = MetadataQuery({'filter': 'r'})
52 >>> query2(metadata)
53 True
55 A query that overconstrains the available metadata:
57 >>> query3 = MetadataQuery({'filter': 'r', 'camera': 'MegaCam',
58 ... 'photometric': True})
59 >>> query3(metadata)
60 False
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:
65 >>> query3(metadata, arg_driven=True)
66 True
67 >>> query2(metadata, arg_driven=True)
68 False
69 """
71 terms = None
72 """Term mapping (`dict`). Metadata must have all keys and corresponding
73 values.
74 """
76 def __init__(self, terms=None):
77 self.terms = terms or dict()
79 def __call__(self, metadata, arg_driven=False):
80 """Determine if a metadata set matches the query terms.
82 Parameters
83 ----------
84 metadata : `dict` or `lsst.verify.Metadata`
85 Metadata mapping. Typically this is a job's
86 `lsst.verify.Job.meta`.
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.
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.
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
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
121 # If metadata can be floats, may need to do more sophisticated
122 # comparison
123 if term_value != metadata[term_key]:
124 return False
126 return True
128 def __eq__(self, other):
129 return self.terms == other.terms
131 def __str__(self):
132 return str(self.terms)
134 def __repr__(self):
135 template = 'MetadataQuery({0!r})'
136 return template.format(self.terms)
138 @property
139 def json(self):
140 """A JSON-serializable dict.
142 Keys are metadata keys. Values are the associated metadata values
143 of the query term.
144 """
145 return self.jsonify_dict(self.terms)