Coverage for python / lsst / analysis / tools / atools / metadataMetrics.py: 38%
36 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-15 00:23 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-15 00:23 +0000
1# This file is part of analysis_tools.
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/>.
21from __future__ import annotations
23__all__ = (
24 "DatasetMetadataMetricTool",
25 "TaskMetadataMetricTool",
26)
29from lsst.pex.config import DictField, Field
31from ..actions.keyedData import KeyedDataKeyAccessAction
32from ..interfaces import AnalysisTool
35class MetadataMetricTool(AnalysisTool):
36 """Base class for tools designed to extract values from metadata"""
38 parameterizedBand = Field[bool](
39 doc="Does this MetadataMetricTool support band as a name parameter?", default=False
40 )
42 metrics = DictField[str, str](doc="The metrics to extract from the metadata and their respective units.")
44 newNames = DictField[str, str](
45 doc="New names to allocate to the extracted metrics. Keys are the current "
46 "names, values are the new names.",
47 default=None,
48 optional=True,
49 )
51 @staticmethod
52 def makeValidAttributeName(name):
53 """Make a valid attribute name using a simple replacement."""
54 return name.replace(" ", "_")
56 def validate(self):
57 for metric in self.metrics.keys():
58 if not self.makeValidAttributeName(metric).isidentifier():
59 raise ValueError(
60 f"{metric=} must be a valid identifier after replacing spaces with underscores."
61 )
64class DatasetMetadataMetricTool(MetadataMetricTool):
65 """Tool designed to extract values from metadata of data products"""
67 metricsPrefixedWithBaseKeys = DictField[str, bool](
68 doc="Whether metrics are prefixed with base keys. For each key (a metric name or base key), "
69 "the corresponding boolean value specifies if the metric should be extracted using the base "
70 "key as a prefix.",
71 default={},
72 optional=True,
73 )
75 def finalize(self):
76 for metric in self.metrics.keys():
77 setattr(
78 self.process.filterActions,
79 self.makeValidAttributeName(metric),
80 KeyedDataKeyAccessAction(topLevelKey="metadata_metrics"),
81 )
82 self.produce.metric.units = dict(self.metrics.items())
84 if self.newNames is not None:
85 self.produce.metric.newNames = dict(self.newNames.items())
88class TaskMetadataMetricTool(MetadataMetricTool):
89 """This tool is designed to extract values from task metadata"""
91 taskName = Field[str](
92 doc="The name of the task to extract metadata from.",
93 default=None,
94 )
96 subTaskNames = DictField[str, str](
97 doc="The names of the subtasks to extract metadata from. "
98 "If the metric name is identified as one of the keys, then "
99 "the corresponding value is taken as the subTask metadata "
100 "from which to extract metadata.",
101 default=None,
102 optional=True,
103 )
105 def finalize(self):
106 for metric in self.metrics.keys():
107 if self.subTaskNames is not None and metric in self.subTaskNames:
108 taskFullName = f"{self.taskName}:{self.subTaskNames[metric]}"
109 else:
110 taskFullName = self.taskName
111 setattr(
112 self.process.filterActions,
113 self.makeValidAttributeName(metric),
114 KeyedDataKeyAccessAction(topLevelKey=taskFullName),
115 )
116 self.produce.metric.units = dict(self.metrics.items())
118 if self.newNames is not None:
119 self.produce.metric.newNames = dict(self.newNames.items())