Source code for concurrent.core.components.component
# -*- coding: utf-8 -*-
"""
Base class every component used. A component is handled as a plugin.
The features of a plugin is defined by interfaces. Those interfaces will
force a component to resolve queries that come from the framework.
"""
__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface']
from concurrent.core.exceptions.baseerror import BaseError
[docs]class Interface(object):
"""Marker base class for extension point interfaces."""
[docs]class ExtensionPoint(property):
"""Marker class for extension points in components."""
def __init__(self, interface):
"""Create the extension point.
@param interface: the `Interface` subclass that defines the protocol
for the extension point
"""
property.__init__(self, self.extensions)
self.interface = interface
self.__doc__ = ('List of components that implement `%s`' % \
self.interface.__name__)
[docs] def extensions(self, component):
"""Return a list of components that declare to implement the extension
point interface.
"""
extensions = ComponentMeta._registry.get(self.interface, [])
return filter(None, [component.compmgr[cls] for cls in extensions])
def __repr__(self):
"""Return a textual representation of the extension point."""
return ('<ExtensionPoint %s>' % self.interface.__name__)
class ComponentMeta(type):
"""Meta class for components.
Takes care of component and extension point registration.
"""
_components = []
_registry = {}
def __new__(cls, name, bases, d):
"""Create the component class."""
new_class = type.__new__(cls, name, bases, d)
if name == 'Component':
# Don't put the Component base class in the registry
return new_class
# Only override __init__ for Components not inheriting ComponentManager
if True not in [issubclass(x, ComponentManager) for x in bases]:
# Allow components to have a no-argument initializer so that
# they don't need to worry about accepting the component manager
# as argument and invoking the super-class initializer
init = d.get('__init__')
if not init:
# Because we're replacing the initializer, we need to make sure
# that any inherited initializers are also called.
for init in [b.__init__._original for b in new_class.mro()
if issubclass(b, Component)
and '__init__' in b.__dict__]:
break
def maybe_init(self, compmgr, init=init, cls=new_class):
if cls not in compmgr.components:
compmgr.components[cls] = self
if init:
try:
init(self)
except:
del compmgr.components[cls]
raise
maybe_init._original = init
new_class.__init__ = maybe_init
if d.get('abstract'):
# Don't put abstract component classes in the registry
return new_class
ComponentMeta._components.append(new_class)
registry = ComponentMeta._registry
for interface in d.get('_implements', []):
registry.setdefault(interface, []).append(new_class)
for base in [base for base in bases if hasattr(base, '_implements')]:
for interface in base._implements:
registry.setdefault(interface, []).append(new_class)
return new_class
[docs]class Component(object):
"""Base class for components.
Every component can declare what extension points it provides, as well as
what extension points of other components it extends.
"""
__metaclass__ = ComponentMeta
def __new__(cls, *args, **kwargs):
"""Return an existing instance of the component if it has already been
activated, otherwise create a new instance.
"""
# If this component is also the component manager, just invoke that
if issubclass(cls, ComponentManager):
self = super(Component, cls).__new__(cls)
self.compmgr = self
return self
# The normal case where the component is not also the component manager
compmgr = args[0]
self = compmgr.components.get(cls)
if self is None:
self = super(Component, cls).__new__(cls)
self.compmgr = compmgr
compmgr.activate_component(self)
return self
[docs] def is_singleton(self):
"""
Defines the component as a singleton or not
"""
return True
[docs] def implements(*interfaces):
"""Can be used in the class definiton of `Component` subclasses to
declare the extension points that are extended.
"""
import sys
frame = sys._getframe(1)
locals_ = frame.f_locals
# Some sanity checks
assert locals_ is not frame.f_globals and '__module__' in locals_, \
'implements() can only be used in a class definition'
locals_.setdefault('_implements', []).extend(interfaces)
implements = staticmethod(implements)
implements = Component.implements
class ComponentManager(object):
"""The component manager keeps a pool of active components."""
def __init__(self):
"""Initialize the component manager."""
self.components = {}
self.enabled = {}
if isinstance(self, Component):
self.components[self.__class__] = self
def __contains__(self, cls):
"""Return wether the given class is in the list of active components."""
return cls in self.components
def __getitem__(self, cls):
"""Activate the component instance for the given class, or return the
existing instance if the component has already been activated and it's
marked as a singleton.
"""
if cls not in self.enabled:
self.enabled[cls] = self.is_component_enabled(cls)
if not self.enabled[cls]:
return None
component = self.components.get(cls)
if not component or not component.is_singleton():
if cls not in ComponentMeta._components:
raise BaseError('Component "%s" not registered' % cls.__name__)
try:
component = cls(self)
except TypeError as err:
raise BaseError('Unable to instantiate component %r (%s)' %
(cls, err))
return component
def disable_component(self, component):
"""Force a component to be disabled.
The argument `component` can be a class or an instance.
"""
if not isinstance(component, type):
component = component.__class__
self.enabled[component] = False
self.components[component] = None
def activate_component(self, component):
"""Can be overridden by sub-classes so that special initialization for
components can be provided."""
def is_component_enabled(self, cls):
"""Can be overridden by sub-classes to veto the activation of a
component.
If this method returns False, the component with the given class will
not be available."""
return True