diff --git a/dependency_injector/containers.py b/dependency_injector/containers.py index 795e2b20..8fc8bea9 100644 --- a/dependency_injector/containers.py +++ b/dependency_injector/containers.py @@ -10,15 +10,44 @@ from dependency_injector import ( class DynamicContainer(object): - """Dynamic inversion of control container.""" + """Dynamic inversion of control container. + + .. code-block:: python + + services = DynamicContainer() + services.auth = providers.Factory(AuthService) + services.users = providers.Factory(UsersService, + auth_service=services.auth) + + .. py:attribute:: providers + + Read-only dictionary of all providers. + + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] + + .. py:attribute:: overridden + + Tuple of overriding containers. + + :type: tuple[:py:class:`DynamicContainer`] + + .. py:attribute:: provider_type + + Type of providers that could be placed in container. + + :type: type + """ __IS_CONTAINER__ = True def __init__(self): - """Initializer.""" + """Initializer. + + :rtype: None + """ self.provider_type = providers.Provider self.providers = dict() - self.overridden_by = tuple() + self.overridden = tuple() super(DynamicContainer, self).__init__() def __setattr__(self, name, value): @@ -26,6 +55,14 @@ class DynamicContainer(object): If value of attribute is provider, it will be added into providers dictionary. + + :param name: Attribute's name + :type name: str + + :param value: Attribute's value + :type value: object + + :rtype: None """ if utils.is_provider(value): _check_provider_type(self, value) @@ -37,6 +74,11 @@ class DynamicContainer(object): If value of attribute is provider, it will be deleted from providers dictionary. + + :param name: Attribute's name + :type name: str + + :rtype: None """ if name in self.providers: del self.providers[name] @@ -46,10 +88,10 @@ class DynamicContainer(object): """Override current container by overriding container. :param overriding: Overriding container. - :type overriding: :py:class:`DeclarativeContainer` + :type overriding: :py:class:`DynamicContainer` :raise: :py:exc:`dependency_injector.errors.Error` if trying to - override container by itself or its subclasses + override container by itself :rtype: None """ @@ -57,7 +99,7 @@ class DynamicContainer(object): raise errors.Error('Container {0} could not be overridden ' 'with itself'.format(self)) - self.overridden_by += (overriding,) + self.overridden += (overriding,) for name, provider in six.iteritems(overriding.providers): try: @@ -70,10 +112,10 @@ class DynamicContainer(object): :rtype: None """ - if not self.overridden_by: + if not self.overridden: raise errors.Error('Container {0} is not overridden'.format(self)) - self.overridden_by = self.overridden_by[:-1] + self.overridden = self.overridden[:-1] for provider in six.itervalues(self.providers): provider.reset_last_overriding() @@ -83,7 +125,7 @@ class DynamicContainer(object): :rtype: None """ - self.overridden_by = tuple() + self.overridden = tuple() for provider in six.itervalues(self.providers): provider.reset_override() @@ -120,6 +162,14 @@ class DeclarativeContainerMetaClass(type): If value of attribute is provider, it will be added into providers dictionary. + + :param name: Attribute's name + :type name: str + + :param value: Attribute's value + :type value: object + + :rtype: None """ if utils.is_provider(value): _check_provider_type(cls, value) @@ -132,6 +182,11 @@ class DeclarativeContainerMetaClass(type): If value of attribute is provider, it will be deleted from providers dictionary. + + :param name: Attribute's name + :type name: str + + :rtype: None """ if name in cls.providers and name in cls.cls_providers: del cls.providers[name] @@ -141,21 +196,61 @@ class DeclarativeContainerMetaClass(type): @six.add_metaclass(DeclarativeContainerMetaClass) class DeclarativeContainer(object): - """Declarative inversion of control container.""" + """Declarative inversion of control container. + + .. code-block:: python + + class Services(DeclarativeContainer): + auth = providers.Factory(AuthService) + users = providers.Factory(UsersService, + auth_service=auth) + """ __IS_CONTAINER__ = True provider_type = providers.Provider + """Type of providers that could be placed in container. - providers = dict() - cls_providers = dict() - inherited_providers = dict() - overridden_by = tuple() + :type: type + """ instance_type = DynamicContainer + """Type of container that is returned on instantiating declarative + container. + + :type: type + """ + + providers = dict() + """Read-only dictionary of all providers. + + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] + """ + + cls_providers = dict() + """Read-only dictionary of current container providers. + + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] + """ + + inherited_providers = dict() + """Read-only dictionary of inherited providers. + + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] + """ + + overridden = tuple() + """Tuple of overriding containers. + + :type: tuple[:py:class:`DeclarativeContainer`] + """ def __new__(cls, *args, **kwargs): - """Constructor.""" + """Constructor. + + :return: Dynamic container with copy of all providers. + :rtype: :py:class:`DynamicContainer` + """ container = cls.instance_type(*args, **kwargs) container.provider_type = cls.provider_type @@ -180,7 +275,7 @@ class DeclarativeContainer(object): raise errors.Error('Container {0} could not be overridden ' 'with itself or its subclasses'.format(cls)) - cls.overridden_by += (overriding,) + cls.overridden += (overriding,) for name, provider in six.iteritems(overriding.cls_providers): try: @@ -194,10 +289,10 @@ class DeclarativeContainer(object): :rtype: None """ - if not cls.overridden_by: + if not cls.overridden: raise errors.Error('Container {0} is not overridden'.format(cls)) - cls.overridden_by = cls.overridden_by[:-1] + cls.overridden = cls.overridden[:-1] for provider in six.itervalues(cls.providers): provider.reset_last_overriding() @@ -208,7 +303,7 @@ class DeclarativeContainer(object): :rtype: None """ - cls.overridden_by = tuple() + cls.overridden = tuple() for provider in six.itervalues(cls.providers): provider.reset_override() diff --git a/dependency_injector/providers/base.py b/dependency_injector/providers/base.py index 193af545..7dad050a 100644 --- a/dependency_injector/providers/base.py +++ b/dependency_injector/providers/base.py @@ -51,7 +51,7 @@ class Provider(object): All providers should extend this class. - .. py:attribute:: overridden_by + .. py:attribute:: overridden Tuple of overriding providers, if any. @@ -60,11 +60,11 @@ class Provider(object): __IS_PROVIDER__ = True __OPTIMIZED_CALLS__ = True - __slots__ = ('overridden_by', 'provide', '__call__') + __slots__ = ('overridden', 'provide', '__call__') def __init__(self): """Initializer.""" - self.overridden_by = tuple() + self.overridden = tuple() super(Provider, self).__init__() # Enable __call__() / _provide() optimization if self.__class__.__OPTIMIZED_CALLS__: @@ -81,7 +81,9 @@ class Provider(object): def _call_last_overriding(self, *args, **kwargs): """Call last overriding provider and return result.""" - return self.last_overriding(*args, **kwargs) + return (self.overridden[-1](*args, **kwargs) + if self.overridden + else None) def provide_injection(self): """Injection strategy implementation. @@ -90,22 +92,6 @@ class Provider(object): """ return self.provide() - @property - def is_overridden(self): - """Read-only property that is set to ``True`` if provider is overridden. - - :rtype: bool - """ - return bool(self.overridden_by) - - @property - def last_overriding(self): - """Read-only reference to the last overriding provider, if any. - - :type: :py:class:`Provider` | None - """ - return self.overridden_by[-1] if self.overridden_by else None - def override(self, provider): """Override provider with another provider. @@ -124,7 +110,7 @@ class Provider(object): if not is_provider(provider): provider = Object(provider) - self.overridden_by += (ensure_is_provider(provider),) + self.overridden += (ensure_is_provider(provider),) # Disable __call__() / _provide() optimization if self.__class__.__OPTIMIZED_CALLS__: @@ -140,12 +126,12 @@ class Provider(object): :rtype: None """ - if not self.overridden_by: + if not self.overridden: raise Error('Provider {0} is not overridden'.format(str(self))) - self.overridden_by = self.overridden_by[:-1] + self.overridden = self.overridden[:-1] - if not self.is_overridden: + if not self.overridden: # Enable __call__() / _provide() optimization if self.__class__.__OPTIMIZED_CALLS__: self.__call__ = self.provide = self._provide @@ -155,7 +141,7 @@ class Provider(object): :rtype: None """ - self.overridden_by = tuple() + self.overridden = tuple() # Enable __call__() / _provide() optimization if self.__class__.__OPTIMIZED_CALLS__: @@ -324,10 +310,10 @@ class ExternalDependency(Provider): :rtype: object """ - if not self.is_overridden: + if not self.overridden: raise Error('Dependency is not defined') - instance = self.last_overriding(*args, **kwargs) + instance = self._call_last_overriding(*args, **kwargs) if not isinstance(instance, self.instance_of): raise Error('{0} is not an '.format(instance) + diff --git a/docs/containers/declarative.rst b/docs/containers/declarative.rst index e290251e..8d64c1ce 100644 --- a/docs/containers/declarative.rst +++ b/docs/containers/declarative.rst @@ -1,12 +1,12 @@ Declarative containers --------------------- +---------------------- .. currentmodule:: dependency_injector.containers -:py:class:`DeclarativeContainer` is a container of providers that could be -defined in declarative manner. It should cover most of the cases when list -of providers that would be included in container is deterministic (container -will not change its structure in runtime). +:py:class:`DeclarativeContainer` is inversion of control container that +could be defined in declarative manner. It should cover most of the cases +when list of providers that would be included in container is deterministic +(container will not change its structure in runtime). Declarative containers have to extend base declarative container class - :py:class:`dependency_injector.containers.DeclarativeContainer`. diff --git a/docs/containers/dynamic.rst b/docs/containers/dynamic.rst index 773dd20b..ed296d4f 100644 --- a/docs/containers/dynamic.rst +++ b/docs/containers/dynamic.rst @@ -1,31 +1,27 @@ -Dynamic catalogs ----------------- +Dynamic containers +------------------ .. currentmodule:: dependency_injector.containers -:py:class:`DynamicCatalog` is a catalog of providers that could be created in -application's runtime. It should cover most of the cases when list of -providers that would be included in catalog is non-deterministic in terms of -apllication code (catalog's structure could be determined just after -application will be started and will do some initial work, like parsing list -of catalog's providers from the configuration). +:py:class:`DynamicContainer` is an inversion of control container with dynamic +structure. It should cover most of the cases when list of providers that +would be included in container is non-deterministic and depends on +application's flow or its configuration (container's structure could be +determined just after application will be started and will do some initial +work, like parsing list of container's providers from the configuration). -:py:class:`DeclarativeCatalog` and :py:class:`DynamicCatalog` have -100% API parity. +While :py:class:`DeclarativeContainer` acts on class-level, +:py:class:`DynamicContainer` does the same on instance-level. -Main difference between :py:class:`DeclarativeCatalog` and -:py:class:`DynamicCatalog` is that :py:class:`DeclarativeCatalog` acts on -class-level, while :py:class:`DynamicCatalog` do the same on -instance-level. +Here is an simple example of defining dynamic container with several factories: -Here is an simple example of defining dynamic catalog with several factories: - -.. literalinclude:: ../../examples/catalogs/dynamic.py +.. literalinclude:: ../../examples/containers/dynamic.py :language: python :linenos: -Next one example demonstrates creation and runtime filling of dynamic catalog: +Next example demonstrates creation of dynamic container based on some +configuration: -.. literalinclude:: ../../examples/catalogs/dynamic_runtime_creation.py +.. literalinclude:: ../../examples/containers/dynamic_runtime_creation.py :language: python :linenos: diff --git a/docs/containers/index.rst b/docs/containers/index.rst index 0cd66a08..55e06f17 100644 --- a/docs/containers/index.rst +++ b/docs/containers/index.rst @@ -1,5 +1,5 @@ -Containers -========== +IoC Containers +============== Containers are collections of providers. Main purpose of containers is to group providers. diff --git a/docs/containers/overriding.rst b/docs/containers/overriding.rst index 676810c2..7937e46a 100644 --- a/docs/containers/overriding.rst +++ b/docs/containers/overriding.rst @@ -1,52 +1,40 @@ -Overriding of catalogs ----------------------- +Overriding of containers +------------------------ .. currentmodule:: dependency_injector.containers -Catalogs can be overridden by other catalogs. This, actually, means that -all of the providers from overriding catalog will override providers with the -same names in overridden catalog. +Containers can be overridden by other containers. This, actually, means that +all of the providers from overriding container will override providers with +the same names in overridden container. -There are two ways to override :py:class:`DeclarativeCatalog` with another -catalog: +There are two ways to override :py:class:`DeclarativeContainer` with another +container: -- Use :py:meth:`DeclarativeCatalog.override` method. +- Use :py:meth:`DeclarativeContainer.override` method. - Use :py:func:`override` class decorator. -Example of overriding catalog using :py:meth:`DeclarativeCatalog.override` +Example of overriding container using :py:meth:`DeclarativeContainer.override` method: -.. literalinclude:: ../../examples/catalogs/override_declarative.py +.. literalinclude:: ../../examples/containers/override_declarative.py :language: python :linenos: -Example of overriding catalog using :py:func:`override` decorator: +Example of overriding container using :py:func:`override` decorator: -.. literalinclude:: ../../examples/catalogs/override_declarative_decorator.py +.. literalinclude:: ../../examples/containers/override_declarative_decorator.py :language: python :linenos: -Also there are several useful :py:class:`DeclarativeCatalog` methods and -properties that help to work with catalog overridings: +Also there are several useful :py:class:`DeclarativeContainer` methods and +properties that help to work with container overridings: -- :py:attr:`DeclarativeCatalog.is_overridden` - read-only property that is set - to ``True`` if catalog is overridden. -- :py:attr:`DeclarativeCatalog.last_overriding` - read-only reference to - the last overriding catalog, if any. -- :py:attr:`DeclarativeCatalog.overridden_by` - tuple of all overriding - catalogs. -- :py:meth:`DeclarativeCatalog.reset_last_overriding()` - reset last - overriding catalog. -- :py:meth:`DeclarativeCatalog.reset_override()` - reset all overridings for - all catalog providers. +- :py:attr:`DeclarativeContainer.overridden` - tuple of all overriding + containers. +- :py:meth:`DeclarativeContainer.reset_last_overriding()` - reset last + overriding provider for each container providers. +- :py:meth:`DeclarativeContainer.reset_override()` - reset all overridings + for each container providers. -:py:class:`DynamicCatalog` has exactly the same functionality, except of -:py:func:`override` decorator. Also :py:class:`DynamicCatalog` can override -:py:class:`DeclarativeCatalog` and vise versa. - -Example of overriding :py:class:`DeclarativeCatalog` by -:py:class:`DynamicCatalog`: - -.. literalinclude:: ../../examples/catalogs/override_declarative_by_dynamic.py - :language: python - :linenos: +:py:class:`DynamicContainer` has exactly the same functionality, except of +:py:func:`override` decorator. diff --git a/docs/containers/specialization.rst b/docs/containers/specialization.rst index 1647180a..3fb4dcd0 100644 --- a/docs/containers/specialization.rst +++ b/docs/containers/specialization.rst @@ -1,45 +1,24 @@ -Specialization of catalogs --------------------------- +Specialization of containers +---------------------------- .. currentmodule:: dependency_injector.containers -:py:class:`DeclarativeCatalog` and :py:class:`DynamicCatalog` could be -specialized for any kind of needs via declaring its subclasses. +:py:class:`DeclarativeContainer` could be specialized for any kind of needs +via declaring its subclasses. -One of such `builtin` features is a limitation to -:py:class:`DeclarativeCatalog` (and :py:class:`DynamicCatalog`) provider type. +One of such `builtin` features is a limitation for providers type. -Next example shows usage of this feature with :py:class:`DeclarativeCatalog` +Next example shows usage of this feature with :py:class:`DeclarativeContainer` in couple with feature of :py:class:`dependency_injector.providers.Factory` for limitation of its provided type: - -Listing of `services.py`: - -.. literalinclude:: ../../examples/catalogs/declarative_provider_type/services.py +.. literalinclude:: ../../examples/containers/declarative_provider_type.py :language: python :linenos: -Listing of `catalog.py`: +Limitation for providers type could be used with :py:class:`DynamicContainer` +as well: -.. literalinclude:: ../../examples/catalogs/declarative_provider_type/catalog.py - :language: python - :linenos: - -Limitation to provider type could be used with :py:class:`DynamicCatalog` -as well. - -Next example does the same that previous one, but use -:py:class:`DynamicCatalog` instead of :py:class:`DeclarativeCatalog`: - -Listing of `services.py`: - -.. literalinclude:: ../../examples/catalogs/dynamic_provider_type/services.py - :language: python - :linenos: - -Listing of `catalog.py`: - -.. literalinclude:: ../../examples/catalogs/dynamic_provider_type/catalog.py +.. literalinclude:: ../../examples/containers/dynamic_provider_type.py :language: python :linenos: diff --git a/examples/containers/declarative_provider_type.py b/examples/containers/declarative_provider_type.py new file mode 100644 index 00000000..cc1b0338 --- /dev/null +++ b/examples/containers/declarative_provider_type.py @@ -0,0 +1,48 @@ +"""Specializing declarative container and factory provider example.""" + +import collections + +import dependency_injector.containers as containers +import dependency_injector.providers as providers +import dependency_injector.errors as errors + + +class SequenceProvider(providers.Factory): + """Sequence factory. + + Can provide only sequence objects. + """ + + provided_type = collections.Sequence + + +class SequencesContainer(containers.DeclarativeContainer): + """IoC container. + + Can contain only sequence providers. + """ + + provider_type = SequenceProvider + + +if __name__ == '__main__': + try: + class _SequenceContainer1(SequencesContainer): + object_provider = providers.Factory(object) + except errors.Error as exception: + print exception + # can contain only + # instances + + try: + class _SequenceContainer2(SequencesContainer): + object_provider = SequenceProvider(object) + except errors.Error as exception: + print exception + # can provide only + # instances + + class _SequenceContaier3(SequencesContainer): + list_provider = SequenceProvider(list) + + assert _SequenceContaier3.list_provider() == list() diff --git a/examples/containers/declarative_provider_type/container.py b/examples/containers/declarative_provider_type/container.py deleted file mode 100644 index 0dd89d30..00000000 --- a/examples/containers/declarative_provider_type/container.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Specialized declarative IoC container example.""" - -import core -import services - - -class Services(core.ServicesContainer): - """IoC container of service providers.""" - - users = core.ServiceProvider(services.UsersService, - config={'option1': '111', - 'option2': '222'}) - - auth = core.ServiceProvider(services.AuthService, - config={'option3': '333', - 'option4': '444'}, - users_service=users) diff --git a/examples/containers/declarative_provider_type/core.py b/examples/containers/declarative_provider_type/core.py deleted file mode 100644 index ed385df7..00000000 --- a/examples/containers/declarative_provider_type/core.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Base classes for services.""" - -from dependency_injector import containers -from dependency_injector import providers - - -class BaseService(object): - """Base service class.""" - - -class ServiceProvider(providers.Factory): - """Service provider. - - Can provide :py:class:`Base` only. - """ - - provided_type = BaseService - - -class ServicesContainer(containers.DeclarativeContainer): - """Base IoC container of service providers. - - Can include :py:class:`Provider`'s only. - """ - - provider_type = ServiceProvider diff --git a/examples/containers/declarative_provider_type/main.py b/examples/containers/declarative_provider_type/main.py deleted file mode 100644 index 3bd7e21d..00000000 --- a/examples/containers/declarative_provider_type/main.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Main module.""" - -import core -import services -import container - -from dependency_injector import providers -from dependency_injector import errors - - -if __name__ == '__main__': - # Creating users & auth services: - users_service = container.Services.users() - auth_service = container.Services.auth() - - # Making some asserts: - assert users_service.config == {'option1': '111', - 'option2': '222'} - assert auth_service.config == {'option3': '333', - 'option4': '444'} - assert isinstance(auth_service.users_service, services.UsersService) - - # Trying to declare services container with other provider type: - try: - class _Services1(core.ServicesContainer): - - users = providers.Factory(services.UsersService) - except errors.Error as exception: - print exception - # can contain only - # instances - - # Trying to declare services container with correct provider by invalid - # provided type: - try: - class _Services2(core.ServicesContainer): - - users = core.ServiceProvider(object) - except errors.Error as exception: - print exception - # can provide only - # instances diff --git a/examples/containers/declarative_provider_type/services.py b/examples/containers/declarative_provider_type/services.py deleted file mode 100644 index f6c78e0b..00000000 --- a/examples/containers/declarative_provider_type/services.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Base classes for services.""" - -import core - - -class UsersService(core.BaseService): - """Users service.""" - - def __init__(self, config): - """Initializer.""" - self.config = config - super(UsersService, self).__init__() - - -class AuthService(core.BaseService): - """Auth service.""" - - def __init__(self, config, users_service): - """Initializer.""" - self.config = config - self.users_service = users_service - super(AuthService, self).__init__() diff --git a/examples/containers/dynamic.py b/examples/containers/dynamic.py new file mode 100644 index 00000000..cf33dc58 --- /dev/null +++ b/examples/containers/dynamic.py @@ -0,0 +1,18 @@ +"""Dynamic container simple example.""" + +import dependency_injector.containers as containers +import dependency_injector.providers as providers + + +# Defining dynamic container: +container = containers.DynamicContainer() +container.factory1 = providers.Factory(object) +container.factory2 = providers.Factory(object) + +# Creating some objects: +object1 = container.factory1() +object2 = container.factory2() + +# Making some asserts: +assert object1 is not object2 +assert isinstance(object1, object) and isinstance(object2, object) diff --git a/examples/containers/dynamic_provider_type.py b/examples/containers/dynamic_provider_type.py new file mode 100644 index 00000000..2e0835cd --- /dev/null +++ b/examples/containers/dynamic_provider_type.py @@ -0,0 +1,41 @@ +"""Specializing dynamic container and factory provider example.""" + +import collections + +import dependency_injector.containers as containers +import dependency_injector.providers as providers +import dependency_injector.errors as errors + + +class SequenceProvider(providers.Factory): + """Sequence factory. + + Can provide only sequence objects. + """ + + provided_type = collections.Sequence + + +sequences_container = containers.DynamicContainer() +sequences_container.provider_type = SequenceProvider + + +if __name__ == '__main__': + try: + sequences_container.object_provider = providers.Factory(object) + except errors.Error as exception: + print exception + # can contain only + # instances + + try: + sequences_container.object_provider = SequenceProvider(object) + except errors.Error as exception: + print exception + # can provide only + # instances + + sequences_container.list_provider = SequenceProvider(list) + + assert sequences_container.list_provider() == list() diff --git a/examples/containers/dynamic_runtime_creation.py b/examples/containers/dynamic_runtime_creation.py new file mode 100644 index 00000000..10e12d00 --- /dev/null +++ b/examples/containers/dynamic_runtime_creation.py @@ -0,0 +1,61 @@ +"""Creation of dynamic container based on some configuration example.""" + +import dependency_injector.containers as containers + + +# Defining several example services: +class UsersService(object): + """Example users service.""" + + +class AuthService(object): + """Example auth service.""" + + +def import_cls(cls_name): + """Import class by its fully qualified name. + + In terms of current example it is just a small helper function. Please, + don't use it in production approaches. + """ + path_components = cls_name.split('.') + module = __import__('.'.join(path_components[:-1]), + locals(), + globals(), + fromlist=path_components[-1:]) + return getattr(module, path_components[-1]) + + +# "Parsing" some configuration: +config = { + 'services': { + 'users': { + 'class': '__main__.UsersService', + 'provider_class': 'dependency_injector.providers.Factory', + }, + 'auth': { + 'class': '__main__.AuthService', + 'provider_class': 'dependency_injector.providers.Factory', + } + } +} + +# Creating empty container of service providers: +services = containers.DynamicContainer() + +# Filling dynamic container with service providers using configuration: +for service_name, service_info in config['services'].iteritems(): + # Runtime importing of service and service provider classes: + service_cls = import_cls(service_info['class']) + service_provider_cls = import_cls(service_info['provider_class']) + + # Binding service provider to the dynamic service providers catalog: + setattr(services, service_name, service_provider_cls(service_cls)) + +# Creating some objects: +users_service = services.users() +auth_service = services.auth() + +# Making some asserts: +assert isinstance(users_service, UsersService) +assert isinstance(auth_service, AuthService) diff --git a/examples/containers/override_declarative.py b/examples/containers/override_declarative.py index 40c1fb27..b11d1b2e 100644 --- a/examples/containers/override_declarative.py +++ b/examples/containers/override_declarative.py @@ -1,45 +1,28 @@ """Declarative IoC container overriding example.""" -import collections - -from dependency_injector import containers -from dependency_injector import providers - - -# Creating some example classes: -Object1 = collections.namedtuple('Object1', ['arg1', 'arg2']) -Object2 = collections.namedtuple('Object2', ['object1']) -ExtendedObject2 = collections.namedtuple('ExtendedObject2', []) +import dependency_injector.containers as containers +import dependency_injector.providers as providers class Container(containers.DeclarativeContainer): - """Example IoC container.""" + """IoC container.""" - object1_factory = providers.Factory(Object1, - arg1=1, - arg2=2) - - object2_factory = providers.Factory(Object2, - object1=object1_factory) + sequence_factory = providers.Factory(list) class OverridingContainer(containers.DeclarativeContainer): """Overriding IoC container.""" - object2_factory = providers.Factory(ExtendedObject2) + sequence_factory = providers.Factory(tuple) # Overriding `Container` with `OverridingContainer`: Container.override(OverridingContainer) # Creating some objects using overridden container: -object2_1 = Container.object2_factory() -object2_2 = Container.object2_factory() +sequence_1 = Container.sequence_factory([1, 2, 3]) +sequence_2 = Container.sequence_factory([3, 2, 1]) # Making some asserts: -assert Container.overridden_by == (OverridingContainer,) - -assert object2_1 is not object2_2 - -assert isinstance(object2_1, ExtendedObject2) -assert isinstance(object2_2, ExtendedObject2) +assert Container.overridden == (OverridingContainer,) +assert sequence_1 == (1, 2, 3) and sequence_2 == (3, 2, 1) diff --git a/examples/containers/override_declarative_decorator.py b/examples/containers/override_declarative_decorator.py index c1e259ce..74165383 100644 --- a/examples/containers/override_declarative_decorator.py +++ b/examples/containers/override_declarative_decorator.py @@ -1,23 +1,13 @@ """Declarative IoC container overriding using `@override()` decorator.""" -import collections - -from dependency_injector import containers -from dependency_injector import providers - - -# Creating some example classes: -Object1 = collections.namedtuple('Object1', ['arg1', 'arg2']) -Object2 = collections.namedtuple('Object2', ['object1']) -ExtendedObject2 = collections.namedtuple('ExtendedObject2', []) +import dependency_injector.containers as containers +import dependency_injector.providers as providers class Container(containers.DeclarativeContainer): - """Example IoC container.""" + """IoC container.""" - object1_factory = providers.Factory(Object1, arg1=1, arg2=2) - - object2_factory = providers.Factory(Object2, object1=object1_factory) + sequence_factory = providers.Factory(list) # Overriding `Container` with `OverridingContainer`: @@ -25,17 +15,13 @@ class Container(containers.DeclarativeContainer): class OverridingContainer(containers.DeclarativeContainer): """Overriding IoC container.""" - object2_factory = providers.Factory(ExtendedObject2) + sequence_factory = providers.Factory(tuple) # Creating some objects using overridden container: -object2_1 = Container.object2_factory() -object2_2 = Container.object2_factory() +sequence_1 = Container.sequence_factory([1, 2, 3]) +sequence_2 = Container.sequence_factory([3, 2, 1]) # Making some asserts: -assert Container.overridden_by == (OverridingContainer,) - -assert object2_1 is not object2_2 - -assert isinstance(object2_1, ExtendedObject2) -assert isinstance(object2_2, ExtendedObject2) +assert Container.overridden == (OverridingContainer,) +assert sequence_1 == (1, 2, 3) and sequence_2 == (3, 2, 1) diff --git a/tests/providers/test_base.py b/tests/providers/test_base.py index ad6ff404..2d2041ba 100644 --- a/tests/providers/test_base.py +++ b/tests/providers/test_base.py @@ -42,14 +42,14 @@ class ProviderTests(unittest.TestCase): """Test provider overriding.""" overriding_provider = providers.Provider() self.provider.override(overriding_provider) - self.assertTrue(self.provider.is_overridden) + self.assertTrue(self.provider.overridden) def test_overriding_context(self): """Test provider overriding context.""" overriding_provider = providers.Provider() with self.provider.override(overriding_provider): - self.assertTrue(self.provider.is_overridden) - self.assertFalse(self.provider.is_overridden) + self.assertTrue(self.provider.overridden) + self.assertFalse(self.provider.overridden) def test_override_with_itself(self): """Test provider overriding with itself.""" @@ -61,21 +61,6 @@ class ProviderTests(unittest.TestCase): self.provider.override(obj) self.assertIs(self.provider(), obj) - def test_last_overriding(self): - """Test getting last overriding provider.""" - overriding_provider1 = providers.Provider() - overriding_provider2 = providers.Provider() - - self.provider.override(overriding_provider1) - self.assertIs(self.provider.last_overriding, overriding_provider1) - - self.provider.override(overriding_provider2) - self.assertIs(self.provider.last_overriding, overriding_provider2) - - def test_last_overriding_of_not_overridden_provider(self): - """Test getting last overriding from not overridden provider.""" - self.assertIsNone(self.provider.last_overriding) - def test_reset_last_overriding(self): """Test reseting of last overriding provider.""" overriding_provider1 = providers.Provider() @@ -84,13 +69,13 @@ class ProviderTests(unittest.TestCase): self.provider.override(overriding_provider1) self.provider.override(overriding_provider2) - self.assertIs(self.provider.last_overriding, overriding_provider2) + self.assertIs(self.provider.overridden[-1], overriding_provider2) self.provider.reset_last_overriding() - self.assertIs(self.provider.last_overriding, overriding_provider1) + self.assertIs(self.provider.overridden[-1], overriding_provider1) self.provider.reset_last_overriding() - self.assertFalse(self.provider.is_overridden) + self.assertFalse(self.provider.overridden) def test_reset_last_overriding_of_not_overridden_provider(self): """Test resetting of last overriding on not overridden provier.""" @@ -101,13 +86,12 @@ class ProviderTests(unittest.TestCase): overriding_provider = providers.Provider() self.provider.override(overriding_provider) - self.assertTrue(self.provider.is_overridden) - self.assertIs(self.provider.last_overriding, overriding_provider) + self.assertTrue(self.provider.overridden) + self.assertEqual(self.provider.overridden, (overriding_provider,)) self.provider.reset_override() - self.assertFalse(self.provider.is_overridden) - self.assertIsNone(self.provider.last_overriding) + self.assertEqual(self.provider.overridden, tuple()) def test_repr(self): """Test representation of provider.""" diff --git a/tests/test_containers.py b/tests/test_containers.py index 6d9a3788..353e770b 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -138,10 +138,10 @@ class DeclarativeContainerTests(unittest.TestCase): _Container.override(_OverridingContainer1) _Container.override(_OverridingContainer2) - self.assertEqual(_Container.overridden_by, + self.assertEqual(_Container.overridden, (_OverridingContainer1, _OverridingContainer2)) - self.assertEqual(_Container.p11.overridden_by, + self.assertEqual(_Container.p11.overridden, (_OverridingContainer1.p11, _OverridingContainer2.p11)) @@ -169,10 +169,10 @@ class DeclarativeContainerTests(unittest.TestCase): p11 = providers.Provider() p12 = providers.Provider() - self.assertEqual(_Container.overridden_by, + self.assertEqual(_Container.overridden, (_OverridingContainer1, _OverridingContainer2)) - self.assertEqual(_Container.p11.overridden_by, + self.assertEqual(_Container.p11.overridden, (_OverridingContainer1.p11, _OverridingContainer2.p11)) @@ -192,9 +192,9 @@ class DeclarativeContainerTests(unittest.TestCase): _Container.override(_OverridingContainer2) _Container.reset_last_overriding() - self.assertEqual(_Container.overridden_by, + self.assertEqual(_Container.overridden, (_OverridingContainer1,)) - self.assertEqual(_Container.p11.overridden_by, + self.assertEqual(_Container.p11.overridden, (_OverridingContainer1.p11,)) def test_reset_last_overridding_when_not_overridden(self): @@ -218,8 +218,8 @@ class DeclarativeContainerTests(unittest.TestCase): _Container.override(_OverridingContainer2) _Container.reset_override() - self.assertEqual(_Container.overridden_by, tuple()) - self.assertEqual(_Container.p11.overridden_by, tuple()) + self.assertEqual(_Container.overridden, tuple()) + self.assertEqual(_Container.p11.overridden, tuple()) def test_copy(self): """Test copy decorator.""" @@ -361,15 +361,15 @@ class DeclarativeContainerInstanceTests(unittest.TestCase): container.override(overriding_container1) container.override(overriding_container2) - self.assertEqual(container.overridden_by, + self.assertEqual(container.overridden, (overriding_container1, overriding_container2)) - self.assertEqual(container.p11.overridden_by, + self.assertEqual(container.p11.overridden, (overriding_container1.p11, overriding_container2.p11)) - self.assertEqual(_Container.overridden_by, tuple()) - self.assertEqual(_Container.p11.overridden_by, tuple()) + self.assertEqual(_Container.overridden, tuple()) + self.assertEqual(_Container.p11.overridden, tuple()) def test_override_with_itself(self): """Test override container with itself.""" @@ -397,9 +397,9 @@ class DeclarativeContainerInstanceTests(unittest.TestCase): container.override(overriding_container2) container.reset_last_overriding() - self.assertEqual(container.overridden_by, + self.assertEqual(container.overridden, (overriding_container1,)) - self.assertEqual(container.p11.overridden_by, + self.assertEqual(container.p11.overridden, (overriding_container1.p11,)) def test_reset_last_overridding_when_not_overridden(self): @@ -429,8 +429,8 @@ class DeclarativeContainerInstanceTests(unittest.TestCase): container.override(overriding_container2) container.reset_override() - self.assertEqual(container.overridden_by, tuple()) - self.assertEqual(container.p11.overridden_by, tuple()) + self.assertEqual(container.overridden, tuple()) + self.assertEqual(container.p11.overridden, tuple()) if __name__ == '__main__':