LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
pluginRegistry.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # LSST Data Management System
4 # Copyright 2008-2015 AURA/LSST.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
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 LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <http://www.lsstcorp.org/LegalNotices/>.
22 #
23 """Registry for measurement plugins and associated utilities generateAlgorithmName and PluginMap
24 """
25 
26 import collections
27 
28 import lsst.pipe.base
29 import lsst.pex.config
30 from .apCorrRegistry import addApCorrName
31 
32 __all__ = ("generateAlgorithmName", "PluginRegistry", "register", "PluginMap")
33 
34 def generateAlgorithmName(AlgClass):
35  """Generate a string name for an algorithm class that strips away terms that are generally redundant
36  while (hopefully) remaining easy to trace to the code.
37 
38  The returned name will cobmine the package name, with any "lsst" and/or "meas" prefix removed,
39  with the class name, with any "Algorithm" suffix removed. For instance,
40  lsst.meas.base.SdssShapeAlgorithm becomes "base_SdssShape".
41  """
42  name = AlgClass.__name__
43  pkg = AlgClass.__module__
44  name = name.replace("Algorithm", "")
45  terms = pkg.split(".")
46  if terms[-1].endswith("Lib"):
47  terms = terms[:-1]
48  if terms[0] == "lsst":
49  terms = terms[1:]
50  if terms[0] == "meas":
51  terms = terms[1:]
52  if name.lower().startswith(terms[-1].lower()):
53  terms = terms[:-1]
54  return "%s_%s" % ("_".join(terms), name)
55 
56 class PluginRegistry(lsst.pex.config.Registry):
57  """!
58  Base class for plugin registries
59 
60  The Plugin class allowed in the registry is defined in the ctor of the registry.
61 
62  Single-frame and forced plugins have different registries.
63  """
64 
65  class Configurable(object):
66  """!
67  Class used as the actual element in the registry
68 
69  Rather than constructing a Plugin instance, its __call__ method
70  (invoked by RegistryField.apply) returns a tuple
71  of (executionOrder, name, config, PluginClass), which can then
72  be sorted before the plugins are instantiated.
73  """
74 
75  __slots__ = "PluginClass", "name"
76 
77  def __init__(self, name, PluginClass):
78  """!
79  Create a Configurable object for the given PluginClass and name
80  """
81  self.name = name
82  self.PluginClass = PluginClass
83 
84  @property
85  def ConfigClass(self): return self.PluginClass.ConfigClass
86 
87  def __call__(self, config):
88  return (self.PluginClass.getExecutionOrder(), self.name, config, self.PluginClass)
89 
90  def register(self, name, PluginClass, shouldApCorr=False, apCorrList=()):
91  """!
92  Register a Plugin class with the given name.
93 
94  The same Plugin may be registered multiple times with different names; this can
95  be useful if we often want to run it multiple times with different configuration.
96 
97  @param[in] name name of plugin class. This is used as a prefix for all fields produced by the Plugin,
98  and it should generally contain the name of the Plugin or Algorithm class itself
99  as well as enough of the namespace to make it clear where to find the code.
100  For example "base_GaussianFlux" indicates an algorithm in meas_base
101  that measures Gaussian Flux and produces fields such as "base_GaussianFlux_flux",
102  "base_GaussianFlux_fluxSigma" and "base_GaussianFlux_flag".
103  @param[in] shouldApCorr if True then this algorithm measures a flux that should be aperture
104  corrected. This is shorthand for apCorrList=[name] and is ignored if apCorrList is specified.
105  @param[in] apCorrList list of field name prefixes for flux fields that should be aperture corrected.
106  If an algorithm produces a single flux that should be aperture corrected then it is simpler
107  to set shouldApCorr=True. But if an algorithm produces multiple such fields then it must
108  specify apCorrList, instead. For example modelfit_CModel produces 3 such fields:
109  apCorrList=("modelfit_CModel_exp", "modelfit_CModel_exp", "modelfit_CModel_def")
110  If apCorrList is non-empty then shouldApCorr is ignored.
111  """
112  lsst.pex.config.Registry.register(self, name, self.Configurable(name, PluginClass))
113  if shouldApCorr and not apCorrList:
114  apCorrList = [name]
115  for prefix in apCorrList:
116  addApCorrName(prefix)
117 
118  def makeField(self, doc, default=None, optional=False, multi=False):
119  return lsst.pex.config.RegistryField(doc, self, default, optional, multi)
120 
121 
122 def register(name, shouldApCorr=False):
123  """!
124  A Python decorator that registers a class, using the given name, in its base class's PluginRegistry.
125  For example,
126  @code
127  @register("base_TransformedCentroid")
128  class ForcedTransformedCentroidPlugin(ForcedPlugin):
129  ...
130  @endcode
131  is equivalent to:
132  @code
133  class ForcedTransformedCentroidPlugin(ForcedPlugin):
134  ...
135  @ForcedPlugin.registry.register("base_TransformedCentroid", ForcedTransformedCentroidPlugin)
136  @endcode
137  """
138  def decorate(PluginClass):
139  PluginClass.registry.register(name, PluginClass, shouldApCorr=shouldApCorr)
140  return PluginClass
141  return decorate
142 
143 
144 class PluginMap(collections.OrderedDict):
145  """!
146  Map of plugins (instances of subclasses of BasePlugin) to be run for a task
147 
148  We assume plugins are added to the PluginMap according to their "Execution Order", so this
149  class doesn't actually do any of the sorting (though it does have to maintain that order,
150  which it does by inheriting from OrderedDict).
151  """
152 
153  def iter(self):
154  """!Return an iterator over plugins for which plugin.config.doMeasure is true
155 
156  @note plugin.config.doMeasure is usually a simple boolean class attribute, not a normal Config field.
157  """
158  for plugin in self.itervalues():
159  if plugin.config.doMeasure:
160  yield plugin
161 
162  def iterN(self):
163  """!Return an iterator over plugins for which plugin.config.doMeasureN is true
164 
165  @note plugin.config.doMeasureN is usually a simple boolean class attribute, not a normal Config field.
166  """
167  for plugin in self.itervalues():
168  if plugin.config.doMeasureN:
169  yield plugin
def __init__
Create a Configurable object for the given PluginClass and name.
Class used as the actual element in the registry.
Base class for plugin registries.
def iter
Return an iterator over plugins for which plugin.config.doMeasure is true.
def register
Register a Plugin class with the given name.
def register
A Python decorator that registers a class, using the given name, in its base class&#39;s PluginRegistry...
def addApCorrName
Add to the set of field name prefixes for fluxes that should be aperture corrected.
Map of plugins (instances of subclasses of BasePlugin) to be run for a task.
def iterN
Return an iterator over plugins for which plugin.config.doMeasureN is true.