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

29 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-07-24 09:24 +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 

22__all__ = ["register", "registerMultiple"] 

23 

24from lsst.pex.config import Config, ConfigDictField, Registry 

25# Avoid importing tasks, which causes circular dependency 

26from ..tasks.metricTask import MetricTask 

27 

28 

29def register(name): 

30 """A class decorator that registers a 

31 `lsst.verify.tasks.MetricTask` with a central repository. 

32 

33 Parameters 

34 ---------- 

35 name : `str` 

36 The name under which this decorator will register the 

37 `~lsst.verify.tasks.MetricTask`. 

38 

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`. 

46 

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`. 

52 

53 Examples 

54 -------- 

55 The decorator is applied at the class definition: 

56 

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 

72 

73 

74def registerMultiple(name): 

75 """A class decorator that registers a 

76 `lsst.verify.tasks.MetricTask` with a central repository. 

77 

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. 

82 

83 Parameters 

84 ---------- 

85 name : `str` 

86 The name under which this decorator will register the 

87 `~lsst.verify.tasks.MetricTask`. 

88 

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`. 

96 

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`. 

102 

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``. 

111 

112 Examples 

113 -------- 

114 The decorator is applied at the class definition: 

115 

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 

134 

135 

136def _makeMultiConfig(configClass): 

137 """A factory function for creating a config for registerMultiple. 

138 

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`). 

145 

146 Returns 

147 ------- 

148 multiConfig : `lsst.pex.config.Config`-type 

149 A `~lsst.pex.config.Config` class containing the following fields: 

150 

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.") 

161 

162 return MultiConfig 

163 

164 

165class _MultiConfigFactory: 

166 """A factory class for creating multiple `MetricTask` objects at once. 

167 

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 

175 

176 def __call__(self, config, **kwargs): 

177 """Create the configured task(s). 

178 

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. 

185 

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()] 

195 

196 

197class MetricRegistry: 

198 """Registry of all `lsst.verify.tasks.MetricTask` subclasses known 

199 to `lsst.verify`'s client. 

200 

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 """ 

207 

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 """