Merge branch 'release/4.24.0' into master

This commit is contained in:
Roman Mogylatov 2021-02-18 08:51:24 -05:00
commit c0d1e48f7b
9 changed files with 8556 additions and 682 deletions

View File

@ -0,0 +1,14 @@
Container copying
-----------------
You can create declarative container copies using ``@containers.copy()`` decorator.
.. literalinclude:: ../../examples/containers/declarative_copy_decorator.py
:language: python
:lines: 3-
:emphasize-lines: 18-22
Decorator ``@containers.copy()`` copies providers from source container to destination container.
Destination container provider will replace source provider, if names match.
.. disqus::

View File

@ -23,6 +23,7 @@ Containers module API docs - :py:mod:`dependency_injector.containers`.
dynamic dynamic
specialization specialization
overriding overriding
copying
reset_singletons reset_singletons
check_dependencies check_dependencies
traversal traversal

View File

@ -7,6 +7,12 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_ follows `Semantic versioning`_
4.24.0
------
- Add docs on ``@containers.copy()`` decorator.
- Refactor ``@containers.copy()`` decorator.
- Refactor async mode support in containers module.
4.23.5 4.23.5
------ ------
- Fix docs publishing. - Fix docs publishing.

View File

@ -0,0 +1,31 @@
"""Declarative container provider copying with ``@copy()`` decorator."""
import sqlite3
from unittest import mock
from dependency_injector import containers, providers
class Service:
def __init__(self, db):
self.db = db
class SourceContainer(containers.DeclarativeContainer):
database = providers.Singleton(sqlite3.connect, ':memory:')
service = providers.Factory(Service, db=database)
# Copy ``SourceContainer`` providers into ``DestinationContainer``:
@containers.copy(SourceContainer)
class DestinationContainer(SourceContainer):
database = providers.Singleton(mock.Mock)
if __name__ == '__main__':
container = DestinationContainer()
service = container.service()
assert isinstance(service.db, mock.Mock)

View File

@ -1,4 +1,4 @@
"""Declarative container provider overriding with `@override()` decorator.""" """Declarative container provider overriding with ``@override()`` decorator."""
import sqlite3 import sqlite3
from unittest import mock from unittest import mock
@ -11,7 +11,7 @@ class Container(containers.DeclarativeContainer):
database = providers.Singleton(sqlite3.connect, ':memory:') database = providers.Singleton(sqlite3.connect, ':memory:')
# Overriding `Container` with `OverridingContainer`: # Overriding ``Container`` with ``OverridingContainer``:
@containers.override(Container) @containers.override(Container)
class OverridingContainer(containers.DeclarativeContainer): class OverridingContainer(containers.DeclarativeContainer):

View File

@ -1,6 +1,6 @@
"""Top-level package.""" """Top-level package."""
__version__ = '4.23.5' __version__ = '4.24.0'
"""Version number. """Version number.
:type: str :type: str

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,3 @@ cpdef bint is_container(object instance)
cpdef object _check_provider_type(object container, object provider) cpdef object _check_provider_type(object container, object provider)
cpdef bint _isawaitable(object instance)

View File

@ -1,6 +1,5 @@
"""Containers module.""" """Containers module."""
import inspect
import sys import sys
try: try:
@ -11,6 +10,7 @@ except ImportError:
import six import six
from . import providers, errors from . import providers, errors
from .providers cimport __is_future_or_coroutine
if sys.version_info[:2] >= (3, 6): if sys.version_info[:2] >= (3, 6):
@ -276,7 +276,7 @@ class DynamicContainer(Container):
for provider in self.traverse(types=[providers.Resource]): for provider in self.traverse(types=[providers.Resource]):
resource = provider.init() resource = provider.init()
if _isawaitable(resource): if __is_future_or_coroutine(resource):
futures.append(resource) futures.append(resource)
if futures: if futures:
@ -289,7 +289,7 @@ class DynamicContainer(Container):
for provider in self.traverse(types=[providers.Resource]): for provider in self.traverse(types=[providers.Resource]):
shutdown = provider.shutdown() shutdown = provider.shutdown()
if _isawaitable(shutdown): if __is_future_or_coroutine(shutdown):
futures.append(shutdown) futures.append(shutdown)
if futures: if futures:
@ -659,7 +659,7 @@ def override(object container):
def copy(object container): def copy(object container):
""":py:class:`DeclarativeContainer` copying decorator. """:py:class:`DeclarativeContainer` copying decorator.
This decorator copy all providers from provided container to decorated one. This decorator copies all providers from provided container to decorated one.
If one of the decorated container providers matches to source container If one of the decorated container providers matches to source container
providers by name, it would be replaced by reference. providers by name, it would be replaced by reference.
@ -676,7 +676,7 @@ def copy(object container):
try: try:
source_provider = source_providers[name] source_provider = source_providers[name]
except KeyError: except KeyError:
... continue
else: else:
memo[id(source_provider)] = provider memo[id(source_provider)] = provider
@ -711,10 +711,3 @@ cpdef object _check_provider_type(object container, object provider):
if not isinstance(provider, container.provider_type): if not isinstance(provider, container.provider_type):
raise errors.Error('{0} can contain only {1} ' raise errors.Error('{0} can contain only {1} '
'instances'.format(container, container.provider_type)) 'instances'.format(container, container.provider_type))
cpdef bint _isawaitable(object instance):
try:
return <bint> inspect.isawaitable(instance)
except AttributeError:
return <bint> False