lsst.utils  19.0.0-10-g920eed2
Public Member Functions | List of all members
lsst.utils.wrappers.TemplateMeta Class Reference
Inheritance diagram for lsst.utils.wrappers.TemplateMeta:

Public Member Functions

def __new__ (cls, name, bases, attrs)
 
def __call__ (cls, *args, **kwds)
 
def __subclasscheck__ (cls, subclass)
 
def __instancecheck__ (cls, instance)
 
def __subclasses__ (cls)
 
def register (cls, key, subclass)
 
def alias (cls, key, subclass)
 
def __getitem__ (cls, key)
 
def __iter__ (cls)
 
def __len__ (cls)
 
def __contains__ (cls, key)
 
def keys (cls)
 
def values (cls)
 
def items (cls)
 
def get (cls, key, default=None)
 

Detailed Description

A metaclass for abstract base classes that tie together wrapped C++
template types.

C++ template classes are most easily wrapped with a separate Python class
for each template type, which results in an unnatural Python interface.
TemplateMeta provides a thin layer that connects these Python classes by
giving them a common base class and acting as a factory to construct them
in a consistent way.

To use, simply create a new class with the name of the template class, and
use ``TemplateMeta`` as its metaclass, and then call ``register`` on each
of its subclasses.  This registers the class with a "type key" - usually a
Python representation of the C++ template types.  The type key must be a
hashable object - strings, type objects, and tuples of these (for C++
classes with multiple template parameters) are good choices.  Alternate
type keys for existing classes can be added by calling ``alias``, but only
after a subclass already been registered with a "primary" type key.  For
example::

.. code-block:: python

    import numpy as np
    from ._image import ImageF, ImageD

    class Image(metaclass=TemplateMeta):
        pass

    Image.register(np.float32, ImageF)
    Image.register(np.float64, ImageD)
    Image.alias("F", ImageF)
    Image.alias("D", ImageD)

We have intentionally used ``numpy`` types as the primary keys for these
objects in this example, with strings as secondary aliases simply because
the primary key is added as a ``dtype`` attribute on the the registered
classes (so ``ImageF.dtype == numpy.float32`` in the above example).

This allows user code to construct objects directly using ``Image``, as
long as an extra ``dtype`` keyword argument is passed that matches one of
the type keys::

.. code-block:: python

    img = Image(52, 64, dtype=np.float32)

This simply forwards additional positional and keyword arguments to the
wrapped template class's constructor.

The choice of "dtype" as the name of the template parameter is also
configurable, and in fact multiple template parameters are also supported,
by setting a ``TEMPLATE_PARAMS`` class attribute on the ABC to a tuple
containing the names of the template parameters.  A ``TEMPLATE_DEFAULTS``
attribute can also be defined to a tuple of the same length containing
default values for the template parameters, allowing them to be omitted in
constructor calls.  When the length of these attributes is more than one,
the type keys passed to ``register`` and ``alias`` should be tuple of the
same length; when the length of these attributes is one, type keys should
generally not be tuples.

As an aid for those writing the Python wrappers for C++ classes,
``TemplateMeta`` also provides a way to add pure-Python methods and other
attributes to the wrapped template classes.  To add a ``sum`` method to
all registered types, for example, we can just do::

.. code-block:: python

    class Image(metaclass=TemplateMeta):

        def sum(self):
            return np.sum(self.getArray())

    Image.register(np.float32, ImageF)
    Image.register(np.float64, ImageD)

.. note::

    ``TemplateMeta`` works by overriding the ``__instancecheck__`` and
    ``__subclasscheck__`` special methods, and hence does not appear in
    its registered subclasses' method resolution order or ``__bases__``
    attributes. That means its attributes are not inherited by registered
    subclasses. Instead, attributes added to an instance of
    ``TemplateMeta`` are *copied* into the types registered with it. These
    attributes will thus *replace* existing attributes in those classes
    with the same name, and subclasses cannot delegate to base class
    implementations of these methods.

Finally, abstract base classes that use ``TemplateMeta`` define a dict-
like interface for accessing their registered subclasses, providing
something like the C++ syntax for templates::

.. code-block:: python

    Image[np.float32] -> ImageF
    Image["D"] -> ImageD

Both primary dtypes and aliases can be used as keys in this interface,
which means types with aliases will be present multiple times in the dict.
To obtain the sequence of unique subclasses, use the ``__subclasses__``
method.

.. warning::

    Python's built-in `super` function does not behave properly in classes
    that have `TemplateMeta` as their metaclass (which should be rare, as
    TemplateMeta ABCs will have base classes of their own)..

Definition at line 152 of file wrappers.py.

Member Function Documentation

◆ __call__()

def lsst.utils.wrappers.TemplateMeta.__call__ (   cls,
args,
**  kwds 
)

Definition at line 293 of file wrappers.py.

◆ __contains__()

def lsst.utils.wrappers.TemplateMeta.__contains__ (   cls,
  key 
)

Definition at line 458 of file wrappers.py.

◆ __getitem__()

def lsst.utils.wrappers.TemplateMeta.__getitem__ (   cls,
  key 
)

Definition at line 449 of file wrappers.py.

◆ __instancecheck__()

def lsst.utils.wrappers.TemplateMeta.__instancecheck__ (   cls,
  instance 
)

Definition at line 326 of file wrappers.py.

◆ __iter__()

def lsst.utils.wrappers.TemplateMeta.__iter__ (   cls)

Definition at line 452 of file wrappers.py.

◆ __len__()

def lsst.utils.wrappers.TemplateMeta.__len__ (   cls)

Definition at line 455 of file wrappers.py.

◆ __new__()

def lsst.utils.wrappers.TemplateMeta.__new__ (   cls,
  name,
  bases,
  attrs 
)

Definition at line 261 of file wrappers.py.

◆ __subclasscheck__()

def lsst.utils.wrappers.TemplateMeta.__subclasscheck__ (   cls,
  subclass 
)

Definition at line 316 of file wrappers.py.

◆ __subclasses__()

def lsst.utils.wrappers.TemplateMeta.__subclasses__ (   cls)
Return a tuple of all classes that inherit from this class.

Definition at line 336 of file wrappers.py.

◆ alias()

def lsst.utils.wrappers.TemplateMeta.alias (   cls,
  key,
  subclass 
)
Add an alias that allows an existing subclass to be accessed with a
different key.

Definition at line 429 of file wrappers.py.

◆ get()

def lsst.utils.wrappers.TemplateMeta.get (   cls,
  key,
  default = None 
)
Return the subclass associated with the given key (including
aliases), or ``default`` if the key is not recognized.

Definition at line 477 of file wrappers.py.

◆ items()

def lsst.utils.wrappers.TemplateMeta.items (   cls)
Return an iterable of (key, subclass) pairs.

Definition at line 472 of file wrappers.py.

◆ keys()

def lsst.utils.wrappers.TemplateMeta.keys (   cls)
Return an iterable containing all keys (including aliases).

Definition at line 461 of file wrappers.py.

◆ register()

def lsst.utils.wrappers.TemplateMeta.register (   cls,
  key,
  subclass 
)
Register a subclass of this ABC with the given key (a string,
number, type, or other hashable).

Register may only be called once for a given key or a given subclass.

Definition at line 344 of file wrappers.py.

◆ values()

def lsst.utils.wrappers.TemplateMeta.values (   cls)
Return an iterable of registered subclasses, with duplicates
corresponding to any aliases.

Definition at line 466 of file wrappers.py.


The documentation for this class was generated from the following file: