:mod:`dip.plugins`
==================
.. module:: dip.plugins

The :mod:`dip.plugins` module implements the infrastructure for
encapsulating application :term:`plugins<plugin>`.


:class:`ContributionTo`
-----------------------
.. class:: ContributionTo

    Base class: :class:`~dip.model.List`

    The ContributionTo class encapsulates a list of contributions to an
    :term:`extension point` as an attribute of a plugin.  The value is normally
    set using a computed default value.

    .. method:: ContributionTo.__init__(id, **metadata)

        Initialise the object.
        
        :param id:
            is the identifier of the extension point.
        :param \*\*metadata:
            is additional meta-data stored with the type.

    .. method:: ContributionTo.clone(default)

        Create a clone of this instance with a different default value.
        
        :param default:
            is the default value of the cloned instance.
        :return:
            the cloned instance.


:class:`ExtensionPoint`
-----------------------
.. class:: ExtensionPoint

    Base class: :class:`~dip.model.Model`

    The ExtensionPoint class is the default implementation of an
    :term:`extension point`.

    .. method:: ExtensionPoint.bind(obj, name)

        Bind an attribute of an object to the extension point and update it
        with all contributions made so far.
        
        :param obj:
            is the object containing the attribute to bind to.
        :param name:
            is the name of the attribute to bind to.

    .. method:: ExtensionPoint.contribute(contributions)

        Contribute a list of objects to all bound attributes.
        
        :param contributions:
            is the list of objects to contribute.


:class:`IExtensionPoint`
------------------------
.. class:: IExtensionPoint

    Base class: :class:`~dip.model.Interface`

    The IExtensionPoint interface defines the API of an
    :term:`extension point`.

    .. attribute:: contributions = List()

        The list of contributions made.

    .. attribute:: id = Str()

        The identifier of the extension point.

    .. method:: IExtensionPoint.bind(obj, name)

        Bind an attribute of an object to the extension point and update it
        with all contributions made so far.
        
        :param obj:
            is the object containing the attribute to bind to.
        :param name:
            is the name of the attribute to bind to.

    .. method:: IExtensionPoint.contribute(contributions)

        Contribute a list of objects to all bound attributes.
        
        :param contributions:
            is the list of objects to contribute.


:class:`IPlugin`
----------------
.. class:: IPlugin

    Base class: :class:`~dip.model.Interface`

    The IPlugin interface defines the API of a :term:`plugin`. 

    .. attribute:: description = Str()

        The description of the plugin as it will appear to the user.

    .. attribute:: enabled = Bool(False)

        This is set if the plugin is enabled.

    .. attribute:: id = Str()

        The identifier of the plugin.  Two plugins are considered equivalent if
        their factories have the same identifier, even though the factories
        themselves are different.

    .. attribute:: plugin_manager = Instance(IPluginManager)

        The plugin manager that is managing this plugin.  It will be set by the
        plugin manager when the plugin is registered.

    .. method:: IPlugin.bind_extension_point(id, obj, name)

        Bind an extension point to the attribute of an object.  The
        attribute must have an ``append()`` method.
        
        :param id:
            is the identifier of the extension point.
        :param obj:
            is the object containing the attribute that the extension point is
            bound to.
        :param name:
            is the name of the attribute that the extension point is bound to.

    .. method:: IPlugin.enable()

        The plugin is enabled.  It should not be called if it is already
        enabled.

    .. method:: IPlugin.service(interface)

        Get a service that implements a particular interface.
        
        :param interface:
            is the interface that the service must implement.
        :return:
            the service.  An exception is raised if there is no service
            available.


:class:`IPluginManager`
-----------------------
.. class:: IPluginManager

    Base class: :class:`~dip.model.Interface`

    The IPluginManager interface defines the API of a
    :term:`plugin manager`.

    .. method:: IPluginManager.bind_extension_point(id, obj, name)

        Bind an extension point to the attribute of an object.  The
        attribute must have an ``append()`` method.
        
        :param id:
            is the identifier of the extension point.
        :param obj:
            is the object containing the attribute that the extension point is
            bound to.
        :param name:
            is the name of the attribute that the extension point is bound to.

    .. method:: IPluginManager.choose_service(interface, services)

        Choose a particular service from a list of possible services.
        
        :param interface:
            is the interface that the service must implement.
        :param services:
            a list of contributed services to choose from.  This can be
            ignored.
        :return:
            the chosen service or ``None`` if one wasn't chosen.

    .. method:: IPluginManager.contribute(id, *contributions)

        Contribute some objects to an extension point.
        
        :param id:
            is the identifier of the extension point.
        :param \*contributions:
            are the contributions to make to the extension point.  The
            contributions are made one at a time.

    .. method:: IPluginManager.enable_plugins()

        All plugins that are not already enabled are enabled. 

    .. method:: IPluginManager.service(interface)

        Get a service that implements a particular interface.
        
        :param interface:
            is the interface that the service must implement.
        :return:
            the service.  An exception is raised if there is no service
            available.


:class:`IService`
-----------------
.. class:: IService

    Base class: :class:`~dip.model.Interface`

    The IService interface defines the API of a :term:`service` definition.
        

    .. attribute:: interface = Subclass(Interface)

        The interface that the service implements.

    .. attribute:: implementation = Any()

        The service implementation.


:class:`Plugin`
---------------
.. class:: Plugin

    Base class: :class:`~dip.model.Model`

    The Plugin class is a convenience base class for a :term:`plugin`. 

    .. method:: Plugin.bind_extension_point(id, obj, name)

        Bind an extension point to the attribute of an object.  The
        attribute must have an ``append()`` method.
        
        :param id:
            is the identifier of the extension point.
        :param obj:
            is the object containing the attribute that the extension point is
            bound to.
        :param name:
            is the name of the attribute that the extension point is bound to.

    .. method:: Plugin.contributions()

        This is called when the plugin is enabled to return an iterator of
        2-tuples of the extension point identifier and the list of
        contributions to the extension point.  This default implementation
        looks for any :class:`~dip.plugins.ContributionTo` attributes in the
        plugin and its super-classes.
        
        :return:
            the iterator.

    .. method:: Plugin.enable()

        The plugin is enabled.  It should not be called if it is already
        enabled.

    .. method:: Plugin.service(interface)

        Get a service that implements a particular interface.
        
        :param interface:
            is the interface that the service must implement.
        :return:
            the service.  An exception is raised if there is no service
            available.


:class:`PluginManager`
----------------------
.. class:: PluginManager

    Base class: :class:`~dip.model.Model`

    The PluginManager class is the default implementation of the
    :class:`~dip.plugins.IPluginManager` interface.

    .. method:: PluginManager.__init__()

        Initialise the plugin manager. 

    .. method:: PluginManager.bind_extension_point(id, obj, name)

        Bind an extension point to the attribute of an object.  The
        attribute must have an ``append()`` method.
        
        :param id:
            is the identifier of the extension point.
        :param obj:
            is the object containing the attribute that the extension point is
            bound to.
        :param name:
            is the name of the attribute that the extension point is bound to.

    .. method:: PluginManager.choose_service(interface, services)

        Choose a particular service from a list of possible services.
        
        :param interface:
            is the interface that the service must implement.
        :param services:
            a list of contributed services to choose from.  This can be
            ignored.
        :return:
            the chosen service or ``None`` if one wasn't chosen.

    .. method:: PluginManager.contribute(id, *contributions)

        Contribute some objects to an extension point.
        
        :param id:
            is the identifier of the extension point.
        :param \*contributions:
            are the contributions to make to the extension point.  The
            contributions are made one at a time.

    .. method:: PluginManager.enable_plugins()

        All plugins that are not already enabled are enabled. 

    .. method:: PluginManager.service(interface)

        Get a service that implements a particular interface.
        
        :param interface:
            is the interface that the service must implement.
        :return:
            the service.  An exception is raised if there is no service
            available.


:class:`Service`
----------------
.. class:: Service

    Base class: :class:`~dip.model.Model`

    The Service class is the default implementation of a :term:`service`
    definition.
