28 __all__ = (
"Registry", 
"makeRegistry", 
"RegistryField", 
"registerConfig", 
"registerConfigurable")
 
   30 import collections.abc
 
   33 from .config 
import Config, FieldValidationError, _typeStr
 
   34 from .configChoiceField 
import ConfigInstanceDict, ConfigChoiceField
 
   38     """A wrapper for configurables. 
   40     Used for configurables that don't contain a ``ConfigClass`` attribute, 
   41     or contain one that is being overridden. 
   49         return self.
_target(*args, **kwargs)
 
   53     """A base class for global registries, which map names to configurables. 
   55     A registry acts like a read-only dictionary with an additional `register` 
   56     method to add targets. Targets in the registry are configurables (see 
   61     configBaseType : `lsst.pex.config.Config`-type 
   62         The base class for config classes in the registry. 
   66     A configurable is a callable with call signature ``(config, *args)`` 
   67     Configurables typically create an algorithm or are themselves the 
   68     algorithm. Often configurables are `lsst.pipe.base.Task` subclasses, but 
   71     A ``Registry`` has these requirements: 
   73     - All configurables added to a particular registry have the same call 
   75     - All configurables in a registry typically share something important 
   76       in common. For example, all configurables in ``psfMatchingRegistry`` 
   77       return a PSF matching class that has a ``psfMatch`` method with a 
   78       particular call signature. 
   82     This examples creates a configurable class ``Foo`` and adds it to a 
   83     registry. First, creating the configurable: 
   85     >>> from lsst.pex.config import Registry, Config 
   86     >>> class FooConfig(Config): 
   87     ...     val = Field(dtype=int, default=3, doc="parameter for Foo") 
   90     ...     ConfigClass = FooConfig 
   91     ...     def __init__(self, config): 
   92     ...         self.config = config 
   93     ...     def addVal(self, num): 
   94     ...         return self.config.val + num 
   97     Next, create a ``Registry`` instance called ``registry`` and register the 
   98     ``Foo`` configurable under the ``"foo"`` key: 
  100     >>> registry = Registry() 
  101     >>> registry.register("foo", Foo) 
  102     >>> print(list(registry.keys())) 
  105     Now ``Foo`` is conveniently accessible from the registry itself. 
  107     Finally, use the registry to get the configurable class and create an 
  110     >>> FooConfigurable = registry["foo"] 
  111     >>> foo = FooConfigurable(FooConfigurable.ConfigClass()) 
  117         if not issubclass(configBaseType, Config):
 
  118             raise TypeError(
"configBaseType=%s must be a subclass of Config" % _typeStr(configBaseType,))
 
  122     def register(self, name, target, ConfigClass=None):
 
  123         """Add a new configurable target to the registry. 
  128             Name that the ``target`` is registered under. The target can 
  129             be accessed later with `dict`-like patterns using ``name`` as 
  132             A configurable type, usually a subclass of `lsst.pipe.base.Task`. 
  133         ConfigClass : `lsst.pex.config.Config`-type, optional 
  134             A subclass of `lsst.pex.config.Config` used to configure the 
  135             configurable. If `None` then the configurable's ``ConfigClass`` 
  141             Raised if an item with ``name`` is already in the registry. 
  143             Raised if ``ConfigClass`` is `None` and ``target`` does not have 
  144             a ``ConfigClass`` attribute. 
  148         If ``ConfigClass`` is provided then the ``target`` configurable is 
  149         wrapped in a new object that forwards function calls to it. Otherwise 
  150         the original ``target`` is stored. 
  152         if name 
in self.
_dict:
 
  153             raise RuntimeError(
"An item with name %r already exists" % name)
 
  154         if ConfigClass 
is None:
 
  159             raise TypeError(
"ConfigClass=%s is not a subclass of %r" %
 
  161         self.
_dict[name] = wrapper
 
  164         return self.
_dict[key]
 
  167         return len(self.
_dict)
 
  173         return key 
in self.
_dict 
  175     def makeField(self, doc, default=None, optional=False, multi=False):
 
  176         """Create a `RegistryField` configuration field from this registry. 
  181             A description of the field. 
  182         default : object, optional 
  183             The default target for the field. 
  184         optional : `bool`, optional 
  185             When `False`, `lsst.pex.config.Config.validate` fails if the 
  186             field's value is `None`. 
  187         multi : `bool`, optional 
  188             A flag to allow multiple selections in the `RegistryField` if 
  193         field : `lsst.pex.config.RegistryField` 
  194             `~lsst.pex.config.RegistryField` Configuration field. 
  200     """Private class that makes a `Registry` behave like the thing a 
  201     `~lsst.pex.config.ConfigChoiceField` expects. 
  205     registry : `Registry` 
  226     """Dictionary of instantiated configs, used to populate a `RegistryField`. 
  230     config : `lsst.pex.config.Config` 
  231         Configuration instance. 
  232     field : `RegistryField` 
  237         ConfigInstanceDict.__init__(self, config, field)
 
  240     def _getTarget(self):
 
  243                                        "Multi-selection field has no attribute 'target'")
 
  246     target = property(_getTarget)
 
  248     def _getTargets(self):
 
  251                                        "Single-selection field has no attribute 'targets'")
 
  254     targets = property(_getTargets)
 
  257         """Call the active target(s) with the active config as a keyword arg 
  259         If this is a multi-selection field, return a list obtained by calling 
  260         each active target with its corresponding active config. 
  262         Additional arguments will be passed on to the configurable target(s) 
  265             msg = 
"No selection has been made.  Options: %s" % \
 
  266                 " ".join(self.
types.registry.keys())
 
  271                 retvals.append(self.
types.registry[c](*args, config=self[c], **kw))
 
  274             return self.
types.registry[self.
name](*args, config=self[self.
name], **kw)
 
  277         if attr == 
"registry":
 
  278             object.__setattr__(self, attr, value)
 
  280             ConfigInstanceDict.__setattr__(self, attr, value)
 
  284     """A configuration field whose options are defined in a `Registry`. 
  289         A description of the field. 
  290     registry : `Registry` 
  291         The registry that contains this field. 
  292     default : `str`, optional 
  293         The default target key. 
  294     optional : `bool`, optional 
  295         When `False`, `lsst.pex.config.Config.validate` fails if the field's 
  297     multi : `bool`, optional 
  298         If `True`, the field allows multiple selections. The default is 
  314     instanceDictClass = RegistryInstanceDict
 
  315     """Class used to hold configurable instances in the field. 
  318     def __init__(self, doc, registry, default=None, optional=False, multi=False):
 
  321         ConfigChoiceField.__init__(self, doc, types, default, optional, multi)
 
  324         """Customize deep-copying, want a reference to the original registry. 
  326         WARNING: this must be overridden by subclasses if they change the 
  327         constructor signature! 
  330                            default=copy.deepcopy(self.
default),
 
  332         other.source = self.
source 
  337     """Create a `Registry`. 
  342         Docstring for the created `Registry` (this is set as the ``__doc__`` 
  343         attribute of the `Registry` instance. 
  344     configBaseType : `lsst.pex.config.Config`-type 
  345         Base type of config classes in the `Registry` 
  346         (`lsst.pex.config.Registry.configBaseType`). 
  350     registry : `Registry` 
  351         Registry with ``__doc__`` and `~Registry.configBaseType` attributes 
  354     cls = 
type(
"Registry", (Registry,), {
"__doc__": doc})
 
  355     return cls(configBaseType=configBaseType)
 
  359     """A decorator that adds a class as a configurable in a `Registry` 
  365         Name of the target (the decorated class) in the ``registry``. 
  366     registry : `Registry` 
  367         The `Registry` instance that the decorated class is added to. 
  368     ConfigClass : `lsst.pex.config.Config`-type, optional 
  369         Config class associated with the configurable. If `None`, the class's 
  370         ``ConfigClass`` attribute is used instead. 
  378     Internally, this decorator runs `Registry.register`. 
  381         registry.register(name, target=cls, ConfigClass=ConfigClass)
 
  387     """Decorator that adds a class as a ``ConfigClass`` in a `Registry` and 
  388     associates it with the given configurable. 
  393         Name of the ``target`` in the ``registry``. 
  394     registry : `Registry` 
  395         The registry containing the ``target``. 
  397         A configurable type, such as a subclass of `lsst.pipe.base.Task`. 
  405     Internally, this decorator runs `Registry.register`. 
  408         registry.register(name, target=target, ConfigClass=cls)