Coverage for python/lsst/verify/gen2tasks/metricRegistry.py : 80%

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
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/>.
22__all__ = ["register", "registerMultiple"]
24from lsst.pex.config import Config, ConfigDictField, Registry
25# Avoid importing tasks, which causes circular dependency
26from ..tasks.metricTask import MetricTask
29def register(name):
30 """A class decorator that registers a
31 `lsst.verify.tasks.MetricTask` with a central repository.
33 Parameters
34 ----------
35 name : `str`
36 The name under which this decorator will register the
37 `~lsst.verify.tasks.MetricTask`.
39 Raises
40 ------
41 RuntimeError
42 Raised if another class has already been registered under ``name``.
43 ValueError
44 Raised if this decorator is applied to a class that is not a
45 `lsst.verify.tasks.MetricTask`.
47 Notes
48 -----
49 This decorator must be used for any
50 `~lsst.verify.tasks.MetricTask` that is to be used with
51 `lsst.verify.gen2tasks.MetricsControllerTask`.
53 Examples
54 --------
55 The decorator is applied at the class definition:
57 >>> from lsst.verify.gen2tasks import register
58 >>> from lsst.verify.tasks import MetricTask
59 >>> @register("dummy")
60 ... class DummyMetricTask(MetricTask):
61 ... pass
62 """
63 def wrapper(taskClass):
64 if issubclass(taskClass, MetricTask): 64 ↛ 70line 64 didn't jump to line 70, because the condition on line 64 was never false
65 # TODO: if MetricRegistry is phased out, simply return taskClass
66 # instead of removing the decorator
67 MetricRegistry.registry.register(name, taskClass)
68 return taskClass
69 else:
70 raise ValueError("%r is not a %r" % (taskClass, MetricTask))
71 return wrapper
74def registerMultiple(name):
75 """A class decorator that registers a
76 `lsst.verify.tasks.MetricTask` with a central repository.
78 Unlike `register`, this decorator assumes the same
79 `~lsst.verify.tasks.MetricTask` class will be run by
80 `lsst.verify.gen2tasks.MetricsControllerTask` multiple times with
81 different configs.
83 Parameters
84 ----------
85 name : `str`
86 The name under which this decorator will register the
87 `~lsst.verify.tasks.MetricTask`.
89 Raises
90 ------
91 RuntimeError
92 Raised if another class has already been registered under ``name``.
93 ValueError
94 Raised if this decorator is applied to a class that is not a
95 `lsst.verify.tasks.MetricTask`.
97 Notes
98 -----
99 This decorator must be used for any
100 `~lsst.verify.tasks.MetricTask` that will have multiple
101 instances used with `lsst.verify.gen2tasks.MetricsControllerTask`.
103 The registry entry produced by this decorator corresponds to an anonymous
104 `~lsst.pex.config.Config` class with one field, ``configs``. ``configs``
105 is a `~lsst.pex.config.ConfigDictField` that may have any number of
106 configs attached to it. The field will create multiple
107 `~lsst.verify.tasks.MetricTask` objects, one for each config
108 provided. See
109 :lsst-task:`~lsst.verify.gen2tasks.MetricsControllerTask` for an
110 example of how to use ``configs``.
112 Examples
113 --------
114 The decorator is applied at the class definition:
116 >>> from lsst.verify.gen2tasks import registerMultiple
117 >>> from lsst.verify.tasks import MetricTask
118 >>> @registerMultiple("reusable")
119 ... class ReusableMetricTask(MetricTask):
120 ... pass
121 """
122 def wrapper(taskClass):
123 if issubclass(taskClass, MetricTask): 123 ↛ 132line 123 didn't jump to line 132, because the condition on line 123 was never false
124 # TODO: if MetricRegistry is phased out, simply return taskClass
125 # instead of removing the decorator
126 MetricRegistry.registry.register(
127 name,
128 _MultiConfigFactory(taskClass),
129 ConfigClass=_makeMultiConfig(taskClass.ConfigClass))
130 return taskClass
131 else:
132 raise ValueError("%r is not a %r" % (taskClass, MetricTask))
133 return wrapper
136def _makeMultiConfig(configClass):
137 """A factory function for creating a config for registerMultiple.
139 Parameters
140 ----------
141 configClass : `lsst.verify.tasks.MetricTask.ConfigClass`-type
142 The type of task config to be stored inside the new config. Subclasses
143 of ``configClass`` will **NOT** be supported (this is a limitation of
144 `~lsst.pex.config.ConfigDictField`).
146 Returns
147 -------
148 multiConfig : `lsst.pex.config.Config`-type
149 A `~lsst.pex.config.Config` class containing the following fields:
151 configs : `lsst.pex.config.ConfigDictField`
152 A field that maps `str` to ``configClass``. The keys are arbitrary
153 and can be chosen for user convenience.
154 """
155 class MultiConfig(Config):
156 configs = ConfigDictField(
157 keytype=str, itemtype=configClass, optional=False,
158 default={},
159 doc="A collection of multiple configs to create multiple items "
160 "of the same type.")
162 return MultiConfig
165class _MultiConfigFactory:
166 """A factory class for creating multiple `MetricTask` objects at once.
168 Parameters
169 ----------
170 configurableClass : `lsst.verify.tasks.MetricTask`-type
171 The type of configurable created by `__call__`.
172 """
173 def __init__(self, configurableClass):
174 self._configurableClass = configurableClass
176 def __call__(self, config, **kwargs):
177 """Create the configured task(s).
179 Parameters
180 ----------
181 config : type from ``_makeMultiConfig(configurableClass.ConfigClass)``
182 A config containing multiple configs for ``configurableClass`.
183 **kwargs
184 Additional arguments to the ``configurableClass`` constructor.
186 Returns
187 -------
188 tasks : iterable of ``configurableClass``
189 A sequence of ``configurableClass``, one for each config in
190 ``config``. The order in which the objects will be returned
191 is undefined.
192 """
193 return [self._configurableClass(config=subConfig, **kwargs)
194 for subConfig in config.configs.values()]
197class MetricRegistry:
198 """Registry of all `lsst.verify.tasks.MetricTask` subclasses known
199 to `lsst.verify`'s client.
201 Notes
202 -----
203 This class has a singleton-like architecture in case a custom subclass of
204 `lsst.pex.config.Registry` is needed in the future. Code that refers to
205 ``MetricRegistry.registry`` should be agnostic to such changes.
206 """
208 # Don't use MetricTask.ConfigClass, to accommodate MultiConfig
209 registry = Registry(Config)
210 """A unique registry of ``MetricTasks`` or collections of ``MetricTasks``
211 (`lsst.pex.config.Registry`).
212 """