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