Coverage for python/lsst/verify/jobmetadata.py : 23%

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
# # LSST Data Management System # # This product includes software developed by the # LSST Project (http://www.lsst.org/). # # See COPYRIGHT file at the top of the source tree. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the LSST License Statement and # the GNU General Public License along with this program. If not, # see <https://www.lsstcorp.org/LegalNotices/>. #
# Get ChainMap backport
except ImportError: # future 0.16.0 doesn't do the import right; this will be fixed in 0.16.1 # https://github.com/PythonCharmers/python-future/issues/226 from future.backports.misc import ChainMap
"""Container for verification framework job metadata.
Metadata are key-value terms. Both keys and values should be JSON-serializable.
Parameters ---------- measurement_set : `lsst.verify.MeasurementSet`, optional When provided, metadata with keys prefixed by metric names are deferred to `Metadata` instances attached to measurements (`lsst.verify.Measurement.notes`). data : `dict`, optional Dictionary to seed metadata. """
# Pattern for detecting metric name prefixes in names
# Dict of job metadata not stored with a mesaurement self._data = {}
# Measurement set to get measurement annotations from self._meas_set = measurement_set
# Initialize the ChainMap. The first item in the chain map is the # Metadata object's own _data. This is generic metadata. Additional # items in the chain are Measurement.notes annotations for all # measurements in the measurement_set. self._chain = ChainMap(self._data) self._cached_prefixes = set() self._refresh_chainmap()
if data is not None: self.update(data)
prefixes = set([str(name) for name in self._meas_set])
if self._cached_prefixes != prefixes: self._cached_prefixes = prefixes
self._chain = ChainMap(self._data) for _, measurement in self._meas_set.items(): # Get the dict instance directly so we don't use # the MeasurementNotes's key auto-prefixing. self._chain.maps.append(measurement.notes._data)
def _get_prefix(key): """Get the prefix of a measurement not, if it exists.
Examples -------- >>> Metadata._get_prefix('note') is None True >>> Metadata._get_prefix('validate_drp.PA1.note') 'validate_drp.PA1.'
To get the metric name:
>>> prefix = Metadata._get_prefix('validate_drp.PA1.note') >>> prefix.rstrip('.') 'validate_drp.PA1' """ match = Metadata._prefix_pattern.match(key) if match is not None: return match.group(0) else: return None
self._refresh_chainmap() return self._chain[key]
prefix = Metadata._get_prefix(key) if prefix is not None: metric_name = prefix.rstrip('.') if metric_name in self._meas_set: # turn prefix into a metric name self._meas_set[metric_name].notes[key] = value return
# No matching measurement; insert into general metadata self._data[key] = value
prefix = Metadata._get_prefix(key) if prefix is not None: metric_name = prefix.rstrip('.') if metric_name in self._meas_set: del self._meas_set[metric_name].notes[key] return
# No matching measurement; delete from general metadata del self._data[key]
self._refresh_chainmap() return key in self._chain
self._refresh_chainmap() return len(self._chain)
self._refresh_chainmap() for key in self._chain: yield key
# No explicit chain refresh because __len__ already does it if len(self) != len(other): return False
for key, value in other.items(): if key not in self: return False if value != self[key]: return False
return True
return not self.__eq__(other)
json_data = self.json return json.dumps(json_data, sort_keys=True, indent=4)
return repr(self._chain)
return self.__str__()
"""Get a `list` of metadata keys.
Returns ------- keys : `list` of `str` These keys keys can be used to access metadata values (like a `dict`). """ return [key for key in self]
"""Iterate over key-value metadata pairs.
Yields ------ item : `tuple` A metadata item is a tuple of:
- Key (`str`). - Value (object). """ self._refresh_chainmap() for item in self._chain.items(): yield item
"""Update metadata with key-value pairs from a `dict`-like object.
Parameters ---------- data : `dict`-like The ``data`` object needs to provide an ``items`` method to iterate over its key-value pairs. If this ``Metadata`` instance already has a key, the value will be overwritten with the value from ``data``. """ for key, value in data.items(): self[key] = value
def json(self): """A `dict` that can be serialized as semantic SQUASH JSON.
Keys in the `dict` are metadata keys (see `Metadata.keys`). Values are the associated metadata values as JSON-serializable objects. """ self._refresh_chainmap() return self.jsonify_dict(self._chain) |