Merge remote-tracking branch 'origin/docs_update_for_0.11'
31
README.rst
|
@ -67,7 +67,10 @@ Examples
|
|||
"""Concept example of `Dependency Injector`."""
|
||||
|
||||
import sqlite3
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
class UsersService(object):
|
||||
|
@ -87,20 +90,20 @@ Examples
|
|||
self.users_service = users_service
|
||||
|
||||
|
||||
class Services(di.DeclarativeCatalog):
|
||||
class Services(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of service providers."""
|
||||
|
||||
database = di.Singleton(sqlite3.connect, ':memory:')
|
||||
""":type: di.Provider -> sqlite3.Connection"""
|
||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||
""":type: providers.Provider -> sqlite3.Connection"""
|
||||
|
||||
users = di.Factory(UsersService,
|
||||
db=database)
|
||||
""":type: di.Provider -> UsersService"""
|
||||
users = providers.Factory(UsersService,
|
||||
db=database)
|
||||
""":type: providers.Provider -> UsersService"""
|
||||
|
||||
auth = di.Factory(AuthService,
|
||||
db=database,
|
||||
users_service=users)
|
||||
""":type: di.Provider -> AuthService"""
|
||||
auth = providers.Factory(AuthService,
|
||||
db=database,
|
||||
users_service=users)
|
||||
""":type: providers.Provider -> AuthService"""
|
||||
|
||||
|
||||
# Retrieving catalog providers:
|
||||
|
@ -115,9 +118,9 @@ Examples
|
|||
|
||||
|
||||
# Making some "inline" injections:
|
||||
@di.inject(users_service=Services.users)
|
||||
@di.inject(auth_service=Services.auth)
|
||||
@di.inject(database=Services.database)
|
||||
@injections.inject(users_service=Services.users)
|
||||
@injections.inject(auth_service=Services.auth)
|
||||
@injections.inject(database=Services.database)
|
||||
def example(users_service, auth_service, database):
|
||||
"""Example callback."""
|
||||
assert users_service.db is auth_service.db
|
||||
|
|
|
@ -47,7 +47,11 @@ from .errors import UndefinedProviderError
|
|||
from . import catalogs
|
||||
catalog = catalogs
|
||||
|
||||
VERSION = '0.10.5'
|
||||
VERSION = '0.11.0'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
|
||||
|
||||
__all__ = (
|
||||
|
|
|
@ -7,40 +7,79 @@ from .errors import UndefinedProviderError
|
|||
|
||||
from .utils import is_provider
|
||||
from .utils import is_catalog
|
||||
from .utils import is_declarative_catalog
|
||||
from .utils import ensure_is_provider
|
||||
from .utils import ensure_is_catalog_bundle
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class CatalogBundle(object):
|
||||
"""Bundle of catalog providers."""
|
||||
"""Bundle of catalog providers.
|
||||
|
||||
:py:class:`CatalogBundle` is a frozen, limited collection of catalog
|
||||
providers. While catalog could be used as a centralized place for
|
||||
particular providers group, such bundles of catalog providers can be used
|
||||
for creating several frozen, limited scopes that could be passed to
|
||||
different subsystems.
|
||||
|
||||
:py:class:`CatalogBundle` has API's parity with catalogs
|
||||
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) in terms of
|
||||
retrieving the providers, but it is "frozen" in terms of modification
|
||||
provider's list.
|
||||
|
||||
:py:class:`CatalogBundle` is considered to be dependable on catalogs
|
||||
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) entity by
|
||||
its design.
|
||||
"""
|
||||
|
||||
catalog = None
|
||||
""":type: DeclarativeCatalog"""
|
||||
"""Bundle's catalog.
|
||||
|
||||
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
|
||||
"""
|
||||
|
||||
__IS_CATALOG_BUNDLE__ = True
|
||||
__slots__ = ('providers', '__dict__')
|
||||
|
||||
@classmethod
|
||||
def sub_cls_factory(cls, catalog):
|
||||
"""Create bundle subclass for catalog.
|
||||
|
||||
:return: Subclass of :py:class:`CatalogBundle`.
|
||||
:rtype: :py:class:`CatalogBundle`
|
||||
"""
|
||||
return type('BundleSubclass', (cls,), dict(catalog=catalog))
|
||||
|
||||
def __init__(self, *providers):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param providers: Tuple of catalog's bundle providers.
|
||||
:type providers: tuple[
|
||||
:py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
self.providers = dict()
|
||||
"""Dictionary of all providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
|
||||
for provider in providers:
|
||||
provider_name = self.catalog.get_provider_bind_name(provider)
|
||||
self.providers[provider_name] = provider
|
||||
self.__dict__.update(self.providers)
|
||||
super(CatalogBundle, self).__init__()
|
||||
|
||||
@classmethod
|
||||
def sub_cls_factory(cls, catalog):
|
||||
"""Create bundle class for catalog.
|
||||
|
||||
:rtype: CatalogBundle
|
||||
:return: Subclass of CatalogBundle
|
||||
"""
|
||||
return type('BundleSubclass', (cls,), dict(catalog=catalog))
|
||||
|
||||
def get_provider(self, name):
|
||||
"""Return provider with specified name or raise an error."""
|
||||
"""Return provider with specified name or raise an error.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
|
||||
:return: Provider with specified name.
|
||||
:rtype: :py:class:`dependency_injector.providers.Provider`
|
||||
"""
|
||||
try:
|
||||
return self.providers[name]
|
||||
except KeyError:
|
||||
|
@ -48,18 +87,33 @@ class CatalogBundle(object):
|
|||
self))
|
||||
|
||||
def has_provider(self, name):
|
||||
"""Check if there is provider with certain name."""
|
||||
"""Check if there is provider with certain name.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return name in self.providers
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Raise an error on every attempt to get undefined provider."""
|
||||
"""Return provider with specified name or raise en error.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
"""
|
||||
if item.startswith('__') and item.endswith('__'):
|
||||
return super(CatalogBundle, self).__getattr__(item)
|
||||
raise UndefinedProviderError('Provider "{0}" is not a part '
|
||||
'of {1}'.format(item, self))
|
||||
|
||||
def __repr__(self):
|
||||
"""Return string representation of catalog bundle."""
|
||||
"""Return string representation of catalog's bundle.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return '<{0}.Bundle({1})>'.format(
|
||||
self.catalog.name, ', '.join(six.iterkeys(self.providers)))
|
||||
|
||||
|
@ -68,7 +122,22 @@ class CatalogBundle(object):
|
|||
|
||||
@six.python_2_unicode_compatible
|
||||
class DynamicCatalog(object):
|
||||
"""Catalog of providers."""
|
||||
"""Dynamic catalog of providers.
|
||||
|
||||
: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).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
services = DynamicCatalog(auth=providers.Factory(AuthService),
|
||||
users=providers.Factory(UsersService))
|
||||
|
||||
users_service = services.users()
|
||||
"""
|
||||
|
||||
__IS_CATALOG__ = True
|
||||
__slots__ = ('name', 'providers', 'provider_names', 'overridden_by',
|
||||
|
@ -77,64 +146,132 @@ class DynamicCatalog(object):
|
|||
def __init__(self, **providers):
|
||||
"""Initializer.
|
||||
|
||||
:type providers: dict[str, dependency_injector.providers.Provider]
|
||||
:param providers: Dictionary of catalog providers.
|
||||
:type providers:
|
||||
dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
self.Bundle = CatalogBundle.sub_cls_factory(self)
|
||||
"""Catalog's bundle class.
|
||||
|
||||
:type: :py:class:`CatalogBundle`
|
||||
"""
|
||||
|
||||
self.name = '.'.join((self.__class__.__module__,
|
||||
self.__class__.__name__))
|
||||
self.providers = dict()
|
||||
self.provider_names = dict()
|
||||
self.overridden_by = tuple()
|
||||
"""Catalog's name.
|
||||
|
||||
self.Bundle = CatalogBundle.sub_cls_factory(self)
|
||||
By default, it is catalog's module + catalog's class name.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
|
||||
self.providers = dict()
|
||||
"""Dictionary of all providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
|
||||
self.provider_names = dict()
|
||||
|
||||
self.overridden_by = tuple()
|
||||
"""Tuple of overriding catalogs.
|
||||
|
||||
:type: tuple[
|
||||
:py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`]
|
||||
"""
|
||||
|
||||
self.bind_providers(providers)
|
||||
super(DynamicCatalog, self).__init__()
|
||||
|
||||
def is_bundle_owner(self, bundle):
|
||||
"""Check if catalog is bundle owner."""
|
||||
"""Check if catalog is bundle owner.
|
||||
|
||||
:param bundle: Catalog's bundle instance.
|
||||
:type bundle: :py:class:`CatalogBundle`
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return ensure_is_catalog_bundle(bundle) and bundle.catalog is self
|
||||
|
||||
def get_provider_bind_name(self, provider):
|
||||
"""Return provider's name in catalog."""
|
||||
"""Return provider's name in catalog.
|
||||
|
||||
:param provider: Provider instance.
|
||||
:type provider: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
|
||||
:return: Provider's name.
|
||||
:rtype: str
|
||||
"""
|
||||
if not self.is_provider_bound(provider):
|
||||
raise Error('Can not find bind name for {0} in catalog {1}'.format(
|
||||
provider, self))
|
||||
return self.provider_names[provider]
|
||||
|
||||
def is_provider_bound(self, provider):
|
||||
"""Check if provider is bound to the catalog."""
|
||||
"""Check if provider is bound to the catalog.
|
||||
|
||||
:param provider: Provider instance.
|
||||
:type provider: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return provider in self.provider_names
|
||||
|
||||
def filter(self, provider_type):
|
||||
"""Return dict of providers, that are instance of provided type."""
|
||||
"""Return dictionary of providers, that are instance of provided type.
|
||||
|
||||
:param provider_type: Provider's type.
|
||||
:type provider_type: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
return dict((name, provider)
|
||||
for name, provider in six.iteritems(self.providers)
|
||||
if isinstance(provider, provider_type))
|
||||
|
||||
@property
|
||||
def is_overridden(self):
|
||||
"""Check if catalog is overridden by another catalog."""
|
||||
"""Read-only property that is set to ``True`` if catalog is overridden.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return bool(self.overridden_by)
|
||||
|
||||
@property
|
||||
def last_overriding(self):
|
||||
"""Return last overriding catalog."""
|
||||
try:
|
||||
return self.overridden_by[-1]
|
||||
except (TypeError, IndexError):
|
||||
raise Error('Catalog {0} is not overridden'.format(self))
|
||||
"""Read-only reference to the last overriding catalog, if any.
|
||||
|
||||
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog` |
|
||||
None
|
||||
"""
|
||||
return self.overridden_by[-1] if self.overridden_by else None
|
||||
|
||||
def override(self, overriding):
|
||||
"""Override current catalog providers by overriding catalog providers.
|
||||
|
||||
:type overriding: DynamicCatalog
|
||||
:param overriding: Overriding catalog.
|
||||
:type overriding: :py:class:`DeclarativeCatalog` |
|
||||
:py:class:`DynamicCatalog`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if trying to
|
||||
override catalog by itself
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if overriding is self:
|
||||
raise Error('Catalog {0} could not be overridden '
|
||||
'with itself'.format(self))
|
||||
self.overridden_by += (overriding,)
|
||||
for name, provider in six.iteritems(overriding.providers):
|
||||
self.get_provider(name).override(provider)
|
||||
|
||||
def reset_last_overriding(self):
|
||||
"""Reset last overriding catalog."""
|
||||
"""Reset last overriding catalog.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if not self.is_overridden:
|
||||
raise Error('Catalog {0} is not overridden'.format(self))
|
||||
self.overridden_by = self.overridden_by[:-1]
|
||||
|
@ -142,13 +279,25 @@ class DynamicCatalog(object):
|
|||
provider.reset_last_overriding()
|
||||
|
||||
def reset_override(self):
|
||||
"""Reset all overridings for all catalog providers."""
|
||||
"""Reset all overridings for all catalog providers.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.overridden_by = tuple()
|
||||
for provider in six.itervalues(self.providers):
|
||||
provider.reset_override()
|
||||
|
||||
def get_provider(self, name):
|
||||
"""Return provider with specified name or raise an error."""
|
||||
"""Return provider with specified name or raise an error.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
|
||||
:return: Provider with specified name.
|
||||
:rtype: :py:class:`dependency_injector.providers.Provider`
|
||||
"""
|
||||
try:
|
||||
return self.providers[name]
|
||||
except KeyError:
|
||||
|
@ -156,7 +305,18 @@ class DynamicCatalog(object):
|
|||
'name - {1}'.format(self, name))
|
||||
|
||||
def bind_provider(self, name, provider):
|
||||
"""Bind provider to catalog with specified name."""
|
||||
"""Bind provider to catalog with specified name.
|
||||
|
||||
:param name: Name of the provider.
|
||||
:type name: str
|
||||
|
||||
:param provider: Provider instance.
|
||||
:type provider: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
provider = ensure_is_provider(provider)
|
||||
|
||||
if name in self.providers:
|
||||
|
@ -170,29 +330,66 @@ class DynamicCatalog(object):
|
|||
self.provider_names[provider] = name
|
||||
|
||||
def bind_providers(self, providers):
|
||||
"""Bind providers dictionary to catalog."""
|
||||
"""Bind providers dictionary to catalog.
|
||||
|
||||
:param providers: Dictionary of providers, where key is a name
|
||||
and value is a provider.
|
||||
:type providers:
|
||||
dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
for name, provider in six.iteritems(providers):
|
||||
self.bind_provider(name, provider)
|
||||
|
||||
def has_provider(self, name):
|
||||
"""Check if there is provider with certain name."""
|
||||
"""Check if there is provider with certain name.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return name in self.providers
|
||||
|
||||
def unbind_provider(self, name):
|
||||
"""Remove provider binding."""
|
||||
"""Remove provider binding.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
provider = self.get_provider(name)
|
||||
del self.providers[name]
|
||||
del self.provider_names[provider]
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Return provider with specified name or raise en error."""
|
||||
"""Return provider with specified name or raise en error.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
"""
|
||||
return self.get_provider(name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
"""Handle setting of catalog attributes.
|
||||
|
||||
Setting of attributes works as usual, but if value of attribute is
|
||||
provider, this provider will be bound to catalog correctly.
|
||||
provider, this provider will be bound to catalog.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:param value: Attribute's value.
|
||||
:type value: :py:class:`dependency_injector.providers.Provider` |
|
||||
object
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if is_provider(value):
|
||||
return self.bind_provider(name, value)
|
||||
|
@ -202,12 +399,20 @@ class DynamicCatalog(object):
|
|||
"""Handle deleting of catalog attibute.
|
||||
|
||||
Deleting of attributes works as usual, but if value of attribute is
|
||||
provider, this provider will be unbound from catalog correctly.
|
||||
provider, this provider will be unbound from catalog.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.unbind_provider(name)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return Python representation of catalog."""
|
||||
"""Return Python representation of catalog.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return '<{0}({1})>'.format(self.name,
|
||||
', '.join(six.iterkeys(self.providers)))
|
||||
|
||||
|
@ -233,44 +438,70 @@ class DeclarativeCatalogMetaClass(type):
|
|||
|
||||
cls = type.__new__(mcs, class_name, bases, attributes)
|
||||
|
||||
cls.catalog = DynamicCatalog()
|
||||
cls.catalog.name = '.'.join((cls.__module__, cls.__name__))
|
||||
cls.catalog.bind_providers(dict(providers))
|
||||
cls._catalog = DynamicCatalog()
|
||||
cls._catalog.name = '.'.join((cls.__module__, cls.__name__))
|
||||
cls._catalog.bind_providers(dict(providers))
|
||||
|
||||
cls.cls_providers = dict(cls_providers)
|
||||
cls.inherited_providers = dict(inherited_providers)
|
||||
|
||||
cls.Bundle = cls.catalog.Bundle
|
||||
cls.Bundle = cls._catalog.Bundle
|
||||
|
||||
return cls
|
||||
|
||||
@property
|
||||
def name(cls):
|
||||
"""Return catalog's name."""
|
||||
return cls.catalog.name
|
||||
"""Read-only property that represents catalog's name.
|
||||
|
||||
Catalog's name is catalog's module + catalog's class name.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
return cls._catalog.name
|
||||
|
||||
@property
|
||||
def providers(cls):
|
||||
"""Return dict of catalog's providers."""
|
||||
return cls.catalog.providers
|
||||
"""Read-only dictionary of all providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
return cls._catalog.providers
|
||||
|
||||
@property
|
||||
def overridden_by(cls):
|
||||
"""Return tuple of overriding catalogs."""
|
||||
return cls.catalog.overridden_by
|
||||
"""Tuple of overriding catalogs.
|
||||
|
||||
:type: tuple[
|
||||
:py:class:`DeclarativeCatalog` |
|
||||
:py:class:`DynamicCatalog`]
|
||||
"""
|
||||
return cls._catalog.overridden_by
|
||||
|
||||
@property
|
||||
def is_overridden(cls):
|
||||
"""Check if catalog is overridden by another catalog."""
|
||||
return cls.catalog.is_overridden
|
||||
"""Read-only property that is set to ``True`` if catalog is overridden.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return cls._catalog.is_overridden
|
||||
|
||||
@property
|
||||
def last_overriding(cls):
|
||||
"""Return last overriding catalog."""
|
||||
return cls.catalog.last_overriding
|
||||
"""Read-only reference to the last overriding catalog, if any.
|
||||
|
||||
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog` |
|
||||
None
|
||||
"""
|
||||
return cls._catalog.last_overriding
|
||||
|
||||
def __getattr__(cls, name):
|
||||
"""Return provider with specified name or raise en error."""
|
||||
"""Return provider with specified name or raise en error.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
"""
|
||||
raise UndefinedProviderError('There is no provider "{0}" in '
|
||||
'catalog {1}'.format(name, cls))
|
||||
|
||||
|
@ -278,24 +509,41 @@ class DeclarativeCatalogMetaClass(type):
|
|||
"""Handle setting of catalog attributes.
|
||||
|
||||
Setting of attributes works as usual, but if value of attribute is
|
||||
provider, this provider will be bound to catalog correctly.
|
||||
provider, this provider will be bound to catalog.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:param value: Attribute's value.
|
||||
:type value: :py:class:`dependency_injector.providers.Provider` |
|
||||
object
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if is_provider(value):
|
||||
setattr(cls.catalog, name, value)
|
||||
setattr(cls._catalog, name, value)
|
||||
return super(DeclarativeCatalogMetaClass, cls).__setattr__(name, value)
|
||||
|
||||
def __delattr__(cls, name):
|
||||
"""Handle deleting of catalog attibute.
|
||||
|
||||
Deleting of attributes works as usual, but if value of attribute is
|
||||
provider, this provider will be unbound from catalog correctly.
|
||||
provider, this provider will be unbound from catalog.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if is_provider(getattr(cls, name)):
|
||||
delattr(cls.catalog, name)
|
||||
delattr(cls._catalog, name)
|
||||
return super(DeclarativeCatalogMetaClass, cls).__delattr__(name)
|
||||
|
||||
def __repr__(cls):
|
||||
"""Return string representation of the catalog."""
|
||||
"""Return string representation of the catalog.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return '<{0}({1})>'.format(cls.name,
|
||||
', '.join(six.iterkeys(cls.providers)))
|
||||
|
||||
|
@ -304,121 +552,274 @@ class DeclarativeCatalogMetaClass(type):
|
|||
|
||||
@six.add_metaclass(DeclarativeCatalogMetaClass)
|
||||
class DeclarativeCatalog(object):
|
||||
"""Declarative catalog catalog of providers.
|
||||
"""Declarative catalog of providers.
|
||||
|
||||
:type name: str
|
||||
:param name: Catalog's name
|
||||
:py:class:`DeclarativeCatalog` is a catalog 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 catalog is deterministic (catalog
|
||||
will not change its structure in runtime).
|
||||
|
||||
:type catalog: DynamicCatalog
|
||||
:param catalog: Instance of dynamic catalog
|
||||
.. code-block:: python
|
||||
|
||||
:type Bundle: CatalogBundle
|
||||
:param Bundle: Catalog's bundle class
|
||||
class Services(DeclarativeCatalog):
|
||||
|
||||
:type providers: dict[str, dependency_injector.Provider]
|
||||
:param providers: Dict of all catalog providers, including inherited from
|
||||
parent catalogs
|
||||
auth = providers.Factory(AuthService)
|
||||
|
||||
:type cls_providers: dict[str, dependency_injector.Provider]
|
||||
:param cls_providers: Dict of current catalog providers
|
||||
users = providers.Factory(UsersService)
|
||||
|
||||
:type inherited_providers: dict[str, dependency_injector.Provider]
|
||||
:param inherited_providers: Dict of providers, that are inherited from
|
||||
parent catalogs
|
||||
|
||||
:type overridden_by: tuple[DeclarativeCatalog]
|
||||
:param overridden_by: Tuple of overriding catalogs
|
||||
|
||||
:type is_overridden: bool
|
||||
:param is_overridden: Read-only, evaluated in runtime, property that is
|
||||
set to True if catalog is overridden
|
||||
|
||||
:type last_overriding: DeclarativeCatalog | None
|
||||
:param last_overriding: Reference to the last overriding catalog, if any
|
||||
users_service = Services.users()
|
||||
"""
|
||||
|
||||
Bundle = CatalogBundle
|
||||
"""Catalog's bundle class.
|
||||
|
||||
:type: :py:class:`CatalogBundle`
|
||||
"""
|
||||
|
||||
name = str()
|
||||
"""Read-only property that represents catalog's name.
|
||||
|
||||
Catalog's name is catalog's module + catalog's class name.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
|
||||
cls_providers = dict()
|
||||
"""Read-only dictionary of current catalog 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`]
|
||||
"""
|
||||
|
||||
providers = dict()
|
||||
"""Read-only dictionary of all providers.
|
||||
|
||||
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
|
||||
overridden_by = tuple()
|
||||
is_overridden = bool
|
||||
last_overriding = None
|
||||
"""Tuple of overriding catalogs.
|
||||
|
||||
catalog = DynamicCatalog
|
||||
:type: tuple[:py:class:`DeclarativeCatalog` |
|
||||
:py:class:`DynamicCatalog`]
|
||||
"""
|
||||
|
||||
is_overridden = bool
|
||||
"""Read-only property that is set to ``True`` if catalog is overridden.
|
||||
|
||||
:type: bool
|
||||
"""
|
||||
|
||||
last_overriding = None
|
||||
"""Read-only reference to the last overriding catalog, if any.
|
||||
|
||||
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog` | None
|
||||
"""
|
||||
|
||||
_catalog = DynamicCatalog
|
||||
|
||||
__IS_CATALOG__ = True
|
||||
|
||||
@classmethod
|
||||
def is_bundle_owner(cls, bundle):
|
||||
"""Check if catalog is bundle owner."""
|
||||
return cls.catalog.is_bundle_owner(bundle)
|
||||
"""Check if catalog is bundle owner.
|
||||
|
||||
:param bundle: Catalog's bundle instance.
|
||||
:type bundle: :py:class:`CatalogBundle`
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return cls._catalog.is_bundle_owner(bundle)
|
||||
|
||||
@classmethod
|
||||
def get_provider_bind_name(cls, provider):
|
||||
"""Return provider's name in catalog."""
|
||||
return cls.catalog.get_provider_bind_name(provider)
|
||||
"""Return provider's name in catalog.
|
||||
|
||||
:param provider: Provider instance.
|
||||
:type provider: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
|
||||
:return: Provider's name.
|
||||
:rtype: str
|
||||
"""
|
||||
return cls._catalog.get_provider_bind_name(provider)
|
||||
|
||||
@classmethod
|
||||
def is_provider_bound(cls, provider):
|
||||
"""Check if provider is bound to the catalog."""
|
||||
return cls.catalog.is_provider_bound(provider)
|
||||
"""Check if provider is bound to the catalog.
|
||||
|
||||
:param provider: Provider instance.
|
||||
:type provider: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return cls._catalog.is_provider_bound(provider)
|
||||
|
||||
@classmethod
|
||||
def filter(cls, provider_type):
|
||||
"""Return dict of providers, that are instance of provided type."""
|
||||
return cls.catalog.filter(provider_type)
|
||||
"""Return dictionary of providers, that are instance of provided type.
|
||||
|
||||
:param provider_type: Provider's type.
|
||||
:type provider_type: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
"""
|
||||
return cls._catalog.filter(provider_type)
|
||||
|
||||
@classmethod
|
||||
def override(cls, overriding):
|
||||
"""Override current catalog providers by overriding catalog providers.
|
||||
|
||||
:type overriding: DeclarativeCatalog | DynamicCatalog
|
||||
:param overriding: Overriding catalog.
|
||||
:type overriding: :py:class:`DeclarativeCatalog` |
|
||||
:py:class:`DynamicCatalog`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if trying to
|
||||
override catalog by itself or its subclasses
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
return cls.catalog.override(overriding)
|
||||
if is_declarative_catalog(overriding) and issubclass(cls, overriding):
|
||||
raise Error('Catalog {0} could not be overridden '
|
||||
'with itself or its subclasses'.format(cls))
|
||||
return cls._catalog.override(overriding)
|
||||
|
||||
@classmethod
|
||||
def reset_last_overriding(cls):
|
||||
"""Reset last overriding catalog."""
|
||||
cls.catalog.reset_last_overriding()
|
||||
"""Reset last overriding catalog.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
cls._catalog.reset_last_overriding()
|
||||
|
||||
@classmethod
|
||||
def reset_override(cls):
|
||||
"""Reset all overridings for all catalog providers."""
|
||||
cls.catalog.reset_override()
|
||||
"""Reset all overridings for all catalog providers.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
cls._catalog.reset_override()
|
||||
|
||||
@classmethod
|
||||
def get_provider(cls, name):
|
||||
"""Return provider with specified name or raise an error."""
|
||||
return cls.catalog.get_provider(name)
|
||||
"""Return provider with specified name or raise an error.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
|
||||
:return: Provider with specified name.
|
||||
:rtype: :py:class:`dependency_injector.providers.Provider`
|
||||
"""
|
||||
return cls._catalog.get_provider(name)
|
||||
|
||||
get = get_provider # Backward compatibility for versions < 0.11.*
|
||||
|
||||
@classmethod
|
||||
def bind_provider(cls, name, provider):
|
||||
"""Bind provider to catalog with specified name."""
|
||||
"""Bind provider to catalog with specified name.
|
||||
|
||||
:param name: Name of the provider.
|
||||
:type name: str
|
||||
|
||||
:param provider: Provider instance.
|
||||
:type provider: :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
setattr(cls, name, provider)
|
||||
|
||||
@classmethod
|
||||
def bind_providers(cls, providers):
|
||||
"""Bind providers dictionary to catalog."""
|
||||
"""Bind providers dictionary to catalog.
|
||||
|
||||
:param providers: Dictionary of providers, where key is a name
|
||||
and value is a provider.
|
||||
:type providers:
|
||||
dict[str, :py:class:`dependency_injector.providers.Provider`]
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
for name, provider in six.iteritems(providers):
|
||||
setattr(cls, name, provider)
|
||||
|
||||
@classmethod
|
||||
def has_provider(cls, name):
|
||||
"""Check if there is provider with certain name."""
|
||||
"""Check if there is provider with certain name.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return hasattr(cls, name)
|
||||
|
||||
has = has_provider # Backward compatibility for versions < 0.11.*
|
||||
|
||||
@classmethod
|
||||
def unbind_provider(cls, name):
|
||||
"""Remove provider binding."""
|
||||
"""Remove provider binding.
|
||||
|
||||
:param name: Provider's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
delattr(cls, name)
|
||||
|
||||
get = get_provider # Backward compatibility for versions < 0.11.*
|
||||
has = has_provider # Backward compatibility for versions < 0.11.*
|
||||
@classmethod
|
||||
def __getattr__(cls, name): # pragma: no cover
|
||||
"""Return provider with specified name or raise en error.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.UndefinedProviderError`
|
||||
"""
|
||||
raise NotImplementedError('Implementated in metaclass')
|
||||
|
||||
@classmethod
|
||||
def __setattr__(cls, name, value): # pragma: no cover
|
||||
"""Handle setting of catalog attributes.
|
||||
|
||||
Setting of attributes works as usual, but if value of attribute is
|
||||
provider, this provider will be bound to catalog.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:param value: Attribute's value.
|
||||
:type value: :py:class:`dependency_injector.providers.Provider` |
|
||||
object
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
raise NotImplementedError('Implementated in metaclass')
|
||||
|
||||
@classmethod
|
||||
def __delattr__(cls, name): # pragma: no cover
|
||||
"""Handle deleting of catalog attibute.
|
||||
|
||||
Deleting of attributes works as usual, but if value of attribute is
|
||||
provider, this provider will be unbound from catalog.
|
||||
|
||||
:param name: Attribute's name.
|
||||
:type name: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
raise NotImplementedError('Implementated in metaclass')
|
||||
|
||||
|
||||
# Backward compatibility for versions < 0.11.*
|
||||
|
@ -426,7 +827,14 @@ AbstractCatalog = DeclarativeCatalog
|
|||
|
||||
|
||||
def override(catalog):
|
||||
"""Catalog overriding decorator."""
|
||||
""":py:class:`DeclarativeCatalog` overriding decorator.
|
||||
|
||||
:param catalog: Catalog that should be overridden by decorated catalog.
|
||||
:type catalog: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
|
||||
|
||||
:return: Declarative catalog's overriding decorator.
|
||||
:rtype: callable(:py:class:`DeclarativeCatalog`)
|
||||
"""
|
||||
def decorator(overriding_catalog):
|
||||
"""Overriding decorator."""
|
||||
catalog.override(overriding_catalog)
|
||||
|
|
|
@ -2,8 +2,21 @@
|
|||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base error."""
|
||||
"""Base error.
|
||||
|
||||
All dependency injector errors extend this error class.
|
||||
"""
|
||||
|
||||
|
||||
class UndefinedProviderError(Error, AttributeError):
|
||||
"""Undefined provider error."""
|
||||
"""Undefined provider error.
|
||||
|
||||
This error is used when provider could not be defined, for example:
|
||||
|
||||
- provider with certain name could not be defined
|
||||
- catalog's name of the certain provider could not be defined
|
||||
- etc...
|
||||
|
||||
Also this error extends standard :py:class:`AttributeError`. This gives
|
||||
possibility to use it correctly with ``__getattr__()``.
|
||||
"""
|
||||
|
|
|
@ -13,33 +13,60 @@ from .utils import is_kwarg_injection
|
|||
from .errors import Error
|
||||
|
||||
|
||||
IS_PYPY = '__pypy__' in sys.builtin_module_names
|
||||
if IS_PYPY or six.PY3: # pragma: no cover
|
||||
OBJECT_INIT = six.get_unbound_function(object.__init__)
|
||||
_IS_PYPY = '__pypy__' in sys.builtin_module_names
|
||||
if _IS_PYPY or six.PY3: # pragma: no cover
|
||||
_OBJECT_INIT = six.get_unbound_function(object.__init__)
|
||||
else: # pragma: no cover
|
||||
OBJECT_INIT = None
|
||||
_OBJECT_INIT = None
|
||||
|
||||
|
||||
class Injection(object):
|
||||
"""Base injection class."""
|
||||
"""Base injection class.
|
||||
|
||||
All injections extend this class.
|
||||
"""
|
||||
|
||||
__IS_INJECTION__ = True
|
||||
__slots__ = ('injectable', 'is_provider')
|
||||
|
||||
def __init__(self, injectable):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param injectable: Injectable value, could be provider or any
|
||||
other object.
|
||||
:type injectable: object |
|
||||
:py:class:`dependency_injector.providers.Provider`
|
||||
"""
|
||||
self.injectable = injectable
|
||||
"""Injectable value, could be provider or any other object.
|
||||
|
||||
:type: object | :py:class:`dependency_injector.providers.Provider`
|
||||
"""
|
||||
|
||||
self.is_provider = is_provider(injectable)
|
||||
"""Flag that is set to ``True`` if injectable value is provider.
|
||||
|
||||
:type: bool
|
||||
"""
|
||||
|
||||
super(Injection, self).__init__()
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Return injectable value."""
|
||||
"""Read-only property that represents injectable value.
|
||||
|
||||
Injectable values are provided "as is", except of providers
|
||||
(subclasses of :py:class:`dependency_injector.providers.Provider`).
|
||||
Providers will be called every time, when injection needs to be done.
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
if self.is_provider:
|
||||
return self.injectable()
|
||||
return self.injectable
|
||||
|
||||
|
||||
class NamedInjection(Injection):
|
||||
class _NamedInjection(Injection):
|
||||
"""Base class of named injections."""
|
||||
|
||||
__slots__ = ('name',)
|
||||
|
@ -47,7 +74,7 @@ class NamedInjection(Injection):
|
|||
def __init__(self, name, injectable):
|
||||
"""Initializer."""
|
||||
self.name = name
|
||||
super(NamedInjection, self).__init__(injectable)
|
||||
super(_NamedInjection, self).__init__(injectable)
|
||||
|
||||
|
||||
class Arg(Injection):
|
||||
|
@ -56,19 +83,19 @@ class Arg(Injection):
|
|||
__IS_ARG_INJECTION__ = True
|
||||
|
||||
|
||||
class KwArg(NamedInjection):
|
||||
class KwArg(_NamedInjection):
|
||||
"""Keyword argument injection."""
|
||||
|
||||
__IS_KWARG_INJECTION__ = True
|
||||
|
||||
|
||||
class Attribute(NamedInjection):
|
||||
class Attribute(_NamedInjection):
|
||||
"""Attribute injection."""
|
||||
|
||||
__IS_ATTRIBUTE_INJECTION__ = True
|
||||
|
||||
|
||||
class Method(NamedInjection):
|
||||
class Method(_NamedInjection):
|
||||
"""Method injection."""
|
||||
|
||||
__IS_METHOD_INJECTION__ = True
|
||||
|
@ -77,7 +104,48 @@ class Method(NamedInjection):
|
|||
def inject(*args, **kwargs):
|
||||
"""Dependency injection decorator.
|
||||
|
||||
:return: (callable) -> (callable)
|
||||
:py:func:`inject` decorator can be used for making inline dependency
|
||||
injections. It patches decorated callable in such way that dependency
|
||||
injection will be done during every call of decorated callable.
|
||||
|
||||
:py:func:`inject` decorator supports different syntaxes of passing
|
||||
injections:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Positional arguments injections (simplified syntax):
|
||||
@inject(1, 2)
|
||||
def some_function(arg1, arg2):
|
||||
pass
|
||||
|
||||
# Keyword arguments injections (simplified syntax):
|
||||
@inject(arg1=1)
|
||||
@inject(arg2=2)
|
||||
def some_function(arg1, arg2):
|
||||
pass
|
||||
|
||||
# Keyword arguments injections (extended (full) syntax):
|
||||
@inject(KwArg('arg1', 1))
|
||||
@inject(KwArg('arg2', 2))
|
||||
def some_function(arg1, arg2):
|
||||
pass
|
||||
|
||||
# Keyword arguments injections into class init (simplified syntax):
|
||||
@inject(arg1=1)
|
||||
@inject(arg2=2)
|
||||
class SomeClass(object):
|
||||
|
||||
def __init__(self, arg1, arg2):
|
||||
pass
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:return: Class / callable decorator
|
||||
:rtype: (callable) -> (type | callable)
|
||||
"""
|
||||
arg_injections = _parse_args_injections(args)
|
||||
kwarg_injections = _parse_kwargs_injections(args, kwargs)
|
||||
|
@ -88,7 +156,7 @@ def inject(*args, **kwargs):
|
|||
cls = callback_or_cls
|
||||
try:
|
||||
cls_init = six.get_unbound_function(cls.__init__)
|
||||
assert cls_init is not OBJECT_INIT
|
||||
assert cls_init is not _OBJECT_INIT
|
||||
except (AttributeError, AssertionError):
|
||||
raise Error(
|
||||
'Class {0}.{1} has no __init__() '.format(cls.__module__,
|
||||
|
|
|
@ -16,7 +16,45 @@ from .errors import Error
|
|||
|
||||
|
||||
class Provider(object):
|
||||
"""Base provider class."""
|
||||
"""Base provider class.
|
||||
|
||||
:py:class:`Provider` is callable (implements ``__call__`` method). Every
|
||||
call to provider object returns provided result, according to the providing
|
||||
strategy of particular provider. This ``callable`` functionality is a
|
||||
regular part of providers API and it should be the same for all provider's
|
||||
subclasses.
|
||||
|
||||
Implementation of particular providing strategy should be done in
|
||||
:py:meth:`Provider._provide` of :py:class:`Provider` subclass. Current
|
||||
method is called every time when not overridden provider is called.
|
||||
|
||||
:py:class:`Provider` implements provider overriding logic that should be
|
||||
also common for all providers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
provider1 = Factory(SomeClass)
|
||||
provider2 = Factory(ChildSomeClass)
|
||||
|
||||
provider1.override(provider2)
|
||||
|
||||
some_instance = provider1()
|
||||
assert isinstance(some_instance, ChildSomeClass)
|
||||
|
||||
Also :py:class:`Provider` implements helper function for creating its
|
||||
delegates:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
provider = Factory(object)
|
||||
delegate = provider.delegate()
|
||||
|
||||
delegated = delegate()
|
||||
|
||||
assert provider is delegated
|
||||
|
||||
All providers should extend this class.
|
||||
"""
|
||||
|
||||
__IS_PROVIDER__ = True
|
||||
__slots__ = ('overridden_by',)
|
||||
|
@ -24,9 +62,23 @@ class Provider(object):
|
|||
def __init__(self):
|
||||
"""Initializer."""
|
||||
self.overridden_by = None
|
||||
"""Tuple of overriding providers, if any.
|
||||
|
||||
:type: tuple[:py:class:`Provider`] | None
|
||||
"""
|
||||
|
||||
super(Provider, self).__init__()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
Implementation of current method adds ``callable`` functionality for
|
||||
providers API and it should be common for all provider's subclasses.
|
||||
Also this method implements provider overriding logic that is also
|
||||
common for all providers. Implementation of particular providing
|
||||
strategy should be done in :py:meth:`Provider._provide` of
|
||||
:py:class:`Provider` subclass.
|
||||
"""
|
||||
if self.overridden_by:
|
||||
return self.last_overriding(*args, **kwargs)
|
||||
return self._provide(*args, **kwargs)
|
||||
|
@ -40,12 +92,30 @@ class Provider(object):
|
|||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def delegate(self):
|
||||
"""Return provider's delegate."""
|
||||
return Delegate(self)
|
||||
@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."""
|
||||
"""Override provider with another provider.
|
||||
|
||||
:param provider: Overriding provider.
|
||||
:type provider: :py:class:`Provider`
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||
"""
|
||||
if provider is self:
|
||||
raise Error('Provider {0} could not be overridden '
|
||||
'with itself'.format(self))
|
||||
|
@ -54,74 +124,174 @@ class Provider(object):
|
|||
else:
|
||||
self.overridden_by += (ensure_is_provider(provider),)
|
||||
|
||||
@property
|
||||
def is_overridden(self):
|
||||
"""Check if provider is overridden by another provider."""
|
||||
return bool(self.overridden_by)
|
||||
|
||||
@property
|
||||
def last_overriding(self):
|
||||
"""Return last overriding provider."""
|
||||
try:
|
||||
return self.overridden_by[-1]
|
||||
except (TypeError, IndexError):
|
||||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||
|
||||
def reset_last_overriding(self):
|
||||
"""Reset last overriding provider."""
|
||||
if not self.is_overridden:
|
||||
"""Reset last overriding provider.
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if provider is not
|
||||
overridden.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if not self.overridden_by:
|
||||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||
self.overridden_by = self.overridden_by[:-1]
|
||||
|
||||
def reset_override(self):
|
||||
"""Reset all overriding providers."""
|
||||
"""Reset all overriding providers.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.overridden_by = None
|
||||
|
||||
def delegate(self):
|
||||
"""Return provider's delegate.
|
||||
|
||||
:rtype: :py:class:`Delegate`
|
||||
"""
|
||||
return Delegate(self)
|
||||
|
||||
|
||||
class Delegate(Provider):
|
||||
"""Provider's delegate."""
|
||||
""":py:class:`Delegate` provider delegates another provider.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
provider = Factory(object)
|
||||
delegate = Delegate(provider)
|
||||
|
||||
delegated = delegate()
|
||||
|
||||
assert provider is delegated
|
||||
"""
|
||||
|
||||
__slots__ = ('delegated',)
|
||||
|
||||
def __init__(self, delegated):
|
||||
"""Initializer.
|
||||
|
||||
:type delegated: Provider
|
||||
:provider delegated: Delegated provider.
|
||||
:type delegated: :py:class:`Provider`
|
||||
"""
|
||||
self.delegated = ensure_is_provider(delegated)
|
||||
super(Delegate, self).__init__()
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
return self.delegated
|
||||
|
||||
|
||||
class Factory(Provider):
|
||||
"""Factory provider.
|
||||
""":py:class:`Factory` provider creates new instance on every call.
|
||||
|
||||
Factory provider creates new instance of specified class on every call.
|
||||
:py:class:`Factory` supports different syntaxes of passing injections:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# simplified syntax for passing positional and keyword argument
|
||||
# injections only:
|
||||
factory = Factory(SomeClass, 'arg1', 'arg2', arg3=3, arg4=4)
|
||||
|
||||
# extended (full) syntax for passing any type of injections:
|
||||
factory = Factory(SomeClass,
|
||||
injections.Arg(1),
|
||||
injections.Arg(2),
|
||||
injections.KwArg('some_arg', 3),
|
||||
injections.KwArg('other_arg', 4),
|
||||
injections.Attribute('some_attribute', 5))
|
||||
|
||||
Retrieving of provided instance can be performed via calling
|
||||
:py:class:`Factory` object:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
factory = Factory(SomeClass,
|
||||
some_arg1=1,
|
||||
some_arg2=2)
|
||||
some_object = factory()
|
||||
"""
|
||||
|
||||
__slots__ = ('provides', 'args', 'kwargs', 'attributes', 'methods')
|
||||
|
||||
def __init__(self, provides, *args, **kwargs):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param provides: Class or other callable that provides object
|
||||
for creation.
|
||||
:type provides: type | callable
|
||||
|
||||
:param args: Tuple of injections.
|
||||
:type args: tuple
|
||||
|
||||
:param kwargs: Dictionary of injections.
|
||||
:type kwargs: dict
|
||||
"""
|
||||
if not callable(provides):
|
||||
raise Error('Factory provider expects to get callable, ' +
|
||||
'got {0} instead'.format(str(provides)))
|
||||
self.provides = provides
|
||||
"""Class or other callable that provides object for creation.
|
||||
|
||||
:type: type | callable
|
||||
"""
|
||||
|
||||
self.args = _parse_args_injections(args)
|
||||
"""Tuple of positional argument injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
|
||||
"""
|
||||
|
||||
self.kwargs = _parse_kwargs_injections(args, kwargs)
|
||||
"""Tuple of keyword argument injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
|
||||
"""
|
||||
|
||||
self.attributes = tuple(injection
|
||||
for injection in args
|
||||
if is_attribute_injection(injection))
|
||||
"""Tuple of attribute injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
|
||||
"""
|
||||
|
||||
self.methods = tuple(injection
|
||||
for injection in args
|
||||
if is_method_injection(injection))
|
||||
"""Tuple of method injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Method`]
|
||||
"""
|
||||
|
||||
super(Factory, self).__init__()
|
||||
|
||||
@property
|
||||
def injections(self):
|
||||
"""Read-only tuple of all injections.
|
||||
|
||||
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
|
||||
"""
|
||||
return self.args + self.kwargs + self.attributes + self.methods
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
instance = self.provides(*_get_injectable_args(args, self.args),
|
||||
**_get_injectable_kwargs(kwargs, self.kwargs))
|
||||
for attribute in self.attributes:
|
||||
|
@ -131,48 +301,145 @@ class Factory(Provider):
|
|||
|
||||
return instance
|
||||
|
||||
@property
|
||||
def injections(self):
|
||||
"""Return tuple of all injections."""
|
||||
return self.args + self.kwargs + self.attributes + self.methods
|
||||
|
||||
|
||||
class Singleton(Provider):
|
||||
"""Singleton provider.
|
||||
""":py:class:`Singleton` provider returns same instance on every call.
|
||||
|
||||
:py:class:`Singleton` provider creates instance once and return it on every
|
||||
call. :py:class:`Singleton` uses :py:class:`Factory` for creation of
|
||||
instance, so, please follow :py:class:`Factory` documentation to go inside
|
||||
with injections syntax.
|
||||
|
||||
:py:class:`Singleton` is thread-safe and could be used in multithreading
|
||||
environment without any negative impact.
|
||||
|
||||
Retrieving of provided instance can be performed via calling
|
||||
:py:class:`Singleton` object:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
singleton = Singleton(SomeClass,
|
||||
some_arg1=1,
|
||||
some_arg2=2)
|
||||
some_object = singleton()
|
||||
|
||||
Singleton provider will create instance once and return it on every call.
|
||||
"""
|
||||
|
||||
__slots__ = ('instance', 'factory')
|
||||
|
||||
def __init__(self, provides, *args, **kwargs):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param provides: Class or other callable that provides object
|
||||
for creation.
|
||||
:type provides: type | callable
|
||||
|
||||
:param args: Tuple of injections.
|
||||
:type args: tuple
|
||||
|
||||
:param kwargs: Dictionary of injections.
|
||||
:type kwargs: dict
|
||||
"""
|
||||
self.instance = None
|
||||
"""Read-only reference to singleton's instance.
|
||||
|
||||
:type: object
|
||||
"""
|
||||
|
||||
self.factory = Factory(provides, *args, **kwargs)
|
||||
"""Singleton's factory object.
|
||||
|
||||
:type: :py:class:`Factory`
|
||||
"""
|
||||
|
||||
super(Singleton, self).__init__()
|
||||
|
||||
@property
|
||||
def provides(self):
|
||||
"""Class or other callable that provides object for creation.
|
||||
|
||||
:type: type | callable
|
||||
"""
|
||||
return self.factory.provides
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
"""Tuple of positional argument injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
|
||||
"""
|
||||
return self.factory.args
|
||||
|
||||
@property
|
||||
def kwargs(self):
|
||||
"""Tuple of keyword argument injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
|
||||
"""
|
||||
return self.factory.kwargs
|
||||
|
||||
@property
|
||||
def attributes(self):
|
||||
"""Tuple of attribute injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
|
||||
"""
|
||||
return self.factory.attributes
|
||||
|
||||
@property
|
||||
def methods(self):
|
||||
"""Tuple of method injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Method`]
|
||||
"""
|
||||
return self.factory.methods
|
||||
|
||||
@property
|
||||
def injections(self):
|
||||
"""Read-only tuple of all injections.
|
||||
|
||||
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
|
||||
"""
|
||||
return self.factory.injections
|
||||
|
||||
def reset(self):
|
||||
"""Reset cached instance, if any.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.instance = None
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
with GLOBAL_LOCK:
|
||||
if not self.instance:
|
||||
self.instance = self.factory(*args, **kwargs)
|
||||
return self.instance
|
||||
|
||||
def reset(self):
|
||||
"""Reset instance."""
|
||||
self.instance = None
|
||||
|
||||
@property
|
||||
def injections(self):
|
||||
"""Return tuple of all injections."""
|
||||
return self.factory.injections
|
||||
|
||||
|
||||
class ExternalDependency(Provider):
|
||||
"""External dependency provider.
|
||||
""":py:class:`ExternalDependency` provider describes dependency interface.
|
||||
|
||||
Those provider is used when dependency obviously have to be overridden by
|
||||
the client's code, but it's interface is known.
|
||||
This provider is used for description of dependency interface. That might
|
||||
be useful when dependency could be provided in the client's code only,
|
||||
but it's interface is known. Such situations could happen when required
|
||||
dependency has non-determenistic list of dependencies itself.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
database_provider = ExternalDependency(sqlite3.dbapi2.Connection)
|
||||
database_provider.override(Factory(sqlite3.connect, ':memory:'))
|
||||
|
||||
database = database_provider()
|
||||
"""
|
||||
|
||||
__slots__ = ('instance_of',)
|
||||
|
@ -183,10 +450,25 @@ class ExternalDependency(Provider):
|
|||
raise Error('ExternalDependency provider expects to get class, ' +
|
||||
'got {0} instead'.format(str(instance_of)))
|
||||
self.instance_of = instance_of
|
||||
"""Class of required dependency.
|
||||
|
||||
:type: type
|
||||
"""
|
||||
super(ExternalDependency, self).__init__()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
if not self.is_overridden:
|
||||
raise Error('Dependency is not defined')
|
||||
|
||||
|
@ -199,97 +481,207 @@ class ExternalDependency(Provider):
|
|||
return instance
|
||||
|
||||
def provided_by(self, provider):
|
||||
"""Set external dependency provider."""
|
||||
"""Set external dependency provider.
|
||||
|
||||
:param provider: Provider that provides required dependency.
|
||||
:type provider: :py:class:`Provider`
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
return self.override(provider)
|
||||
|
||||
|
||||
class StaticProvider(Provider):
|
||||
"""Static provider.
|
||||
""":py:class:`StaticProvider` returns provided instance "as is".
|
||||
|
||||
Static provider is base implementation that provides exactly the same as
|
||||
it got on input.
|
||||
:py:class:`StaticProvider` is base implementation that provides exactly
|
||||
the same as it got on input.
|
||||
"""
|
||||
|
||||
__slots__ = ('provides',)
|
||||
|
||||
def __init__(self, provides):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param provides: Value that have to be provided.
|
||||
:type provides: object
|
||||
"""
|
||||
self.provides = provides
|
||||
"""Value that have to be provided.
|
||||
|
||||
:type: object
|
||||
"""
|
||||
super(StaticProvider, self).__init__()
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
return self.provides
|
||||
|
||||
|
||||
class Class(StaticProvider):
|
||||
"""Class provider provides class."""
|
||||
""":py:class:`Class` returns provided class "as is".
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cls_provider = Class(object)
|
||||
object_cls = cls_provider()
|
||||
"""
|
||||
|
||||
|
||||
class Object(StaticProvider):
|
||||
"""Object provider provides object."""
|
||||
""":py:class:`Object` returns provided object "as is".
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
object_provider = Object(object())
|
||||
object_instance = object_provider()
|
||||
"""
|
||||
|
||||
|
||||
class Function(StaticProvider):
|
||||
"""Function provider provides function."""
|
||||
""":py:class:`Function` returns provided function "as is".
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
function_provider = Function(len)
|
||||
len_function = function_provider()
|
||||
"""
|
||||
|
||||
|
||||
class Value(StaticProvider):
|
||||
"""Value provider provides value."""
|
||||
""":py:class:`Value` returns provided value "as is".
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
value_provider = Value(31337)
|
||||
value = value_provider()
|
||||
"""
|
||||
|
||||
|
||||
class Callable(Provider):
|
||||
"""Callable provider.
|
||||
""":py:class:`Callable` provider calls wrapped callable on every call.
|
||||
|
||||
Callable provider provides callable that is called on every provider call
|
||||
with some predefined dependency injections.
|
||||
:py:class:`Callable` provider provides callable that is called on every
|
||||
provider call with some predefined dependency injections.
|
||||
|
||||
:py:class:`Callable` syntax of passing injections is the same like
|
||||
:py:class:`Factory` one:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
some_function = Callable(some_function, 'arg1', 'arg2', arg3=3, arg4=4)
|
||||
result = some_function()
|
||||
"""
|
||||
|
||||
__slots__ = ('callback', 'args', 'kwargs')
|
||||
|
||||
def __init__(self, callback, *args, **kwargs):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param callback: Wrapped callable.
|
||||
:type callback: callable
|
||||
|
||||
:param args: Tuple of injections.
|
||||
:type args: tuple
|
||||
|
||||
:param kwargs: Dictionary of injections.
|
||||
:type kwargs: dict
|
||||
"""
|
||||
if not callable(callback):
|
||||
raise Error('Callable expected, got {0}'.format(str(callback)))
|
||||
self.callback = callback
|
||||
self.args = _parse_args_injections(args)
|
||||
self.kwargs = _parse_kwargs_injections(args, kwargs)
|
||||
super(Callable, self).__init__()
|
||||
"""Wrapped callable.
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
return self.callback(*_get_injectable_args(args, self.args),
|
||||
**_get_injectable_kwargs(kwargs, self.kwargs))
|
||||
:type: callable
|
||||
"""
|
||||
|
||||
self.args = _parse_args_injections(args)
|
||||
"""Tuple of positional argument injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.Arg`]
|
||||
"""
|
||||
|
||||
self.kwargs = _parse_kwargs_injections(args, kwargs)
|
||||
"""Tuple of keyword argument injections.
|
||||
|
||||
:type: tuple[:py:class:`dependency_injector.injections.KwArg`]
|
||||
"""
|
||||
|
||||
super(Callable, self).__init__()
|
||||
|
||||
@property
|
||||
def injections(self):
|
||||
"""Return tuple of all injections."""
|
||||
"""Read-only tuple of all injections.
|
||||
|
||||
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
|
||||
"""
|
||||
return self.args + self.kwargs
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
return self.callback(*_get_injectable_args(args, self.args),
|
||||
**_get_injectable_kwargs(kwargs, self.kwargs))
|
||||
|
||||
|
||||
class Config(Provider):
|
||||
"""Config provider.
|
||||
""":py:class:`Config` provider provide dict values.
|
||||
|
||||
Config provider provides dict values. Also config provider creates
|
||||
child config objects for all undefined attribute calls. It makes possible
|
||||
to create deferred config value provider.
|
||||
:py:class:`Config` provider creates :py:class:`ChildConfig` objects for all
|
||||
undefined attribute calls. It makes possible to create deferred config
|
||||
value providers. It might be useful in cases where it is needed to
|
||||
define / pass some configuration in declarative manner, while
|
||||
configuration values will be loaded / updated in application's runtime.
|
||||
"""
|
||||
|
||||
__slots__ = ('value',)
|
||||
|
||||
def __init__(self, value=None):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param value: Configuration dictionary.
|
||||
:type value: dict[str, object]
|
||||
"""
|
||||
if not value:
|
||||
value = dict()
|
||||
self.value = value
|
||||
super(Config, self).__init__()
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Return instance of deferred config."""
|
||||
"""Return instance of deferred config.
|
||||
|
||||
:param item: Name of configuration option or section.
|
||||
:type item: str
|
||||
|
||||
:rtype: :py:class:`ChildConfig`
|
||||
"""
|
||||
return ChildConfig(parents=(item,), root_config=self)
|
||||
|
||||
def _provide(self, paths=None):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param paths: Tuple of pieces of configuration option / section path.
|
||||
:type args: tuple[str]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
value = self.value
|
||||
if paths:
|
||||
for path in paths:
|
||||
|
@ -301,30 +693,69 @@ class Config(Provider):
|
|||
return value
|
||||
|
||||
def update_from(self, value):
|
||||
"""Update current value from another one."""
|
||||
"""Update current value from another one.
|
||||
|
||||
:param value: Configuration dictionary.
|
||||
:type value: dict[str, object]
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.value.update(value)
|
||||
|
||||
|
||||
class ChildConfig(Provider):
|
||||
"""Child config provider.
|
||||
""":py:class:`ChildConfig` provider provides value from :py:class:`Config`.
|
||||
|
||||
Child config provide an value from the root config object according to
|
||||
the current path in the config tree.
|
||||
:py:class:`ChildConfig` provides value from the root config object
|
||||
according to the current path in the config tree.
|
||||
"""
|
||||
|
||||
__slots__ = ('parents', 'root_config')
|
||||
|
||||
def __init__(self, parents, root_config):
|
||||
"""Initializer."""
|
||||
"""Initializer.
|
||||
|
||||
:param parents: Tuple of pieces of configuration option / section
|
||||
parent path.
|
||||
:type parents: tuple[str]
|
||||
|
||||
:param root_config: Root configuration object.
|
||||
:type root_config: :py:class:`Config`
|
||||
"""
|
||||
self.parents = parents
|
||||
"""Tuple of pieces of configuration option / section parent path.
|
||||
|
||||
:type: tuple[str]
|
||||
"""
|
||||
|
||||
self.root_config = root_config
|
||||
"""Root configuration object.
|
||||
|
||||
:type: :py:class:`Config`
|
||||
"""
|
||||
|
||||
super(ChildConfig, self).__init__()
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Return instance of deferred config."""
|
||||
"""Return instance of deferred config.
|
||||
|
||||
:param item: Name of configuration option or section.
|
||||
:type item: str
|
||||
|
||||
:rtype: :py:class:`ChildConfig`
|
||||
"""
|
||||
return ChildConfig(parents=self.parents + (item,),
|
||||
root_config=self.root_config)
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: Tuple of context positional arguments.
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: Dictionary of context keyword arguments.
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
return self.root_config(self.parents)
|
||||
|
|
|
@ -8,10 +8,20 @@ from .errors import Error
|
|||
|
||||
|
||||
GLOBAL_LOCK = threading.RLock()
|
||||
"""Dependency injector global reentrant lock.
|
||||
|
||||
:type: :py:class:`threading.RLock`
|
||||
"""
|
||||
|
||||
|
||||
def is_provider(instance):
|
||||
"""Check if instance is provider instance."""
|
||||
"""Check if instance is provider instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_PROVIDER__') and
|
||||
getattr(instance, '__IS_PROVIDER__') is True)
|
||||
|
@ -20,7 +30,13 @@ def is_provider(instance):
|
|||
def ensure_is_provider(instance):
|
||||
"""Check if instance is provider instance and return it.
|
||||
|
||||
:raise: Error if provided instance is not provider.
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if provided instance is
|
||||
not provider.
|
||||
|
||||
:rtype: :py:class:`dependency_injector.providers.Provider`
|
||||
"""
|
||||
if not is_provider(instance):
|
||||
raise Error('Expected provider instance, '
|
||||
|
@ -29,14 +45,29 @@ def ensure_is_provider(instance):
|
|||
|
||||
|
||||
def is_injection(instance):
|
||||
"""Check if instance is injection instance."""
|
||||
"""Check if instance is injection instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_INJECTION__') and
|
||||
getattr(instance, '__IS_INJECTION__') is True)
|
||||
|
||||
|
||||
def ensure_is_injection(instance):
|
||||
"""Check if instance is injection instance, otherwise raise and error."""
|
||||
"""Check if instance is injection instance and return it.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if provided instance is
|
||||
not injection.
|
||||
|
||||
:rtype: :py:class:`dependency_injector.injections.Injection`
|
||||
"""
|
||||
if not is_injection(instance):
|
||||
raise Error('Expected injection instance, '
|
||||
'got {0}'.format(str(instance)))
|
||||
|
@ -44,51 +75,99 @@ def ensure_is_injection(instance):
|
|||
|
||||
|
||||
def is_arg_injection(instance):
|
||||
"""Check if instance is positional argument injection instance."""
|
||||
"""Check if instance is positional argument injection instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_ARG_INJECTION__') and
|
||||
getattr(instance, '__IS_ARG_INJECTION__', False) is True)
|
||||
|
||||
|
||||
def is_kwarg_injection(instance):
|
||||
"""Check if instance is keyword argument injection instance."""
|
||||
"""Check if instance is keyword argument injection instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_KWARG_INJECTION__') and
|
||||
getattr(instance, '__IS_KWARG_INJECTION__', False) is True)
|
||||
|
||||
|
||||
def is_attribute_injection(instance):
|
||||
"""Check if instance is attribute injection instance."""
|
||||
"""Check if instance is attribute injection instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_ATTRIBUTE_INJECTION__') and
|
||||
getattr(instance, '__IS_ATTRIBUTE_INJECTION__', False) is True)
|
||||
|
||||
|
||||
def is_method_injection(instance):
|
||||
"""Check if instance is method injection instance."""
|
||||
"""Check if instance is method injection instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_METHOD_INJECTION__') and
|
||||
getattr(instance, '__IS_METHOD_INJECTION__', False) is True)
|
||||
|
||||
|
||||
def is_catalog(instance):
|
||||
"""Check if instance is catalog instance."""
|
||||
"""Check if instance is catalog instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (hasattr(instance, '__IS_CATALOG__') and
|
||||
getattr(instance, '__IS_CATALOG__', False) is True)
|
||||
|
||||
|
||||
def is_dynamic_catalog(instance):
|
||||
"""Check if instance is dynamic catalog instance."""
|
||||
"""Check if instance is dynamic catalog instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and is_catalog(instance))
|
||||
|
||||
|
||||
def is_declarative_catalog(instance):
|
||||
"""Check if instance is declarative catalog instance."""
|
||||
"""Check if instance is declarative catalog instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (isinstance(instance, six.class_types) and is_catalog(instance))
|
||||
|
||||
|
||||
def is_catalog_bundle(instance):
|
||||
"""Check if instance is catalog bundle instance."""
|
||||
"""Check if instance is catalog bundle instance.
|
||||
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, six.class_types) and
|
||||
hasattr(instance, '__IS_CATALOG_BUNDLE__') and
|
||||
getattr(instance, '__IS_CATALOG_BUNDLE__', False) is True)
|
||||
|
@ -97,7 +176,13 @@ def is_catalog_bundle(instance):
|
|||
def ensure_is_catalog_bundle(instance):
|
||||
"""Check if instance is catalog bundle instance and return it.
|
||||
|
||||
:raise: Error if provided instance is not catalog bundle.
|
||||
:param instance: Instance to be checked.
|
||||
:type instance: object
|
||||
|
||||
:raise: :py:exc:`dependency_injector.errors.Error` if provided instance
|
||||
is not catalog bundle.
|
||||
|
||||
:rtype: :py:class:`dependency_injector.catalogs.CatalogBundle`
|
||||
"""
|
||||
if not is_catalog_bundle(instance):
|
||||
raise Error('Expected catalog bundle instance, '
|
||||
|
|
|
@ -7,28 +7,35 @@ Current section of documentation describes advanced usage of
|
|||
@inject decorator
|
||||
-----------------
|
||||
|
||||
``@di.inject()`` decorator can be used for making *inline* dependency
|
||||
.. module:: dependency_injector.injections
|
||||
|
||||
:py:func:`inject` decorator is a part of
|
||||
:py:mod:`dependency_injector.injections` module.
|
||||
|
||||
:py:func:`inject` decorator can be used for making *inline* dependency
|
||||
injections. It *patches* decorated callable in such way that dependency
|
||||
injection will be done during every call of decorated callable.
|
||||
|
||||
``di.inject()`` takes a various number of positional and keyword arguments
|
||||
:py:func:`inject` takes a various number of positional and keyword arguments
|
||||
that are used as decorated callable injections. Every time, when
|
||||
``di.inject()`` is called, positional and keyword argument injections would be
|
||||
passed as an callable arguments.
|
||||
:py:func:`inject` is called, positional and keyword argument injections would
|
||||
be passed as an callable arguments.
|
||||
|
||||
Such behaviour is very similar to the standard Python ``functools.partial``
|
||||
object, except of one thing: all injectable values are provided
|
||||
*"as is"*, except of providers (subclasses of ``di.Provider``). Providers
|
||||
*"as is"*, except of providers (subclasses of
|
||||
:py:class:`dependency_injector.providers.Provider`). Providers
|
||||
will be called every time, when injection needs to be done. For example,
|
||||
if injectable value of injection is a ``di.Factory``, it will provide new one
|
||||
if injectable value of injection is a
|
||||
:py:class:`dependency_injector.providers.Factory`, it will provide new one
|
||||
instance (as a result of its call) every time, when injection needs to be done.
|
||||
|
||||
``di.inject()`` behaviour with context positional and keyword arguments is
|
||||
:py:func:`inject` behaviour with context positional and keyword arguments is
|
||||
very like a standard Python ``functools.partial``:
|
||||
|
||||
- Positional context arguments will be appended after ``di.inject()``
|
||||
- Positional context arguments will be appended after :py:func:`inject`
|
||||
positional injections.
|
||||
- Keyword context arguments have priority on ``di.inject()`` keyword
|
||||
- Keyword context arguments have priority on :py:func:`inject` keyword
|
||||
injections and will be merged over them.
|
||||
|
||||
Example:
|
||||
|
@ -36,7 +43,7 @@ Example:
|
|||
.. literalinclude:: ../../examples/advanced_usage/inject_simple.py
|
||||
:language: python
|
||||
|
||||
Example of usage ``@di.inject()`` decorator with Flask:
|
||||
Example of usage :py:func:`inject` decorator with Flask:
|
||||
|
||||
.. literalinclude:: ../../examples/advanced_usage/inject_flask.py
|
||||
:language: python
|
||||
|
@ -45,11 +52,12 @@ Example of usage ``@di.inject()`` decorator with Flask:
|
|||
@inject decorator with classes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``@di.inject()`` could be applied for classes. In such case, it will look for
|
||||
:py:func:`inject` could be applied for classes. In such case, it will look for
|
||||
class ``__init__()`` method and pass injection to it. If decorated class has
|
||||
no ``__init__()`` method, appropriate ``di.Error`` will be raised.
|
||||
no ``__init__()`` method, appropriate
|
||||
:py:exc:`dependency_injector.errors.Error` will be raised.
|
||||
|
||||
Example of usage ``@di.inject()`` with Flask class-based view:
|
||||
Example of usage :py:func:`inject` with Flask class-based view:
|
||||
|
||||
.. literalinclude:: ../../examples/advanced_usage/inject_flask_class_based.py
|
||||
:language: python
|
||||
|
|
7
docs/api/catalogs.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
``dependency_injector.catalogs``
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: dependency_injector.catalogs
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:special-members:
|
6
docs/api/errors.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
``dependency_injector.errors``
|
||||
------------------------------
|
||||
|
||||
.. automodule:: dependency_injector.errors
|
||||
:members:
|
||||
:member-order: bysource
|
12
docs/api/index.rst
Normal file
|
@ -0,0 +1,12 @@
|
|||
API Documentation
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
top_level
|
||||
providers
|
||||
injections
|
||||
catalogs
|
||||
utils
|
||||
errors
|
7
docs/api/injections.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
``dependency_injector.injections``
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: dependency_injector.injections
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:inherited-members:
|
7
docs/api/providers.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
``dependency_injector.providers``
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: dependency_injector.providers
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:inherited-members:
|
5
docs/api/top_level.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
``dependency_injector``
|
||||
-----------------------
|
||||
|
||||
.. automodule:: dependency_injector
|
||||
:members: VERSION
|
6
docs/api/utils.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
``dependency_injector.utils``
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: dependency_injector.utils
|
||||
:members:
|
||||
:member-order: bysource
|
|
@ -1,23 +1,43 @@
|
|||
Creating catalog provider bundles
|
||||
---------------------------------
|
||||
Catalog provider bundles
|
||||
------------------------
|
||||
|
||||
``di.DeclarativeCatalog.Bundle`` is a limited collection of catalog providers.
|
||||
While catalog could be used as a centralized place for particular providers
|
||||
group, such bundles of catalog providers can be used for creating several
|
||||
limited scopes that could be passed to different subsystems.
|
||||
.. module:: dependency_injector.catalogs
|
||||
|
||||
``di.DeclarativeCatalog.Bundle`` has exactly the same API as
|
||||
``di.DeclarativeCatalog`` except of the limitations on getting providers.
|
||||
:py:class:`CatalogBundle` is a frozen, limited collection of catalog
|
||||
providers. While catalog could be used as a centralized place for
|
||||
particular providers group, such bundles of catalog providers can be used
|
||||
for creating several frozen, limited scopes that could be passed to different
|
||||
subsystems.
|
||||
|
||||
Each ``di.DeclarativeCatalog`` has a reference to its bundle class -
|
||||
``di.DeclarativeCatalog.Bundle``. For example, if some concrete catalog has name
|
||||
``SomeCatalog``, then its bundle class could be reached as
|
||||
``SomeCatalog.Bundle``.
|
||||
:py:class:`CatalogBundle` has API's parity with catalogs
|
||||
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) in terms of
|
||||
retrieving the providers, but it is "frozen" in terms of modification
|
||||
provider's list.
|
||||
|
||||
``di.DeclarativeCatalog.Bundle`` expects to get the list of its catalog providers
|
||||
:py:class:`CatalogBundle` is considered to be dependable on catalogs
|
||||
(:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`) entity by
|
||||
its design.
|
||||
|
||||
Each catalog (:py:class:`DeclarativeCatalog` or :py:class:`DynamicCatalog`)
|
||||
has a reference to its bundle class - :py:attr:`DeclarativeCatalog.Bundle`
|
||||
(or :py:attr:`DynamicCatalog.Bundle` consequently). For example, subclass of
|
||||
:py:class:`CatalogBundle` for some concrete declarative catalog
|
||||
``SomeCatalog`` could be reached as ``SomeCatalog.Bundle``.
|
||||
|
||||
:py:class:`CatalogBundle` expects to get the list of its catalog providers
|
||||
as positional arguments and will limit the scope of created bundle to this
|
||||
list.
|
||||
|
||||
.. note::
|
||||
|
||||
Some notes about :py:class:`CatalogBundle` design.
|
||||
|
||||
Design and syntax of :py:class:`CatalogBundle` was developed with the idea
|
||||
of keeping full functionalities of type-hinting and introspection of
|
||||
modern IDE's. This design came from some practical experience of using
|
||||
:py:class:`CatalogBundle` and considered to be the most comfortable for
|
||||
developer.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/catalogs/bundles.png
|
||||
|
|
61
docs/catalogs/declarative.rst
Normal file
|
@ -0,0 +1,61 @@
|
|||
Declarative catalogs
|
||||
--------------------
|
||||
|
||||
.. module:: dependency_injector.catalogs
|
||||
|
||||
:py:class:`DeclarativeCatalog` is a catalog 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 catalog is deterministic (catalog
|
||||
will not change its structure in runtime).
|
||||
|
||||
Declarative catalogs have to extend base declarative catalog class -
|
||||
:py:class:`dependency_injector.catalogs.DeclarativeCatalog`.
|
||||
|
||||
Declarative catalog's providers have to be defined like catalog's class
|
||||
attributes. Every provider in catalog has name. This name should follow
|
||||
``some_provider`` convention, that is standard naming convention for
|
||||
attribute names in Python.
|
||||
|
||||
.. note::
|
||||
|
||||
Declarative catalogs have several features that could be useful
|
||||
for some kind of operations on catalog's providers, please visit API
|
||||
documentation for getting full list of features -
|
||||
:py:class:`dependency_injector.catalogs.DeclarativeCatalog`.
|
||||
|
||||
.. note::
|
||||
|
||||
It might be useful to add such
|
||||
``""":type: dependency_injector.providers.Provider -> Object1"""``
|
||||
docstrings just on the next line after provider's definition. It will
|
||||
help code analyzing tools and IDE's to understand that variable above
|
||||
contains some callable object, that returns particular instance as a
|
||||
result of its call.
|
||||
|
||||
Here is an simple example of defining declarative catalog with several
|
||||
factories:
|
||||
|
||||
.. image:: /images/catalogs/declarative.png
|
||||
:width: 85%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/declarative.py
|
||||
:language: python
|
||||
|
||||
Example of declarative catalogs inheritance:
|
||||
|
||||
.. image:: /images/catalogs/declarative_inheritance.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/declarative_inheritance.py
|
||||
:language: python
|
||||
|
||||
Example of declarative catalog's provider injections:
|
||||
|
||||
.. image:: /images/catalogs/declarative_injections.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/declarative_injections.py
|
||||
:language: python
|
29
docs/catalogs/dynamic.rst
Normal file
|
@ -0,0 +1,29 @@
|
|||
Dynamic catalogs
|
||||
----------------
|
||||
|
||||
.. module:: dependency_injector.catalogs
|
||||
|
||||
: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:`DeclarativeCatalog` and :py:class:`DynamicCatalog` have
|
||||
100% API parity.
|
||||
|
||||
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 catalog with several factories:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/dynamic.py
|
||||
:language: python
|
||||
|
||||
Next one example demonstrates creation and runtime filling of dynamic catalog:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/dynamic_runtime_creation.py
|
||||
:language: python
|
|
@ -16,10 +16,12 @@ Also, for both of these and some other cases, it might be useful to attach
|
|||
some init / shutdown functionality or something else, that deals with group
|
||||
of providers.
|
||||
|
||||
Catalogs module API docs - :py:mod:`dependency_injector.catalogs`.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
writing
|
||||
operating
|
||||
declarative
|
||||
dynamic
|
||||
bundles
|
||||
overriding
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
Operating with catalogs
|
||||
-----------------------
|
||||
|
||||
``di.DeclarativeCatalog`` has several features that could be useful for some
|
||||
kind of operations on catalog's providers:
|
||||
|
||||
- ``di.DeclarativeCatalog.providers`` is read-only attribute that contains
|
||||
``dict`` of all catalog providers, including providers that are inherited
|
||||
from parent catalogs, where key is the name of provider and value is
|
||||
provider itself.
|
||||
- ``di.DeclarativeCatalog.cls_providers`` is read-only attribute contains
|
||||
``dict`` of current catalog providers, where key is the name of provider
|
||||
and value is provider itself.
|
||||
- ``di.DeclarativeCatalog.inherited_providers`` is read-only attribute
|
||||
contains ``dict`` of all providers that are inherited from parent catalogs,
|
||||
where key is the name of provider and value is provider itself.
|
||||
- ``di.DeclarativeCatalog.filter(provider_type=di.Provider)`` is a class
|
||||
method that could be used for filtering catalog providers by provider types
|
||||
(for example, for getting all ``di.Factory`` providers).
|
||||
``di.DeclarativeCatalog.filter()`` method use
|
||||
``di.DeclarativeCatalog.providers``.
|
||||
|
||||
Example:
|
||||
|
||||
.. image:: /images/catalogs/operating_with_providers.png
|
||||
:width: 100%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/operating_with_providers.py
|
||||
:language: python
|
|
@ -1,35 +1,49 @@
|
|||
Overriding of catalogs
|
||||
----------------------
|
||||
|
||||
.. module:: dependency_injector.catalogs
|
||||
|
||||
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.
|
||||
|
||||
There are two ways to override catalog by another catalog:
|
||||
There are two ways to override :py:class:`DeclarativeCatalog` with another
|
||||
catalog:
|
||||
|
||||
- Use ``di.DeclarativeCatalog.override(AnotherCatalog)`` method.
|
||||
- Use ``@di.override(AnotherCatalog)`` class decorator.
|
||||
- Use :py:meth:`DeclarativeCatalog.override` method.
|
||||
- Use :py:func:`override` class decorator.
|
||||
|
||||
Example of overriding catalog using ``di.DeclarativeCatalog.override()``
|
||||
Example of overriding catalog using :py:meth:`DeclarativeCatalog.override`
|
||||
method:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override.py
|
||||
.. literalinclude:: ../../examples/catalogs/override_declarative.py
|
||||
:language: python
|
||||
|
||||
Example of overriding catalog using ``@di.override()`` decorator:
|
||||
Example of overriding catalog using :py:func:`override` decorator:
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/override_decorator.py
|
||||
.. literalinclude:: ../../examples/catalogs/override_declarative_decorator.py
|
||||
:language: python
|
||||
|
||||
Also there are several useful methods and properties that help to work with
|
||||
catalog overridings:
|
||||
Also there are several useful :py:class:`DeclarativeCatalog` methods and
|
||||
properties that help to work with catalog overridings:
|
||||
|
||||
- ``di.DeclarativeCatalog.is_overridden`` - read-only, evaluated in runtime,
|
||||
property that is set to True if catalog is overridden.
|
||||
- ``di.DeclarativeCatalog.last_overriding`` - reference to the last overriding
|
||||
catalog, if any.
|
||||
- ``di.DeclarativeCatalog.overridden_by`` - tuple of all overriding catalogs.
|
||||
- ``di.DeclarativeCatalog.reset_last_overriding()`` - reset last overriding
|
||||
catalog.
|
||||
- ``di.DeclarativeCatalog.reset_override()`` - reset all overridings for all
|
||||
catalog providers.
|
||||
- :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: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
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
Writing catalogs
|
||||
----------------
|
||||
|
||||
Catalogs have to extend base catalog class ``di.DeclarativeCatalog``.
|
||||
|
||||
Providers have to be defined like catalog's attributes. Every provider in
|
||||
catalog has name. This name should follow ``some_provider`` convention,
|
||||
that is standard naming convention for attribute names in Python.
|
||||
|
||||
.. note::
|
||||
|
||||
It might be useful to add such ``""":type: di.Provider -> Object1"""``
|
||||
docstrings just on the next line after provider's definition. It will
|
||||
help code analyzing tools and IDE's to understand that variable above
|
||||
contains some callable object, that returns particular instance as a
|
||||
result of its call.
|
||||
|
||||
Here is an simple example of catalog with several factories:
|
||||
|
||||
.. image:: /images/catalogs/writing_catalogs.png
|
||||
:width: 85%
|
||||
:align: center
|
||||
|
||||
.. literalinclude:: ../../examples/catalogs/writing_catalogs.py
|
||||
:language: python
|
|
@ -28,7 +28,7 @@ import re
|
|||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
extensions = ['sphinx.ext.autodoc']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 295 KiB |
BIN
docs/images/catalogs/declarative.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
docs/images/catalogs/declarative_inheritance.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
docs/images/catalogs/declarative_injections.png
Normal file
After Width: | Height: | Size: 231 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 19 KiB |
BIN
docs/images/providers/factory_attribute_injection.png
Normal file
After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 26 KiB |
|
@ -55,5 +55,6 @@ Contents
|
|||
providers/index
|
||||
catalogs/index
|
||||
advanced_usage/index
|
||||
api/index
|
||||
main/feedback
|
||||
main/changelog
|
||||
|
|
|
@ -9,13 +9,31 @@ follows `Semantic versioning`_
|
|||
|
||||
Development version
|
||||
-------------------
|
||||
- Rename ``di.AbstractCatalog`` to ``di.DeclarativeCatalog``
|
||||
- No features.
|
||||
|
||||
0.11.0
|
||||
------
|
||||
- Rename ``AbstractCatalog`` to ``DeclarativeCatalog``
|
||||
(with backward compatibility).
|
||||
- Rename ``catalog`` module to ``catalogs`` with backward compatibility.
|
||||
- Implement dynamic binding of providers for ``DeclarativeCatalog``.
|
||||
- Add ``DynamicCatalog``.
|
||||
- Change restrictions for providers-to-catalogs bindings - provider could be
|
||||
bound to several catalogs with different names.
|
||||
- Restrict overriding of providers by themselves.
|
||||
- Restrict overriding of catalogs by themselves.
|
||||
- Make ``DeclarativeCatalog.last_overriding`` attribute to be ``None`` by
|
||||
default.
|
||||
- Make ``Provider.last_overriding`` attribute to be ``None`` by
|
||||
default.
|
||||
- Refactor catalogs and providers modules.
|
||||
- Add API documentation
|
||||
- Improve user's guides and examples.
|
||||
|
||||
0.10.5
|
||||
------
|
||||
- Add more representable implementation for ``di.AbstractCatalog`` and
|
||||
``di.AbstractCatalog.Bundle``.
|
||||
- Add more representable implementation for ``AbstractCatalog`` and
|
||||
``AbstractCatalog.Bundle``.
|
||||
|
||||
0.10.4
|
||||
------
|
||||
|
@ -35,22 +53,22 @@ Development version
|
|||
|
||||
0.10.0
|
||||
------
|
||||
- Add functionality for creating ``di.AbstractCatalog`` provider bundles.
|
||||
- Improve ``di.AbstractCatalog`` inheritance.
|
||||
- Improve ``di.AbstractCatalog`` overriding.
|
||||
- Add functionality for creating ``AbstractCatalog`` provider bundles.
|
||||
- Improve ``AbstractCatalog`` inheritance.
|
||||
- Improve ``AbstractCatalog`` overriding.
|
||||
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
|
||||
examples.
|
||||
- Add functionality for using positional argument injections with
|
||||
``di.Factory``, ``di.Singleton``, ``di.Callable`` providers and
|
||||
``di.inject`` decorator.
|
||||
- Add functionality for decorating classes with ``@di.inject``.
|
||||
- Add ``di.Singleton.injections`` attribute that represents a tuple of all
|
||||
``di.Singleton`` injections (including args, kwargs, attributes and methods).
|
||||
- Add ``di.Callable.injections`` attribute that represents a tuple of all
|
||||
``di.Callable`` injections (including args and kwargs).
|
||||
- Add optimization for ``di.Injection.value`` property that will compute
|
||||
``Factory``, ``Singleton``, ``Callable`` providers and
|
||||
``inject`` decorator.
|
||||
- Add functionality for decorating classes with ``@inject``.
|
||||
- Add ``Singleton.injections`` attribute that represents a tuple of all
|
||||
``Singleton`` injections (including args, kwargs, attributes and methods).
|
||||
- Add ``Callable.injections`` attribute that represents a tuple of all
|
||||
``Callable`` injections (including args and kwargs).
|
||||
- Add optimization for ``Injection.value`` property that will compute
|
||||
type of injection once, instead of doing this on every call.
|
||||
- Add ``di.VERSION`` constant for verification of currently installed version.
|
||||
- Add ``VERSION`` constant for verification of currently installed version.
|
||||
- Add support of Python 3.5.
|
||||
- Add support of six 1.10.0.
|
||||
- Add minor refactorings and code style fixes.
|
||||
|
@ -58,8 +76,8 @@ Development version
|
|||
0.9.5
|
||||
-----
|
||||
- Change provider attributes scope to public.
|
||||
- Add ``di.Factory.injections`` attribute that represents a tuple of all
|
||||
``di.Factory`` injections (including kwargs, attributes and methods).
|
||||
- Add ``Factory.injections`` attribute that represents a tuple of all
|
||||
``Factory`` injections (including kwargs, attributes and methods).
|
||||
|
||||
0.9.4
|
||||
-----
|
||||
|
|
|
@ -12,7 +12,7 @@ framework can be installed from PyPi_:
|
|||
pip install dependency_injector
|
||||
|
||||
# Installing particular version:
|
||||
pip install dependency_injector==0.9.0
|
||||
pip install dependency_injector==0.11.0
|
||||
|
||||
Sources can be cloned from GitHub_:
|
||||
|
||||
|
@ -23,14 +23,14 @@ Sources can be cloned from GitHub_:
|
|||
Also all *Dependency Injector* releases can be downloaded from
|
||||
`GitHub releases page`_.
|
||||
|
||||
Verification of currently installed version could be done using ``di.VERSION``
|
||||
constant:
|
||||
Verification of currently installed version could be done using
|
||||
:py:obj:`dependency_injector.VERSION` constant:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
>>> import dependency_injector as di
|
||||
>>> di.VERSION
|
||||
'0.10.0'
|
||||
>>> from dependency_injector import VERSION
|
||||
>>> VERSION
|
||||
'0.11.0'
|
||||
|
||||
.. _PyPi: https://pypi.python.org/pypi/dependency_injector
|
||||
.. _GitHub: https://github.com/rmk135/dependency_injector
|
||||
|
|
|
@ -57,27 +57,6 @@ framework:
|
|||
|
||||
Main idea of *Dependency Injector* is to keep dependencies under control.
|
||||
|
||||
Shortcuts
|
||||
---------
|
||||
|
||||
*Dependency Injector* recommends to use such kind of import shortcut:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import dependency_injector as di
|
||||
|
||||
- All *Dependency Injector* entities could be used just from top-level package
|
||||
(like ``di.Factory``, ``di.inject``, ``di.AbstractCatalog`` and so on).
|
||||
- Another one way is to use second level packages (like
|
||||
``di.providers.Factory``, ``di.injections.inject``,
|
||||
``di.catalog.AbstractCatalog`` and so on). It might be useful for improving
|
||||
of readability in some cases.
|
||||
|
||||
.. note::
|
||||
|
||||
``import dependency_injector as di`` shortcut is used among current
|
||||
documentation, images and examples.
|
||||
|
||||
Main entities
|
||||
-------------
|
||||
|
||||
|
@ -91,18 +70,21 @@ interaction with each other.
|
|||
There are 3 main entities:
|
||||
|
||||
- Providers. Providers are strategies of accesing objects. For example,
|
||||
``di.providers.Factory`` creates new instance of provided
|
||||
class every time it is called. ``di.providers.Singleton`` creates
|
||||
provided instance once and returns it on every next call. Providers
|
||||
could be overridden by another providers. Base class is -
|
||||
``di.providers.Provider``.
|
||||
:py:class:`dependency_injector.providers.Factory` creates new instance of
|
||||
provided class every time it is called.
|
||||
:py:class:`dependency_injector.providers.Singleton` creates provided
|
||||
instance once and returns it on every next call. Providers could be
|
||||
overridden by another providers. Base class is -
|
||||
:py:class:`dependency_injector.providers.Provider`.
|
||||
- Injections. Injections are instructions for making dependency injections
|
||||
(there are several ways how they could be done). Injections are used mostly
|
||||
by ``di.providers.Factory`` and ``di.providers.Singleton`` providers, but
|
||||
these are not only cases. Base class is - ``di.injections.Injection``.
|
||||
by :py:class:`dependency_injector.providers.Factory` and
|
||||
:py:class:`dependency_injector.providers.Singleton` providers, but
|
||||
these are not only cases. Base class is -
|
||||
:py:class:`dependency_injector.injections.Injection`.
|
||||
- Catalogs. Catalogs are collections of providers. They are used for grouping
|
||||
of providers by some principles. Base class is -
|
||||
``di.catalog.AbstractCatalog``.
|
||||
:py:class:`dependency_injector.catalogs.DeclarativeCatalog`.
|
||||
|
||||
|
||||
.. _SLOC: http://en.wikipedia.org/wiki/Source_lines_of_code
|
||||
|
|
|
@ -1,40 +1,43 @@
|
|||
Callable providers
|
||||
------------------
|
||||
|
||||
``di.Callable`` provider is a provider that wraps particular callable with
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
:py:class:`Callable` provider is a provider that wraps particular callable with
|
||||
some injections. Every call of this provider returns result of call of initial
|
||||
callable.
|
||||
|
||||
Callable providers and injections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``di.Callable`` takes a various number of positional and keyword arguments
|
||||
that are used as decorated callable injections. Every time, when
|
||||
``di.Callable`` is called, positional and keyword argument injections would be
|
||||
passed as an callable arguments.
|
||||
:py:class:`Callable` takes a various number of positional and keyword
|
||||
arguments that are used as decorated callable injections. Every time, when
|
||||
:py:class:`Callable` is called, positional and keyword argument injections
|
||||
would be passed as an callable arguments.
|
||||
|
||||
Such behaviour is very similar to the standard Python ``functools.partial``
|
||||
object, except of one thing: all injectable values are provided
|
||||
*"as is"*, except of providers (subclasses of ``di.Provider``). Providers
|
||||
*"as is"*, except of providers (subclasses of :py:class:`Provider`). Providers
|
||||
will be called every time, when injection needs to be done. For example,
|
||||
if injectable value of injection is a ``di.Factory``, it will provide new one
|
||||
instance (as a result of its call) every time, when injection needs to be done.
|
||||
if injectable value of injection is a :py:class:`Factory`, it will provide
|
||||
new one instance (as a result of its call) every time, when injection needs
|
||||
to be done.
|
||||
|
||||
``di.Callable`` behaviour with context positional and keyword arguments is
|
||||
very like a standard Python ``functools.partial``:
|
||||
:py:class:`Callable` behaviour with context positional and keyword arguments
|
||||
is very like a standard Python ``functools.partial``:
|
||||
|
||||
- Positional context arguments will be appended after ``di.Callable``
|
||||
- Positional context arguments will be appended after :py:class:`Callable`
|
||||
positional injections.
|
||||
- Keyword context arguments have priority on ``di.Callable`` keyword
|
||||
- Keyword context arguments have priority on :py:class:`Callable` keyword
|
||||
injections and will be merged over them.
|
||||
|
||||
Example that shows usage of ``di.Callable`` with positional argument
|
||||
Example that shows usage of :py:class:`Callable` with positional argument
|
||||
injections:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/callable_args.py
|
||||
:language: python
|
||||
|
||||
Next one example shows usage of ``di.Callable`` with keyword argument
|
||||
Next one example shows usage of :py:class:`Callable` with keyword argument
|
||||
injections:
|
||||
|
||||
.. image:: /images/providers/callable.png
|
||||
|
@ -47,13 +50,13 @@ injections:
|
|||
Callable providers delegation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``di.Callable`` provider could be delegated to any other provider via any kind
|
||||
of injection. Delegation of ``di.Callable`` providers is the same as
|
||||
``di.Factory`` and ``di.Singleton`` providers delegation, please follow
|
||||
*Factory providers delegation* section for example.
|
||||
:py:class:`Callable` provider could be delegated to any other provider via any
|
||||
kind of injection. Delegation of :py:class:`Callable` providers is the same as
|
||||
:py:class:`Factory` and :py:class:`Singleton` providers delegation, please
|
||||
follow *Factory providers delegation* section for example.
|
||||
|
||||
``di.Callable`` delegate could be created obviously using
|
||||
``di.Delegate(di.Callable())`` or by calling ``di.Callable.delegate()`` method.
|
||||
:py:class:`Callable` delegate could be created obviously using
|
||||
``Delegate(Callable(...))`` or by calling ``Callable(...).delegate()`` method.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
Writing custom providers
|
||||
Writing of custom providers
|
||||
------------------------
|
||||
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
List of *Dependency Injector* providers could be widened with custom providers.
|
||||
|
||||
Below are some tips and recommendations that have to be met:
|
||||
|
||||
1. Every custom provider has to extend base provider class -
|
||||
``di.Provider``.
|
||||
2. Cusom provider's ``__init__()`` could be overriden with only condition:
|
||||
parent initializer (``di.Provider.__init__()``) has to be called.
|
||||
:py:class:`Provider`.
|
||||
2. Cusom provider's ``__init__()`` could be overriden, but parent's
|
||||
initializer (:py:meth:`Provider.__init__`) has to be called.
|
||||
3. Providing strategy has to be implemented in custom provider's
|
||||
``_provide()`` method. All ``*args`` & ``**kwargs`` that will be
|
||||
recieved by ``di.Provider.__call__()`` will be transefed to custom
|
||||
provider's ``_provide()``.
|
||||
:py:meth:`Provider._provide` method. All ``*args`` & ``**kwargs``
|
||||
that will be recieved by :py:meth:`Provider.__call__` will be
|
||||
transefed to custom provider's :py:meth:`Provider._provide`.
|
||||
4. If custom provider is based on some standard providers, it is better to
|
||||
use delegation of standard providers, then extending of them.
|
||||
5. If custom provider defines any attributes, it is good to list them in
|
||||
``__slots__`` attribute (as *Dependency Injector* does). It can save
|
||||
some memory.
|
||||
6. If custom provider deals with injections (e.g. ``di.Factory``,
|
||||
``di.Singleton`` providers), it is strongly recommended to be
|
||||
consistent with ``di.Factory``, ``di.Singleton`` and ``di.Callable``
|
||||
providers style.
|
||||
6. If custom provider deals with injections, it is strongly recommended
|
||||
to be consistent with :py:class:`Factory`, :py:class:`Singleton` and
|
||||
:py:class:`Callable` providers style.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
External dependency providers
|
||||
-----------------------------
|
||||
|
||||
``di.ExternalDependency`` provider can be useful for development of
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
:py:class:`ExternalDependency` provider can be useful for development of
|
||||
self-sufficient libraries / modules / applications that has required external
|
||||
dependencies.
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
Factory providers
|
||||
-----------------
|
||||
|
||||
``di.Factory`` provider creates new instance of specified class on every call.
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
:py:class:`Factory` provider creates new instance of specified class on every
|
||||
call.
|
||||
|
||||
Nothing could be better than brief example:
|
||||
|
||||
|
@ -15,21 +18,22 @@ Nothing could be better than brief example:
|
|||
Factory providers and __init__ injections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``di.Factory`` takes a various number of positional and keyword arguments that
|
||||
are used as ``__init__()`` injections. Every time, when ``di.Factory``
|
||||
creates new one instance, positional and keyword argument injections would be
|
||||
passed as an instance's arguments.
|
||||
:py:class:`Factory` takes a various number of positional and keyword arguments
|
||||
that are used as ``__init__()`` injections. Every time, when
|
||||
:py:class:`Factory` creates new one instance, positional and keyword
|
||||
argument injections would be passed as an instance's arguments.
|
||||
|
||||
Such behaviour is very similar to the standard Python ``functools.partial``
|
||||
object, except of one thing: all injectable values are provided
|
||||
*"as is"*, except of providers (subclasses of ``di.Provider``). Providers
|
||||
*"as is"*, except of providers (subclasses of :py:class:`Provider`). Providers
|
||||
will be called every time, when injection needs to be done. For example,
|
||||
if injectable value of injection is a ``di.Factory``, it will provide new one
|
||||
instance (as a result of its call) every time, when injection needs to be done.
|
||||
if injectable value of injection is a :py:class:`Factory`, it will provide
|
||||
new one instance (as a result of its call) every time, when injection needs
|
||||
to be done.
|
||||
|
||||
Example below is a little bit more complicated. It shows how to create
|
||||
``di.Factory`` of particular class with ``__init__()`` argument injections
|
||||
which injectable values are also provided by another factories:
|
||||
:py:class:`Factory` of particular class with ``__init__()`` argument
|
||||
injections which injectable values are also provided by another factories:
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -58,14 +62,14 @@ Example of usage keyword argument injections:
|
|||
Factory providers and __init__ injections priority
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Next example shows how ``di.Factory`` provider deals with positional and
|
||||
keyword ``__init__()`` context arguments. In few words, ``di.Factory``
|
||||
Next example shows how :py:class:`Factory` provider deals with positional and
|
||||
keyword ``__init__()`` context arguments. In few words, :py:class:`Factory`
|
||||
behaviour here is very like a standard Python ``functools.partial``:
|
||||
|
||||
- Positional context arguments will be appended after ``di.Factory``
|
||||
- Positional context arguments will be appended after :py:class:`Factory`
|
||||
positional injections.
|
||||
- Keyword context arguments have priority on ``di.Factory`` keyword injections
|
||||
and will be merged over them.
|
||||
- Keyword context arguments have priority on :py:class:`Factory` keyword
|
||||
injections and will be merged over them.
|
||||
|
||||
So, please, follow the example below:
|
||||
|
||||
|
@ -82,34 +86,38 @@ Objects can take dependencies in different forms (some objects take init
|
|||
arguments, other use attributes setting or method calls). It affects how
|
||||
such objects are created and initialized.
|
||||
|
||||
``di.Factory`` provider takes various number of positional and keyword
|
||||
:py:class:`Factory` provider takes various number of positional and keyword
|
||||
arguments, that define what kinds of dependency injections have to be used.
|
||||
|
||||
All of those instructions are defined in ``di.injections`` module and are
|
||||
subclasses of ``di.injections.Injection`` (shortcut ``di.Injection``). There
|
||||
are several types of injections that are used by ``di.Factory`` provider:
|
||||
All of those instructions are defined in
|
||||
:py:mod:`dependency_injector.injections` module and are subclasses of
|
||||
:py:class:`dependency_injector.injections.Injection`. There are several types
|
||||
of injections that are used by :py:class:`Factory` provider:
|
||||
|
||||
+ ``di.Arg`` - injection is done by passing injectable value in object's
|
||||
``__init__()`` method in time of object's creation as positional argument.
|
||||
Takes injectable value only.
|
||||
+ ``di.KwArg`` - injection is done by passing injectable value in object's
|
||||
``__init__()`` method in time of object's creation as keyword argument.
|
||||
Takes keyword name of ``__init__()`` argument and injectable value.
|
||||
+ ``di.Attribute`` - injection is done by setting specified attribute with
|
||||
injectable value right after object's creation. Takes attribute's name
|
||||
and injectable value.
|
||||
+ ``di.Method`` - injection is done by calling of specified method with
|
||||
injectable value right after object's creation and attribute injections
|
||||
are done. Takes method name and injectable value.
|
||||
+ :py:class:`dependency_injector.injections.Arg` - injection is done by
|
||||
passing injectable value in object's ``__init__()`` method in time of
|
||||
object's creation as positional argument. Takes injectable value only.
|
||||
+ :py:class:`dependency_injector.injections.KwArg` - injection is done by
|
||||
passing injectable value in object's ``__init__()`` method in time of
|
||||
object's creation as keyword argument. Takes keyword name of
|
||||
``__init__()`` argument and injectable value.
|
||||
+ :py:class:`dependency_injector.injections.Attribute` - injection is done
|
||||
by setting specified attribute with injectable value right after
|
||||
object's creation. Takes attribute's name and injectable value.
|
||||
+ :py:class:`dependency_injector.injections.Method` - injection is done by
|
||||
calling of specified method with injectable value right after object's
|
||||
creation and attribute injections are done. Takes method name and
|
||||
injectable value.
|
||||
|
||||
All ``di.Injection``'s injectable values are provided *"as is"*, except of
|
||||
providers (subclasses of ``di.Provider``). Providers will be called every time,
|
||||
when injection needs to be done.
|
||||
All :py:class:`dependency_injector.injections.Injection`'s injectable values
|
||||
are provided *"as is"*, except of providers (subclasses of
|
||||
:py:class:`Provider`). Providers will be called every time, when injection
|
||||
needs to be done.
|
||||
|
||||
Factory providers and attribute injections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Example below shows how to create ``di.Factory`` of particular class with
|
||||
Example below shows how to create :py:class:`Factory` of particular class with
|
||||
attribute injections. Those injections are done by setting specified attributes
|
||||
with injectable values right after object's creation.
|
||||
|
||||
|
@ -123,10 +131,10 @@ Example:
|
|||
Factory providers and method injections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Current example shows how to create ``di.Factory`` of particular class with
|
||||
method injections. Those injections are done by calling of specified method
|
||||
with injectable value right after object's creation and attribute injections
|
||||
are done.
|
||||
Current example shows how to create :py:class:`Factory` of particular class
|
||||
with method injections. Those injections are done by calling of specified
|
||||
method with injectable value right after object's creation and attribute
|
||||
injections are done.
|
||||
|
||||
Method injections are not very popular in Python due Python best practices
|
||||
(usage of public attributes instead of setter methods), but they may appear in
|
||||
|
@ -142,21 +150,21 @@ Example:
|
|||
Factory providers delegation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``di.Factory`` provider could be delegated to any other provider via any kind
|
||||
of injection. As it was mentioned earlier, if ``di.Factory`` is injectable
|
||||
value, it will be called every time when injection is done. ``di.Factory``
|
||||
delegation is performed by wrapping delegated ``di.Factory`` into special
|
||||
provider type - ``di.Delegate``, that just returns wrapped ``di.Factory``.
|
||||
Saying in other words, delegation of factories - is a way to inject factories
|
||||
themselves, instead of results of their calls.
|
||||
|
||||
:py:class:`Factory` provider could be delegated to any other provider via any
|
||||
kind of injection. As it was mentioned earlier, if :py:class:`Factory` is
|
||||
injectable value, it will be called every time when injection is done.
|
||||
:py:class:`Factory` delegation is performed by wrapping delegated
|
||||
:py:class:`Factory` into special provider type - :py:class:`Delegate`, that
|
||||
just returns wrapped :py:class:`Factory`. Saying in other words, delegation
|
||||
of factories - is a way to inject factories themselves, instead of results
|
||||
of their calls.
|
||||
|
||||
Actually, there are two ways of creating factory delegates:
|
||||
|
||||
+ ``di.Delegate(di.Factory(...))`` - obviously wrapping factory into
|
||||
``di.Delegate`` provider.
|
||||
+ ``di.Factory(...).delegate()`` - calling factory ``delegate()`` method, that
|
||||
returns delegate wrapper for current factory.
|
||||
+ ``Delegate(Factory(...))`` - obviously wrapping factory into
|
||||
:py:class:`Delegate` provider.
|
||||
+ ``Factory(...).delegate()`` - calling factory :py:meth:`Factory.delegate`
|
||||
method, that returns delegate wrapper for current factory.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -4,17 +4,21 @@ Providers
|
|||
Providers are strategies of accessing objects. They describe how particular
|
||||
objects are provided.
|
||||
|
||||
Base providers class is - :py:class:`dependency_injector.providers.Provider`
|
||||
|
||||
Every provider is callable (implements ``__call__()``). Every call to provider
|
||||
instance returns provided result, according to the providing strategy of
|
||||
particular provider.
|
||||
|
||||
Current documentation section consists from description of standard providers
|
||||
library and some useful information like overriding of providers and writing
|
||||
custom providers.
|
||||
of custom providers.
|
||||
|
||||
All providers are validated in multithreading environment and considered to
|
||||
be thread safe.
|
||||
|
||||
Providers module API docs - :py:mod:`dependency_injector.providers`
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Overriding of providers
|
||||
-----------------------
|
||||
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
Every provider could be overridden by another provider.
|
||||
|
||||
This gives opportunity to make system behaviour more flexible in some points.
|
||||
|
@ -15,22 +17,22 @@ Provider overriding functionality has such interface:
|
|||
:width: 45%
|
||||
:align: center
|
||||
|
||||
+ ``di.Provider.override()`` - takes another provider that will be used
|
||||
+ :py:meth:`Provider.override()` - takes another provider that will be used
|
||||
instead of current provider. This method could be called several times.
|
||||
In such case, last passed provider would be used as overriding one.
|
||||
+ ``di.Provider.reset_override()`` - resets all overriding providers. Provider
|
||||
starts to behave itself like usual.
|
||||
+ ``di.Provider.is_overridden`` - bool, ``True`` if provider is overridden.
|
||||
+ :py:meth:`Provider.reset_override()` - resets all overriding providers.
|
||||
Provider starts to behave itself like usual.
|
||||
+ :py:attr:`Provider.is_overridden` - bool, ``True`` if provider is overridden.
|
||||
|
||||
.. note::
|
||||
|
||||
Actually, initial provider forms stack from overriding providers. There is
|
||||
some, not so common, but still usefull, functionality that could be used:
|
||||
|
||||
+ ``di.Provider.last_overriding`` - always keeps reference to last
|
||||
+ :py:attr:`Provider.last_overriding` - always keeps reference to last
|
||||
overriding provider.
|
||||
+ ``di.Provider.reset_last_overriding()`` - remove last overriding provider
|
||||
from stack of overriding providers.
|
||||
+ :py:meth:`Provider.reset_last_overriding()` - remove last overriding
|
||||
provider from stack of overriding providers.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
Singleton providers
|
||||
-------------------
|
||||
|
||||
``di.Singleton`` provider creates new instance of specified class on first call
|
||||
and returns same instance on every next call.
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
:py:class:`Singleton` provider creates new instance of specified class on
|
||||
first call and returns same instance on every next call.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -16,9 +18,9 @@ Example:
|
|||
Singleton providers and injections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``di.Singleton`` providers use ``di.Factory`` providers for first creation of
|
||||
specified class instance, so, all of the rules about injections are the same,
|
||||
as for ``di.Factory`` providers.
|
||||
:py:class:`Singleton` providers use :py:class:`Factory` providers for first
|
||||
creation of specified class instance, so, all of the rules about injections
|
||||
are the same, as for :py:class:`Factory` providers.
|
||||
|
||||
.. image:: /images/providers/singleton_internals.png
|
||||
:width: 80%
|
||||
|
@ -26,29 +28,29 @@ as for ``di.Factory`` providers.
|
|||
|
||||
.. note::
|
||||
|
||||
Due that ``di.Singleton`` provider creates specified class instance only on
|
||||
the first call, all injections are done once, during the first call, also.
|
||||
Every next call, while instance has been already created and memorized, no
|
||||
injections are done, ``di.Singleton`` provider just returns memorized
|
||||
earlier instance.
|
||||
Due that :py:class:`Singleton` provider creates specified class instance
|
||||
only on the first call, all injections are done once, during the first
|
||||
call, also. Every next call, while instance has been already created
|
||||
and memorized, no injections are done, :py:class:`Singleton` provider just
|
||||
returns memorized earlier instance.
|
||||
|
||||
This may cause some problems, for example, in case of trying to bind
|
||||
``di.Factory`` provider with ``di.Singleton`` provider (provided by
|
||||
dependent ``di.Factory`` instance will be injected only once, during the
|
||||
first call). Be aware that such behaviour was made with opened eyes and is
|
||||
not a bug.
|
||||
:py:class:`Factory` provider with :py:class:`Singleton` provider (provided
|
||||
by dependent :py:class:`Factory` instance will be injected only once,
|
||||
during the first call). Be aware that such behaviour was made with opened
|
||||
eyes and is not a bug.
|
||||
|
||||
By the way, in such case, ``di.Delegate`` provider can be useful. It makes
|
||||
possible to inject providers *as is*. Please check out full example in
|
||||
*Providers delegation* section.
|
||||
By the way, in such case, :py:class:`Delegate` provider can be useful. It
|
||||
makes possible to inject providers *as is*. Please check out full example
|
||||
in *Providers delegation* section.
|
||||
|
||||
Singleton providers resetting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Created and memorized by ``di.Singleton`` instance can be reset. Reset of
|
||||
``di.Singleton``'s memorized instance is done by clearing reference to it.
|
||||
Further lifecycle of memorized instance is out of ``di.Singleton`` provider's
|
||||
control.
|
||||
Created and memorized by :py:class:`Singleton` instance can be reset. Reset of
|
||||
:py:class:`Singleton`'s memorized instance is done by clearing reference to
|
||||
it. Further lifecycle of memorized instance is out of :py:class:`Singleton`
|
||||
provider's control.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -58,13 +60,13 @@ Example:
|
|||
Singleton providers delegation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``di.Singleton`` provider could be delegated to any other provider via any
|
||||
kind of injection. Delegation of ``di.Singleton`` providers is the same as
|
||||
``di.Factory`` providers delegation, please follow
|
||||
*Factory providers delegation* section for example.
|
||||
:py:class:`Singleton` provider could be delegated to any other provider via
|
||||
any kind of injection. Delegation of :py:class:`Singleton` providers is the
|
||||
same as :py:class:`Factory` providers delegation, please follow *Factory
|
||||
providers delegation* section for example.
|
||||
|
||||
``di.Singleton`` delegate could be created obviously using
|
||||
``di.Delegate(di.Singleton())`` or by calling ``di.Singleton.delegate()``
|
||||
:py:class:`Singleton` delegate could be created obviously using
|
||||
``Delegate(Singleton(...))`` or by calling ``Singleton(...).delegate()``
|
||||
method.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
Static providers
|
||||
----------------
|
||||
|
||||
.. module:: dependency_injector.providers
|
||||
|
||||
Static providers are family of providers that return their values "as is".
|
||||
There are four types of static providers:
|
||||
|
||||
- ``di.Class``
|
||||
- ``di.Object``
|
||||
- ``di.Function``
|
||||
- ``di.Value``
|
||||
- :py:class:`Class`
|
||||
- :py:class:`Object`
|
||||
- :py:class:`Function`
|
||||
- :py:class:`Value`
|
||||
|
||||
All of them have the same behaviour, but usage of anyone is predicted by
|
||||
readability and providing object's type.
|
||||
All of them have the same behaviour (inherited from
|
||||
:py:class:`StaticProvider`), but usage of any is predicted by readability
|
||||
and providing object's type.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""Config provider examples."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class ObjectA(object):
|
||||
|
@ -13,17 +14,17 @@ class ObjectA(object):
|
|||
self.timezone = timezone
|
||||
|
||||
|
||||
class Catalog(di.AbstractCatalog):
|
||||
class Catalog(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of providers."""
|
||||
|
||||
config = di.Config()
|
||||
""":type: di.Config"""
|
||||
config = providers.Config()
|
||||
""":type: providers.Config"""
|
||||
|
||||
object_a = di.Factory(ObjectA,
|
||||
fee=config.FEE,
|
||||
price=config.PRICE,
|
||||
timezone=config.GLOBAL.TIMEZONE)
|
||||
""":type: di.Provider -> ObjectA"""
|
||||
object_a = providers.Factory(ObjectA,
|
||||
fee=config.FEE,
|
||||
price=config.PRICE,
|
||||
timezone=config.GLOBAL.TIMEZONE)
|
||||
""":type: providers.Provider -> ObjectA"""
|
||||
|
||||
|
||||
# Setting config value and making some tests.
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
"""`@di.inject()` decorator and Flask view example."""
|
||||
"""`inject()` decorator and Flask view example."""
|
||||
|
||||
import sqlite3
|
||||
import flask
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
database = di.Singleton(sqlite3.connect,
|
||||
':memory:',
|
||||
timeout=30,
|
||||
detect_types=True,
|
||||
isolation_level='EXCLUSIVE')
|
||||
database = providers.Singleton(sqlite3.connect,
|
||||
':memory:',
|
||||
timeout=30,
|
||||
detect_types=True,
|
||||
isolation_level='EXCLUSIVE')
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@di.inject(database)
|
||||
@di.inject(flask.request)
|
||||
@injections.inject(database)
|
||||
@injections.inject(flask.request)
|
||||
def hello(request, database):
|
||||
"""Example Flask view."""
|
||||
print request
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
"""`@di.inject()` decorator with classes example."""
|
||||
"""`inject()` decorator with classes example."""
|
||||
|
||||
import sqlite3
|
||||
import flask
|
||||
import flask.views
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
database = di.Singleton(sqlite3.Connection,
|
||||
database=':memory:',
|
||||
timeout=30,
|
||||
detect_types=True,
|
||||
isolation_level='EXCLUSIVE')
|
||||
database = providers.Singleton(sqlite3.Connection,
|
||||
database=':memory:',
|
||||
timeout=30,
|
||||
detect_types=True,
|
||||
isolation_level='EXCLUSIVE')
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
|
||||
@di.inject(database=database)
|
||||
@di.inject(some_setting=777)
|
||||
@injections.inject(database=database)
|
||||
@injections.inject(some_setting=777)
|
||||
class HelloView(flask.views.View):
|
||||
"""Example flask class-based view."""
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
"""`@di.inject()` decorator simple example."""
|
||||
"""`inject()` decorator simple example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
dependency_injector_factory = di.Factory(object)
|
||||
dependency_injector_factory = providers.Factory(object)
|
||||
|
||||
|
||||
# Example of using `di.inject()` decorator keyword argument injections:
|
||||
@di.inject(new_object=dependency_injector_factory)
|
||||
@di.inject(some_setting=1334)
|
||||
@injections.inject(new_object=dependency_injector_factory)
|
||||
@injections.inject(some_setting=1334)
|
||||
def example_callback1(new_object, some_setting):
|
||||
"""Example callback that does some asserts for input args."""
|
||||
assert isinstance(new_object, object)
|
||||
|
@ -16,7 +17,7 @@ def example_callback1(new_object, some_setting):
|
|||
|
||||
|
||||
# Example of using `di.inject()` decorator with positional argument injections:
|
||||
@di.inject(dependency_injector_factory, 1334)
|
||||
@injections.inject(dependency_injector_factory, 1334)
|
||||
def example_callback2(new_object, some_setting):
|
||||
"""Example callback that does some asserts for input args."""
|
||||
assert isinstance(new_object, object)
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
"""Catalog bundles example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import errors
|
||||
|
||||
import services
|
||||
import views
|
||||
|
||||
|
||||
# Declaring services catalog:
|
||||
class Services(di.DeclarativeCatalog):
|
||||
class Services(catalogs.DeclarativeCatalog):
|
||||
"""Example catalog of service providers."""
|
||||
|
||||
users = di.Factory(services.UsersService)
|
||||
""":type: di.Provider -> services.UsersService"""
|
||||
users = providers.Factory(services.Users)
|
||||
""":type: providers.Provider -> services.Users"""
|
||||
|
||||
auth = di.Factory(services.AuthService)
|
||||
""":type: di.Provider -> services.AuthService"""
|
||||
auth = providers.Factory(services.Auth)
|
||||
""":type: providers.Provider -> services.Auth"""
|
||||
|
||||
photos = di.Factory(services.PhotosService)
|
||||
""":type: di.Provider -> services.PhotosService"""
|
||||
photos = providers.Factory(services.Photos)
|
||||
""":type: providers.Provider -> services.Photos"""
|
||||
|
||||
|
||||
# Declaring views catalog:
|
||||
class Views(di.DeclarativeCatalog):
|
||||
class Views(catalogs.DeclarativeCatalog):
|
||||
"""Example catalog of web views."""
|
||||
|
||||
auth = di.Factory(views.AuthView,
|
||||
services=Services.Bundle(Services.users,
|
||||
Services.auth))
|
||||
""":type: di.Provider -> views.AuthView"""
|
||||
auth = providers.Factory(views.Auth,
|
||||
services=Services.Bundle(Services.users,
|
||||
Services.auth))
|
||||
""":type: providers.Provider -> views.Auth"""
|
||||
|
||||
photos = di.Factory(views.PhotosView,
|
||||
services=Services.Bundle(Services.users,
|
||||
Services.photos))
|
||||
""":type: di.Provider -> views.PhotosView"""
|
||||
photos = providers.Factory(views.Photos,
|
||||
services=Services.Bundle(Services.users,
|
||||
Services.photos))
|
||||
""":type: providers.Provider -> views.Photos"""
|
||||
|
||||
|
||||
# Creating example views:
|
||||
|
@ -47,7 +49,7 @@ assert auth_view.services.users is Services.users
|
|||
assert auth_view.services.auth is Services.auth
|
||||
try:
|
||||
auth_view.services.photos
|
||||
except di.Error:
|
||||
except errors.Error:
|
||||
# `photos` service provider is not in scope of `auth_view` services bundle,
|
||||
# so `di.Error` will be raised.
|
||||
pass
|
||||
|
@ -56,7 +58,7 @@ assert photos_view.services.users is Services.users
|
|||
assert photos_view.services.photos is Services.photos
|
||||
try:
|
||||
photos_view.services.auth
|
||||
except di.Error as exception:
|
||||
except errors.Error as exception:
|
||||
# `auth` service provider is not in scope of `photo_processing_view`
|
||||
# services bundle, so `di.Error` will be raised.
|
||||
pass
|
||||
|
|
|
@ -5,13 +5,13 @@ class BaseService(object):
|
|||
"""Example base class of service."""
|
||||
|
||||
|
||||
class UsersService(BaseService):
|
||||
class Users(BaseService):
|
||||
"""Example users service."""
|
||||
|
||||
|
||||
class AuthService(BaseService):
|
||||
class Auth(BaseService):
|
||||
"""Example auth service."""
|
||||
|
||||
|
||||
class PhotosService(BaseService):
|
||||
class Photos(BaseService):
|
||||
"""Example photo service."""
|
||||
|
|
|
@ -7,15 +7,15 @@ class BaseWebView(object):
|
|||
def __init__(self, services):
|
||||
"""Initializer.
|
||||
|
||||
:type services: catalogs.Services
|
||||
:param services: Bundle of service providers
|
||||
:type services: catalogs.Services
|
||||
"""
|
||||
self.services = services
|
||||
|
||||
|
||||
class AuthView(BaseWebView):
|
||||
class Auth(BaseWebView):
|
||||
"""Example auth web view."""
|
||||
|
||||
|
||||
class PhotosView(BaseWebView):
|
||||
class Photos(BaseWebView):
|
||||
"""Example photo processing web view."""
|
||||
|
|
24
examples/catalogs/declarative.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
"""Declarative catalog simple example."""
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Defining declarative catalog:
|
||||
class Catalog(catalogs.DeclarativeCatalog):
|
||||
"""Providers catalog."""
|
||||
|
||||
factory1 = providers.Factory(object)
|
||||
""":type: providers.Provider -> object"""
|
||||
|
||||
factory2 = providers.Factory(object)
|
||||
""":type: providers.Provider -> object"""
|
||||
|
||||
# Creating some objects:
|
||||
object1 = Catalog.factory1()
|
||||
object2 = Catalog.factory2()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object)
|
||||
assert isinstance(object2, object)
|
|
@ -1,20 +1,21 @@
|
|||
"""Operating with catalog providers example."""
|
||||
"""Declarative catalogs inheritance example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class CatalogA(di.DeclarativeCatalog):
|
||||
class CatalogA(catalogs.DeclarativeCatalog):
|
||||
"""Example catalog A."""
|
||||
|
||||
provider1 = di.Factory(object)
|
||||
""":type: di.Provider -> object"""
|
||||
provider1 = providers.Factory(object)
|
||||
""":type: providers.Provider -> object"""
|
||||
|
||||
|
||||
class CatalogB(CatalogA):
|
||||
"""Example catalog B."""
|
||||
|
||||
provider2 = di.Singleton(object)
|
||||
""":type: di.Provider -> object"""
|
||||
provider2 = providers.Singleton(object)
|
||||
""":type: providers.Provider -> object"""
|
||||
|
||||
|
||||
# Making some asserts for `providers` attribute:
|
||||
|
@ -29,7 +30,3 @@ assert CatalogB.cls_providers == dict(provider2=CatalogB.provider2)
|
|||
# Making some asserts for `inherited_providers` attribute:
|
||||
assert CatalogA.inherited_providers == dict()
|
||||
assert CatalogB.inherited_providers == dict(provider1=CatalogA.provider1)
|
||||
|
||||
# Making some asserts for `filter()` method:
|
||||
assert CatalogB.filter(di.Factory) == dict(provider1=CatalogA.provider1)
|
||||
assert CatalogB.filter(di.Singleton) == dict(provider2=CatalogB.provider2)
|
50
examples/catalogs/declarative_injections.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
"""Declarative catalog's provider injections example."""
|
||||
|
||||
import sqlite3
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class UsersService(object):
|
||||
"""Users service, that has dependency on database."""
|
||||
|
||||
def __init__(self, db):
|
||||
"""Initializer."""
|
||||
self.db = db
|
||||
|
||||
|
||||
class AuthService(object):
|
||||
"""Auth service, that has dependencies on users service and database."""
|
||||
|
||||
def __init__(self, db, users_service):
|
||||
"""Initializer."""
|
||||
self.db = db
|
||||
self.users_service = users_service
|
||||
|
||||
|
||||
class Services(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of service providers."""
|
||||
|
||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||
""":type: providers.Provider -> sqlite3.Connection"""
|
||||
|
||||
users = providers.Factory(UsersService,
|
||||
db=database)
|
||||
""":type: providers.Provider -> UsersService"""
|
||||
|
||||
auth = providers.Factory(AuthService,
|
||||
db=database,
|
||||
users_service=users)
|
||||
""":type: providers.Provider -> AuthService"""
|
||||
|
||||
|
||||
# Retrieving service providers from catalog:
|
||||
users_service = Services.users()
|
||||
auth_service = Services.auth()
|
||||
|
||||
# Making some asserts:
|
||||
assert users_service.db is auth_service.db is Services.database()
|
||||
assert isinstance(auth_service.users_service, UsersService)
|
||||
assert users_service is not Services.users()
|
||||
assert auth_service is not Services.auth()
|
18
examples/catalogs/dynamic.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""Dynamic catalog simple example."""
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Defining dynamic catalog:
|
||||
catalog = catalogs.DynamicCatalog(factory1=providers.Factory(object),
|
||||
factory2=providers.Factory(object))
|
||||
|
||||
# Creating some objects:
|
||||
object1 = catalog.factory1()
|
||||
object2 = catalog.factory2()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object)
|
||||
assert isinstance(object2, object)
|
66
examples/catalogs/dynamic_runtime_creation.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
"""Dynamic catalog creation and runtime filling of it example."""
|
||||
|
||||
from dependency_injector import catalogs
|
||||
|
||||
|
||||
# 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('.')
|
||||
if len(path_components) == 1:
|
||||
path_components.insert(0, '__main__')
|
||||
module = __import__('.'.join(path_components[0:-1]),
|
||||
locals(),
|
||||
globals(),
|
||||
fromlist=path_components[-1:])
|
||||
return getattr(module, path_components[-1])
|
||||
|
||||
|
||||
# "Parsing" some configuration:
|
||||
config = {
|
||||
'services': {
|
||||
'users': {
|
||||
'class': 'UsersService',
|
||||
'provider_class': 'dependency_injector.providers.Factory',
|
||||
},
|
||||
'auth': {
|
||||
'class': 'AuthService',
|
||||
'provider_class': 'dependency_injector.providers.Factory',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Defining dynamic service providers catalog:
|
||||
services = catalogs.DynamicCatalog()
|
||||
|
||||
# Filling dynamic service providers catalog according to the 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'])
|
||||
|
||||
# Creating service provider:
|
||||
service_provider = service_provider_cls(service_cls)
|
||||
|
||||
# Binding service provider to the dynamic service providers catalog:
|
||||
services.bind_provider(service_name, service_provider)
|
||||
|
||||
# Creating some objects:
|
||||
users_service = services.users()
|
||||
auth_service = services.auth()
|
||||
|
||||
# Making some asserts:
|
||||
assert isinstance(users_service, UsersService)
|
||||
assert isinstance(auth_service, AuthService)
|
|
@ -1,44 +0,0 @@
|
|||
"""Catalog overriding example."""
|
||||
|
||||
import collections
|
||||
import dependency_injector as di
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
|
||||
|
||||
class Catalog(di.DeclarativeCatalog):
|
||||
"""Providers catalog."""
|
||||
|
||||
object1_factory = di.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
""":type: di.Provider -> Object1"""
|
||||
|
||||
object2_factory = di.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
""":type: di.Provider -> Object2"""
|
||||
|
||||
|
||||
class AnotherCatalog(di.DeclarativeCatalog):
|
||||
"""Another providers catalog."""
|
||||
|
||||
object2_factory = di.Factory(ExtendedObject2)
|
||||
""":type: di.Provider -> ExtendedObject2"""
|
||||
|
||||
|
||||
# Overriding `Catalog` with `AnotherCatalog`:
|
||||
Catalog.override(AnotherCatalog)
|
||||
|
||||
# Creating some objects using overridden catalog:
|
||||
object2_1 = Catalog.object2_factory()
|
||||
object2_2 = Catalog.object2_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
48
examples/catalogs/override_declarative.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
"""Declarative catalog overriding example."""
|
||||
|
||||
import collections
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
|
||||
|
||||
class Catalog(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of some providers."""
|
||||
|
||||
object1_factory = providers.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
""":type: providers.Provider -> Object1"""
|
||||
|
||||
object2_factory = providers.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
""":type: providers.Provider -> Object2"""
|
||||
|
||||
|
||||
class AnotherCatalog(catalogs.DeclarativeCatalog):
|
||||
"""Overriding catalog."""
|
||||
|
||||
object2_factory = providers.Factory(ExtendedObject2)
|
||||
""":type: providers.Provider -> ExtendedObject2"""
|
||||
|
||||
|
||||
# Overriding `Catalog` with `AnotherCatalog`:
|
||||
Catalog.override(AnotherCatalog)
|
||||
|
||||
# Creating some objects using overridden catalog:
|
||||
object2_1 = Catalog.object2_factory()
|
||||
object2_2 = Catalog.object2_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert Catalog.is_overridden
|
||||
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
43
examples/catalogs/override_declarative_by_dynamic.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
"""Declarative catalog overriding by dynamic catalog example."""
|
||||
|
||||
import collections
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
|
||||
|
||||
class Catalog(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of some providers."""
|
||||
|
||||
object1_factory = providers.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
""":type: providers.Provider -> Object1"""
|
||||
|
||||
object2_factory = providers.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
""":type: providers.Provider -> Object2"""
|
||||
|
||||
|
||||
# Overriding `Catalog` with some `DynamicCatalog` instance:
|
||||
overriding_catalog = catalogs.DynamicCatalog(
|
||||
object2_factory=providers.Factory(ExtendedObject2))
|
||||
Catalog.override(overriding_catalog)
|
||||
|
||||
# Creating some objects using overridden catalog:
|
||||
object2_1 = Catalog.object2_factory()
|
||||
object2_2 = Catalog.object2_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert Catalog.is_overridden
|
||||
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
46
examples/catalogs/override_declarative_decorator.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
"""Declarative catalog overriding using `@override()` decorator example."""
|
||||
|
||||
import collections
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
|
||||
|
||||
class Catalog(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of some providers."""
|
||||
|
||||
object1_factory = providers.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
""":type: providers.Provider -> Object1"""
|
||||
|
||||
object2_factory = providers.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
""":type: providers.Provider -> Object2"""
|
||||
|
||||
|
||||
# Overriding `Catalog` with `AnotherCatalog`:
|
||||
@catalogs.override(Catalog)
|
||||
class AnotherCatalog(catalogs.DeclarativeCatalog):
|
||||
"""Overriding catalog."""
|
||||
|
||||
object2_factory = providers.Factory(ExtendedObject2)
|
||||
""":type: providers.Provider -> ExtendedObject2"""
|
||||
|
||||
|
||||
# Creating some objects using overridden catalog:
|
||||
object2_1 = Catalog.object2_factory()
|
||||
object2_2 = Catalog.object2_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert Catalog.is_overridden
|
||||
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
|
@ -1,43 +0,0 @@
|
|||
"""Catalog overriding using `@di.override()` decorator example."""
|
||||
|
||||
import collections
|
||||
import dependency_injector as di
|
||||
|
||||
|
||||
# Creating some example classes:
|
||||
Object1 = collections.namedtuple('Object1', ['arg1', 'arg2'])
|
||||
Object2 = collections.namedtuple('Object2', ['object1'])
|
||||
ExtendedObject2 = collections.namedtuple('ExtendedObject2', [])
|
||||
|
||||
|
||||
class Catalog(di.DeclarativeCatalog):
|
||||
"""Providers catalog."""
|
||||
|
||||
object1_factory = di.Factory(Object1,
|
||||
arg1=1,
|
||||
arg2=2)
|
||||
""":type: di.Provider -> Object1"""
|
||||
|
||||
object2_factory = di.Factory(Object2,
|
||||
object1=object1_factory)
|
||||
""":type: di.Provider -> Object2"""
|
||||
|
||||
|
||||
# Overriding `Catalog` with `AnotherCatalog`:
|
||||
@di.override(Catalog)
|
||||
class AnotherCatalog(di.DeclarativeCatalog):
|
||||
"""Another providers catalog."""
|
||||
|
||||
object2_factory = di.Factory(ExtendedObject2)
|
||||
""":type: di.Provider -> ExtendedObject2"""
|
||||
|
||||
|
||||
# Creating some objects using overridden catalog:
|
||||
object2_1 = Catalog.object2_factory()
|
||||
object2_2 = Catalog.object2_factory()
|
||||
|
||||
# Making some asserts:
|
||||
assert object2_1 is not object2_2
|
||||
|
||||
assert isinstance(object2_1, ExtendedObject2)
|
||||
assert isinstance(object2_2, ExtendedObject2)
|
|
@ -1,22 +0,0 @@
|
|||
"""Catalog example."""
|
||||
|
||||
import dependency_injector as di
|
||||
|
||||
|
||||
class Catalog(di.DeclarativeCatalog):
|
||||
"""Providers catalog."""
|
||||
|
||||
factory1 = di.Factory(object)
|
||||
""":type: di.Provider -> object"""
|
||||
|
||||
factory2 = di.Factory(object)
|
||||
""":type: di.Provider -> object"""
|
||||
|
||||
# Creating some objects:
|
||||
object1 = Catalog.factory1()
|
||||
object2 = Catalog.factory2()
|
||||
|
||||
# Making some asserts:
|
||||
assert object1 is not object2
|
||||
assert isinstance(object1, object)
|
||||
assert isinstance(object2, object)
|
|
@ -1,7 +1,10 @@
|
|||
"""Concept example of `Dependency Injector`."""
|
||||
|
||||
import sqlite3
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import catalogs
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
class UsersService(object):
|
||||
|
@ -21,20 +24,20 @@ class AuthService(object):
|
|||
self.users_service = users_service
|
||||
|
||||
|
||||
class Services(di.DeclarativeCatalog):
|
||||
class Services(catalogs.DeclarativeCatalog):
|
||||
"""Catalog of service providers."""
|
||||
|
||||
database = di.Singleton(sqlite3.connect, ':memory:')
|
||||
""":type: di.Provider -> sqlite3.Connection"""
|
||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||
""":type: providers.Provider -> sqlite3.Connection"""
|
||||
|
||||
users = di.Factory(UsersService,
|
||||
db=database)
|
||||
""":type: di.Provider -> UsersService"""
|
||||
users = providers.Factory(UsersService,
|
||||
db=database)
|
||||
""":type: providers.Provider -> UsersService"""
|
||||
|
||||
auth = di.Factory(AuthService,
|
||||
db=database,
|
||||
users_service=users)
|
||||
""":type: di.Provider -> AuthService"""
|
||||
auth = providers.Factory(AuthService,
|
||||
db=database,
|
||||
users_service=users)
|
||||
""":type: providers.Provider -> AuthService"""
|
||||
|
||||
|
||||
# Retrieving catalog providers:
|
||||
|
@ -49,9 +52,9 @@ assert auth_service is not Services.auth()
|
|||
|
||||
|
||||
# Making some "inline" injections:
|
||||
@di.inject(users_service=Services.users)
|
||||
@di.inject(auth_service=Services.auth)
|
||||
@di.inject(database=Services.database)
|
||||
@injections.inject(users_service=Services.users)
|
||||
@injections.inject(auth_service=Services.auth)
|
||||
@injections.inject(database=Services.database)
|
||||
def example(users_service, auth_service, database):
|
||||
"""Example callback."""
|
||||
assert users_service.db is auth_service.db
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
"""`di.Callable` providers with positional arguments example."""
|
||||
"""`Callable` providers with positional arguments example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Creating even and odd filter providers:
|
||||
even_filter = di.Callable(filter, lambda x: x % 2 == 0)
|
||||
odd_filter = di.Callable(filter, lambda x: x % 2 != 0)
|
||||
even_filter = providers.Callable(filter, lambda x: x % 2 == 0)
|
||||
odd_filter = providers.Callable(filter, lambda x: x % 2 != 0)
|
||||
|
||||
# Creating even and odd ranges using xrange() and filter providers:
|
||||
even_range = even_filter(xrange(1, 10))
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
"""`di.Callable` providers delegation example."""
|
||||
"""`Callable` providers delegation example."""
|
||||
|
||||
import sys
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Creating some callable provider and few delegates of it:
|
||||
callable_provider = di.Callable(sys.exit)
|
||||
callable_provider = providers.Callable(sys.exit)
|
||||
callable_provider_delegate1 = callable_provider.delegate()
|
||||
callable_provider_delegate2 = di.Delegate(callable_provider)
|
||||
callable_provider_delegate2 = providers.Delegate(callable_provider)
|
||||
|
||||
# Making some asserts:
|
||||
assert callable_provider_delegate1() is callable_provider
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
"""`di.Callable` providers with keyword arguments example."""
|
||||
"""`Callable` providers with keyword arguments example."""
|
||||
|
||||
import passlib.hash
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Password hasher and verifier providers (hash function could be changed
|
||||
# anytime (for example, to sha512) without any changes in client's code):
|
||||
password_hasher = di.Callable(passlib.hash.sha256_crypt.encrypt,
|
||||
salt_size=16,
|
||||
rounds=10000)
|
||||
password_verifier = di.Callable(passlib.hash.sha256_crypt.verify)
|
||||
password_hasher = providers.Callable(passlib.hash.sha256_crypt.encrypt,
|
||||
salt_size=16,
|
||||
rounds=10000)
|
||||
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
|
||||
|
||||
# Making some asserts:
|
||||
hashed_password = password_hasher('super secret')
|
||||
|
|
|
@ -1,24 +1,33 @@
|
|||
"""Custom `di.Factory` example."""
|
||||
"""Custom `Factory` example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
"""Example class User."""
|
||||
|
||||
|
||||
class UsersFactory(di.Provider):
|
||||
class UsersFactory(providers.Provider):
|
||||
"""Example users factory."""
|
||||
|
||||
__slots__ = ('_factory',)
|
||||
|
||||
def __init__(self):
|
||||
"""Initializer."""
|
||||
self._factory = di.Factory(User)
|
||||
self._factory = providers.Factory(User)
|
||||
super(UsersFactory, self).__init__()
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Return provided instance."""
|
||||
"""Return provided instance.
|
||||
|
||||
:param args: tuple of context positional arguments
|
||||
:type args: tuple[object]
|
||||
|
||||
:param kwargs: dictionary of context keyword arguments
|
||||
:type kwargs: dict[str, object]
|
||||
|
||||
:rtype: object
|
||||
"""
|
||||
return self._factory(*args, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
"""`di.ExternalDependency` providers example."""
|
||||
"""`ExternalDependency` providers example."""
|
||||
|
||||
import sqlite3
|
||||
import contextlib
|
||||
import dependency_injector as di
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class UserService(object):
|
||||
|
@ -14,7 +15,8 @@ class UserService(object):
|
|||
def __init__(self, database):
|
||||
"""Initializer.
|
||||
|
||||
Database dependency need to be injected via init arg.
|
||||
:param database: Database connection.
|
||||
:type database: sqlite3.dbapi2.Connection
|
||||
"""
|
||||
self.database = database
|
||||
self.database.row_factory = sqlite3.dbapi2.Row
|
||||
|
@ -43,18 +45,18 @@ class UserService(object):
|
|||
|
||||
|
||||
# Database and UserService providers:
|
||||
database = di.ExternalDependency(instance_of=sqlite3.dbapi2.Connection)
|
||||
users_service_factory = di.Factory(UserService,
|
||||
database=database)
|
||||
database = providers.ExternalDependency(instance_of=sqlite3.dbapi2.Connection)
|
||||
users_service_factory = providers.Factory(UserService,
|
||||
database=database)
|
||||
|
||||
# Out of library's scope.
|
||||
#
|
||||
# Setting database provider:
|
||||
database.provided_by(di.Singleton(sqlite3.dbapi2.Connection,
|
||||
database=':memory:',
|
||||
timeout=30,
|
||||
detect_types=True,
|
||||
isolation_level='EXCLUSIVE'))
|
||||
database.provided_by(providers.Singleton(sqlite3.dbapi2.Connection,
|
||||
database=':memory:',
|
||||
timeout=30,
|
||||
detect_types=True,
|
||||
isolation_level='EXCLUSIVE'))
|
||||
|
||||
# Creating UserService instance:
|
||||
users_service = users_service_factory()
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
"""`di.Factory` providers example."""
|
||||
"""`Factory` providers example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
"""Example class User."""
|
||||
|
||||
# Factory provider creates new instance of specified class on every call.
|
||||
users_factory = di.Factory(User)
|
||||
users_factory = providers.Factory(User)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""`di.Factory` providers with attribute injections example."""
|
||||
"""`Factory` providers with attribute injections example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -20,11 +21,13 @@ class CreditCard(object):
|
|||
"""Example class CreditCard."""
|
||||
|
||||
# User, Photo and CreditCard factories:
|
||||
credit_cards_factory = di.Factory(CreditCard)
|
||||
photos_factory = di.Factory(Photo)
|
||||
users_factory = di.Factory(User,
|
||||
di.Attribute('main_photo', photos_factory),
|
||||
di.Attribute('credit_card', credit_cards_factory))
|
||||
credit_cards_factory = providers.Factory(CreditCard)
|
||||
photos_factory = providers.Factory(Photo)
|
||||
users_factory = providers.Factory(User,
|
||||
injections.Attribute('main_photo',
|
||||
photos_factory),
|
||||
injections.Attribute('credit_card',
|
||||
credit_cards_factory))
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`di.Factory` providers delegation example."""
|
||||
"""`Factory` providers delegation example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -9,7 +9,7 @@ class User(object):
|
|||
def __init__(self, photos_factory):
|
||||
"""Initializer.
|
||||
|
||||
:param photos_factory: (di.Factory) -> Photo
|
||||
:param photos_factory: providers.Factory -> Photo
|
||||
"""
|
||||
self.photos_factory = photos_factory
|
||||
self._main_photo = None
|
||||
|
@ -27,9 +27,9 @@ class Photo(object):
|
|||
"""Example class Photo."""
|
||||
|
||||
# User and Photo factories:
|
||||
photos_factory = di.Factory(Photo)
|
||||
users_factory = di.Factory(User,
|
||||
photos_factory=di.Delegate(photos_factory))
|
||||
photos_factory = providers.Factory(Photo)
|
||||
users_factory = providers.Factory(User,
|
||||
photos_factory=photos_factory.delegate())
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`di.Factory` providers with init positional injections example."""
|
||||
"""`Factory` providers with init positional injections example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -16,8 +16,8 @@ class Photo(object):
|
|||
"""Example class Photo."""
|
||||
|
||||
# User and Photo factories:
|
||||
photos_factory = di.Factory(Photo)
|
||||
users_factory = di.Factory(User, photos_factory)
|
||||
photos_factory = providers.Factory(Photo)
|
||||
users_factory = providers.Factory(User, photos_factory)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory() # Same as: user1 = User(Photo())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`di.Factory` providers with init injections priority example."""
|
||||
"""`Factory` providers with init injections priority example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -30,11 +30,11 @@ class CreditCard(object):
|
|||
"""Example class CreditCard."""
|
||||
|
||||
# User, Photo and CreditCard factories:
|
||||
credit_cards_factory = di.Factory(CreditCard)
|
||||
photos_factory = di.Factory(Photo)
|
||||
users_factory = di.Factory(User,
|
||||
main_photo=photos_factory,
|
||||
credit_card=credit_cards_factory)
|
||||
credit_cards_factory = providers.Factory(CreditCard)
|
||||
photos_factory = providers.Factory(Photo)
|
||||
users_factory = providers.Factory(User,
|
||||
main_photo=photos_factory,
|
||||
credit_card=credit_cards_factory)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory(1)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`di.Factory` providers with init keyword injections example."""
|
||||
"""`Factory` providers with init keyword injections example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -16,8 +16,8 @@ class Photo(object):
|
|||
"""Example class Photo."""
|
||||
|
||||
# User and Photo factories:
|
||||
photos_factory = di.Factory(Photo)
|
||||
users_factory = di.Factory(User, main_photo=photos_factory)
|
||||
photos_factory = providers.Factory(Photo)
|
||||
users_factory = providers.Factory(User, main_photo=photos_factory)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory() # Same as: user1 = User(main_photo=Photo())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""`di.Factory` providers with method injections example."""
|
||||
"""`Factory` providers with method injections example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
from dependency_injector import injections
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -28,11 +29,13 @@ class CreditCard(object):
|
|||
"""Example class CreditCard."""
|
||||
|
||||
# User, Photo and CreditCard factories:
|
||||
credit_cards_factory = di.Factory(CreditCard)
|
||||
photos_factory = di.Factory(Photo)
|
||||
users_factory = di.Factory(User,
|
||||
di.Method('set_main_photo', photos_factory),
|
||||
di.Method('set_credit_card', credit_cards_factory))
|
||||
credit_cards_factory = providers.Factory(CreditCard)
|
||||
photos_factory = providers.Factory(Photo)
|
||||
users_factory = providers.Factory(User,
|
||||
injections.Method('set_main_photo',
|
||||
photos_factory),
|
||||
injections.Method('set_credit_card',
|
||||
credit_cards_factory))
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
"""Simple providers overriding example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
"""Example class User."""
|
||||
|
||||
# Users factory:
|
||||
users_factory = di.Factory(User)
|
||||
users_factory = providers.Factory(User)
|
||||
|
||||
# Creating several User objects:
|
||||
user1 = users_factory()
|
||||
|
@ -23,7 +23,7 @@ class SuperUser(User):
|
|||
"""Example class SuperUser."""
|
||||
|
||||
# Overriding users factory:
|
||||
users_factory.override(di.Factory(SuperUser))
|
||||
users_factory.override(providers.Factory(SuperUser))
|
||||
|
||||
# Creating some more User objects using overridden users factory:
|
||||
user3 = users_factory()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Overriding user's model example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class User(object):
|
||||
|
@ -26,8 +26,7 @@ class UserService(object):
|
|||
return self.user_cls(id=id, password='secret' + str(id))
|
||||
|
||||
# Users factory and UserService provider:
|
||||
users_service = di.Factory(UserService,
|
||||
user_cls=User)
|
||||
users_service = providers.Factory(UserService, user_cls=User)
|
||||
|
||||
# Getting several users and making some asserts:
|
||||
user1 = users_service().get_by_id(1)
|
||||
|
@ -71,8 +70,8 @@ class ExtendedUserService(UserService):
|
|||
return user
|
||||
|
||||
# Overriding users_service provider:
|
||||
extended_users_service = di.Factory(ExtendedUserService,
|
||||
user_cls=ExtendedUser)
|
||||
extended_users_service = providers.Factory(ExtendedUserService,
|
||||
user_cls=ExtendedUser)
|
||||
users_service.override(extended_users_service)
|
||||
|
||||
# Getting few other users users and making some asserts:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""`di.Singleton` providers example."""
|
||||
"""`Singleton` providers example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class UserService(object):
|
||||
|
@ -8,7 +8,7 @@ class UserService(object):
|
|||
|
||||
# Singleton provider creates new instance of specified class on first call and
|
||||
# returns same instance on every next call.
|
||||
users_service_provider = di.Singleton(UserService)
|
||||
users_service_provider = providers.Singleton(UserService)
|
||||
|
||||
# Retrieving several UserService objects:
|
||||
user_service1 = users_service_provider()
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
"""`di.Singleton` providers delegation example."""
|
||||
"""`Singleton` providers delegation example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Some singleton provider and few delegates of it:
|
||||
singleton_provider = di.Singleton(object)
|
||||
singleton_provider = providers.Singleton(object)
|
||||
singleton_provider_delegate1 = singleton_provider.delegate()
|
||||
singleton_provider_delegate2 = di.Delegate(singleton_provider)
|
||||
singleton_provider_delegate2 = providers.Delegate(singleton_provider)
|
||||
|
||||
# Making some asserts:
|
||||
assert singleton_provider_delegate1() is singleton_provider
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
"""`di.Singleton` providers resetting example."""
|
||||
"""`Singleton` providers resetting example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class UserService(object):
|
||||
"""Example class UserService."""
|
||||
|
||||
# Users service singleton provider:
|
||||
users_service_provider = di.Singleton(UserService)
|
||||
users_service_provider = providers.Singleton(UserService)
|
||||
|
||||
# Retrieving several UserService objects:
|
||||
user_service1 = users_service_provider()
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
"""Static providers example."""
|
||||
|
||||
import dependency_injector as di
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Provides class - `object`:
|
||||
cls_provider = di.Class(object)
|
||||
cls_provider = providers.Class(object)
|
||||
assert cls_provider() is object
|
||||
|
||||
# Provides object - `object()`:
|
||||
object_provider = di.Object(object())
|
||||
object_provider = providers.Object(object())
|
||||
assert isinstance(object_provider(), object)
|
||||
|
||||
# Provides function - `len`:
|
||||
function_provider = di.Function(len)
|
||||
function_provider = providers.Function(len)
|
||||
assert function_provider() is len
|
||||
|
||||
# Provides value - `123`:
|
||||
value_provider = di.Value(123)
|
||||
value_provider = providers.Value(123)
|
||||
assert value_provider() == 123
|
||||
|
|
|
@ -1 +1,13 @@
|
|||
"""Dependency injector unittests."""
|
||||
|
||||
import unittest2 as unittest
|
||||
|
||||
from dependency_injector import VERSION
|
||||
|
||||
|
||||
class VersionTest(unittest.TestCase):
|
||||
"""Version constant tests."""
|
||||
|
||||
def test_version_follows_semantic_versioning(self):
|
||||
"""Test that version follows semantic versioning."""
|
||||
self.assertEquals(len(VERSION.split('.')))
|
||||
|
|
|
@ -282,11 +282,9 @@ class DeclarativeCatalogTests(unittest.TestCase):
|
|||
|
||||
self.assertIs(CatalogA.px, px)
|
||||
self.assertIs(CatalogA.get_provider('px'), px)
|
||||
self.assertIs(CatalogA.catalog.px, px)
|
||||
|
||||
self.assertIs(CatalogA.py, py)
|
||||
self.assertIs(CatalogA.get_provider('py'), py)
|
||||
self.assertIs(CatalogA.catalog.py, py)
|
||||
|
||||
del CatalogA.px
|
||||
del CatalogA.py
|
||||
|
@ -300,11 +298,9 @@ class DeclarativeCatalogTests(unittest.TestCase):
|
|||
|
||||
self.assertIs(CatalogB.px, px)
|
||||
self.assertIs(CatalogB.get_provider('px'), px)
|
||||
self.assertIs(CatalogB.catalog.px, px)
|
||||
|
||||
self.assertIs(CatalogB.py, py)
|
||||
self.assertIs(CatalogB.get_provider('py'), py)
|
||||
self.assertIs(CatalogB.catalog.py, py)
|
||||
|
||||
del CatalogB.px
|
||||
del CatalogB.py
|
||||
|
@ -319,11 +315,9 @@ class DeclarativeCatalogTests(unittest.TestCase):
|
|||
|
||||
self.assertIs(CatalogB.px, px)
|
||||
self.assertIs(CatalogB.get_provider('px'), px)
|
||||
self.assertIs(CatalogB.catalog.px, px)
|
||||
|
||||
self.assertIs(CatalogB.py, py)
|
||||
self.assertIs(CatalogB.get_provider('py'), py)
|
||||
self.assertIs(CatalogB.catalog.py, py)
|
||||
|
||||
del CatalogB.px
|
||||
del CatalogB.py
|
||||
|
@ -480,6 +474,23 @@ class OverrideTests(unittest.TestCase):
|
|||
self.assertEqual(CatalogA.p12(), 2)
|
||||
self.assertEqual(len(CatalogA.overridden_by), 1)
|
||||
|
||||
def test_override_declarative_catalog_with_itself(self):
|
||||
"""Test catalog overriding of declarative catalog with itself."""
|
||||
with self.assertRaises(errors.Error):
|
||||
CatalogA.override(CatalogA)
|
||||
|
||||
def test_override_declarative_catalog_with_subclass(self):
|
||||
"""Test catalog overriding of declarative catalog with subclass."""
|
||||
with self.assertRaises(errors.Error):
|
||||
CatalogB.override(CatalogA)
|
||||
|
||||
def test_override_dynamic_catalog_with_itself(self):
|
||||
"""Test catalog overriding of dynamic catalog with itself."""
|
||||
catalog = catalogs.DynamicCatalog(p11=providers.Value(1),
|
||||
p12=providers.Value(2))
|
||||
with self.assertRaises(errors.Error):
|
||||
catalog.override(catalog)
|
||||
|
||||
def test_overriding_with_dynamic_catalog(self):
|
||||
"""Test catalog overriding with another dynamic catalog."""
|
||||
CatalogA.override(catalogs.DynamicCatalog(p11=providers.Value(1),
|
||||
|
@ -512,8 +523,7 @@ class OverrideTests(unittest.TestCase):
|
|||
|
||||
def test_last_overriding_on_not_overridden(self):
|
||||
"""Test catalog last_overriding property on not overridden catalog."""
|
||||
with self.assertRaises(errors.Error):
|
||||
CatalogA.last_overriding
|
||||
self.assertIsNone(CatalogA.last_overriding)
|
||||
|
||||
def test_reset_last_overriding(self):
|
||||
"""Test resetting last overriding catalog."""
|
||||
|
@ -561,3 +571,14 @@ class OverrideTests(unittest.TestCase):
|
|||
|
||||
self.assertFalse(CatalogA.p11.is_overridden)
|
||||
self.assertFalse(CatalogA.p12.is_overridden)
|
||||
|
||||
|
||||
class CatalogModuleBackwardCompatibility(unittest.TestCase):
|
||||
"""Backward compatibility test of catalog module."""
|
||||
|
||||
def test_import_catalog(self):
|
||||
"""Test that module `catalog` is the same as `catalogs`."""
|
||||
from dependency_injector import catalog
|
||||
from dependency_injector import catalogs
|
||||
|
||||
self.assertIs(catalog, catalogs)
|
||||
|
|
|
@ -90,13 +90,7 @@ class ProviderTests(unittest.TestCase):
|
|||
|
||||
def test_last_overriding_of_not_overridden_provider(self):
|
||||
"""Test getting last overriding from not overridden provider."""
|
||||
try:
|
||||
self.provider.last_overriding
|
||||
except errors.Error:
|
||||
pass
|
||||
else:
|
||||
self.fail('Got en error in {}'.format(
|
||||
str(self.test_last_overriding_of_not_overridden_provider)))
|
||||
self.assertIsNone(self.provider.last_overriding)
|
||||
|
||||
def test_reset_last_overriding(self):
|
||||
"""Test reseting of last overriding provider."""
|
||||
|
@ -129,13 +123,7 @@ class ProviderTests(unittest.TestCase):
|
|||
self.provider.reset_override()
|
||||
|
||||
self.assertFalse(self.provider.is_overridden)
|
||||
try:
|
||||
self.provider.last_overriding
|
||||
except errors.Error:
|
||||
pass
|
||||
else:
|
||||
self.fail('Got en error in {}'.format(
|
||||
str(self.test_last_overriding_of_not_overridden_provider)))
|
||||
self.assertIsNone(self.provider.last_overriding)
|
||||
|
||||
|
||||
class DelegateTests(unittest.TestCase):
|
||||
|
@ -564,6 +552,35 @@ class SingletonTests(unittest.TestCase):
|
|||
self.assertIsInstance(instance1, object)
|
||||
self.assertIsInstance(instance2, object)
|
||||
|
||||
def test_provides_attr(self):
|
||||
"""Test provides attribute."""
|
||||
provider = providers.Singleton(Example)
|
||||
self.assertIs(provider.provides, Example)
|
||||
|
||||
def test_args_attr(self):
|
||||
"""Test args attribute."""
|
||||
provider = providers.Singleton(Example, 1, 2)
|
||||
self.assertEquals(len(provider.args), 2)
|
||||
|
||||
def test_kwargs_attr(self):
|
||||
"""Test kwargs attribute."""
|
||||
provider = providers.Singleton(Example, init_arg1=1, init_arg2=2)
|
||||
self.assertEquals(len(provider.kwargs), 2)
|
||||
|
||||
def test_attributes_attr(self):
|
||||
"""Test attributes attribute."""
|
||||
provider = providers.Singleton(Example,
|
||||
injections.Attribute('attribute1', 1),
|
||||
injections.Attribute('attribute2', 2))
|
||||
self.assertEquals(len(provider.attributes), 2)
|
||||
|
||||
def test_methods_attr(self):
|
||||
"""Test methods attribute."""
|
||||
provider = providers.Singleton(Example,
|
||||
injections.Method('method1', 1),
|
||||
injections.Method('method2', 2))
|
||||
self.assertEquals(len(provider.methods), 2)
|
||||
|
||||
def test_injections(self):
|
||||
"""Test getting a full list of injections using injections property."""
|
||||
provider = providers.Singleton(Example,
|
||||
|
|