diff --git a/dependency_injector/containers.py b/dependency_injector/containers.py new file mode 100644 index 00000000..858d8e1a --- /dev/null +++ b/dependency_injector/containers.py @@ -0,0 +1,93 @@ +"""IoC containers module.""" + +import six + +from dependency_injector import utils + + +class DeclarativeContainerMetaClass(type): + """Declarative inversion of control container meta class.""" + + def __new__(mcs, class_name, bases, attributes): + """Declarative container class factory.""" + cls_providers = tuple((name, provider) + for name, provider in six.iteritems(attributes) + if utils.is_provider(provider)) + + inherited_providers = tuple((name, provider) + for base in bases if utils.is_catalog(base) + for name, provider in six.iteritems( + base.cls_providers)) + + attributes['cls_providers'] = dict(cls_providers) + attributes['inherited_providers'] = dict(inherited_providers) + + return type.__new__(mcs, class_name, bases, attributes) + + def __setattr__(cls, name, value): + """Set class attribute. + + If value of attribute is provider, it will be added into providers + dictionary. + """ + if utils.is_provider(value): + cls.providers[name] = value + super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) + + +class Container(object): + """Inversion of control container.""" + + __IS_CATALOG__ = True + + def __init__(self): + """Initializer.""" + self.providers = dict() + + def bind_providers(self, **providers): + """Bind providers to the container.""" + for name, provider in six.iteritems(providers): + setattr(self, name, utils.ensure_is_provider(provider)) + return self + + def __setattr__(self, name, value): + """Set instance attribute. + + If value of attribute is provider, it will be added into providers + dictionary. + """ + if utils.is_provider(value): + self.providers[name] = value + super(Container, self).__setattr__(name, value) + + +@six.add_metaclass(DeclarativeContainerMetaClass) +class DeclarativeContainer(object): + """Declarative inversion of control container.""" + + cls_providers = dict() + inherited_providers = dict() + + def __init__(self): + """Initializer.""" + self.providers = dict() + self.providers.update(self.__class__.inherited_providers) + self.providers.update(self.__class__.cls_providers) + super(DeclarativeContainer, self).__init__() + + +def override(declarative_container): + """:py:class:`DeclarativeContainer` overriding decorator. + + :param declarative_container: Container that should be overridden by + decorated container. + :type declarative_container: :py:class:`DeclarativeContainer` + + :return: Declarative container's overriding decorator. + :rtype: callable(:py:class:`DeclarativeContainer`) + """ + def decorator(overriding_container): + """Overriding decorator.""" + declarative_container.override(overriding_container) + return overriding_container + return decorator