[docs]classContext(object):''' An IoC container for :func:`interface` s, :func:`service` s and :func:`component` s :param parent: a parent context :type parent: :class:`Context` '''def__init__(self,parent=None):self.parent=parentself.service_instances={}self.component_instances={}def__repr__(self):ifself.parent:return'[Context %s (child of %s)]'%(id(self),id(self.parent))else:return'[Context %s]'%id(self)
[docs]defget_components(self,cls,ignore_exceptions=False):forcompincls.implementations:try:instance=self.get_component(comp)yieldinstanceexceptExceptionase:ifignore_exceptions:log.error('Could not instantiate %s: %s',cls,e)else:raise
[docs]defservice(cls):''' Marks the decorated class as a singleton ``service``. Injects following classmethods: .. py:method:: .get(context) Returns a singleton instance of the class for given ``context`` :param context: context to look in :type context: :class:`Context` :returns: ``cls`` '''ifnotcls:returnNone# Inject methodsdefget(cls,context):returncontext.get_service(cls)cls.get=get.__get__(cls)log.debug('Registering [%s] (service)',get_fqdn(cls))returncls
[docs]classNoImplementationError(Exception):def__init__(self,cls):self.cls=clsdef__str__(self):returnu'No implementation for [%s] is available'%self.cls.__name__def__repr__(self):returnunicode(self)
[docs]definterface(cls):''' Marks the decorated class as an abstract interface. Injects following classmethods: .. py:method:: .all(context) Returns a list of instances of each component in the ``context`` implementing this ``@interface`` :param context: context to look in :type context: :class:`Context` :returns: list(``cls``) .. py:method:: .any(context) Returns the first suitable instance implementing this ``@interface`` or raises :exc:`NoImplementationError` if none is available. :param context: context to look in :type context: :class:`Context` :returns: ``cls`` .. py:method:: .classes() Returns a list of classes implementing this ``@interface`` :returns: list(class) '''ifnotcls:returnNonecls.implementations=[]# Inject methodsdef_all(cls,context,ignore_exceptions=False):returnlist(context.get_components(cls,ignore_exceptions=ignore_exceptions))cls.all=_all.__get__(cls)def_any(cls,context):instances=cls.all(context)ifinstances:returninstances[0]raiseNoImplementationError(cls)cls.any=_any.__get__(cls)def_classes(cls):returnlist(cls.implementations)cls.classes=_classes.__get__(cls)log.debug('Registering [%s] (interface)',get_fqdn(cls))returncls
[docs]defcomponent(iface):''' Marks the decorated class as a component implementing the given ``iface`` :param iface: the interface to implement :type iface: :func:`interface` '''defdecorator(cls):ifnotcls:returnNone# Run custom verificator if anyifhasattr(cls,'__verify__'):ifnotcls.__verify__():returnNoneifnothasattr(iface,'implementations'):log.error('%s is not an @interface',iface)log.debug('Registering [%s] (implementation of [%s])'%(get_fqdn(cls),get_fqdn(iface)))iface.implementations.append(cls)defget(cls,context):returncontext.get_component(cls)cls.get=get.__get__(cls)returnclsreturndecorator