python-dependency-injector/dependency_injector/catalogs.py

824 lines
24 KiB
Python
Raw Normal View History

"""Catalogs module."""
2015-01-04 17:26:33 +03:00
2015-09-01 00:36:26 +03:00
import six
2015-07-17 19:31:44 +03:00
2015-03-13 18:31:07 +03:00
from .errors import Error
from .errors import UndefinedProviderError
2015-07-17 19:31:44 +03:00
from .utils import is_provider
from .utils import is_catalog
2015-11-10 18:58:04 +03:00
from .utils import ensure_is_provider
from .utils import ensure_is_catalog_bundle
2015-07-17 19:31:44 +03:00
@six.python_2_unicode_compatible
class CatalogBundle(object):
2015-11-20 14:46:57 +03:00
"""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
"""Bundle's catalog.
2015-11-24 10:59:53 +03:00
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
"""
__IS_CATALOG_BUNDLE__ = True
__slots__ = ('providers', '__dict__')
2015-11-20 14:46:57 +03:00
@classmethod
def sub_cls_factory(cls, catalog):
"""Create bundle subclass for catalog.
2015-11-24 10:59:53 +03:00
:return: Subclass of :py:class:`CatalogBundle`
:rtype: :py:class:`CatalogBundle`
2015-11-20 14:46:57 +03:00
"""
return type('BundleSubclass', (cls,), dict(catalog=catalog))
def __init__(self, *providers):
"""Initializer.
:param providers: Tuple of catalog's bundle providers
:type providers: tuple[
:py:class:`dependency_injector.providers.Provider`]
"""
self.providers = dict()
"""Dictionary of all providers.
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
for provider in providers:
provider_name = self.catalog.get_provider_bind_name(provider)
self.providers[provider_name] = provider
self.__dict__.update(self.providers)
super(CatalogBundle, self).__init__()
2015-11-11 16:51:42 +03:00
def get_provider(self, name):
"""Return provider with specified name or raise an error.
:param name: Provider's name
:type name: str
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
:return: Provider with specified name
:rtype: :py:class:`dependency_injector.providers.Provider`
"""
try:
return self.providers[name]
except KeyError:
raise Error('Provider "{0}" is not a part of {1}'.format(name,
self))
2015-11-11 16:51:42 +03:00
def has_provider(self, name):
"""Check if there is provider with certain name.
:param name: Provider's name
:type name: str
:rtype: bool
"""
return name in self.providers
def __getattr__(self, item):
"""Return provider with specified name or raise en error.
:param name: Attribute's name
:type name: str
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
"""
if item.startswith('__') and item.endswith('__'):
return super(CatalogBundle, self).__getattr__(item)
raise UndefinedProviderError('Provider "{0}" is not a part '
'of {1}'.format(item, self))
def __repr__(self):
"""Return string representation of catalog's bundle.
:rtype: str
"""
return '<{0}.Bundle({1})>'.format(
self.catalog.name, ', '.join(six.iterkeys(self.providers)))
__str__ = __repr__
2015-11-10 18:58:04 +03:00
@six.python_2_unicode_compatible
class DynamicCatalog(object):
2015-11-24 11:33:29 +03:00
"""Dynamic catalog of providers.
.. code-block:: python
services = DynamicCatalog(auth=providers.Factory(AuthService),
users=providers.Factory(UsersService))
users_service = services.users()
"""
2015-11-10 18:58:04 +03:00
__IS_CATALOG__ = True
2015-11-11 16:45:39 +03:00
__slots__ = ('name', 'providers', 'provider_names', 'overridden_by',
'Bundle')
2015-11-10 18:58:04 +03:00
def __init__(self, **providers):
2015-11-10 18:58:04 +03:00
"""Initializer.
: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.
2015-11-24 10:59:53 +03:00
:type: :py:class:`CatalogBundle`
2015-11-10 18:58:04 +03:00
"""
self.name = '.'.join((self.__class__.__module__,
self.__class__.__name__))
"""Catalog's name.
By default, it is catalog's module + catalog's class name.
:type: str
"""
2015-11-10 18:58:04 +03:00
self.providers = dict()
"""Dictionary of all providers.
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
2015-11-10 18:58:04 +03:00
self.provider_names = dict()
self.overridden_by = tuple()
"""Tuple of overriding catalogs.
2015-11-14 00:43:36 +03:00
:type: tuple[
2015-11-24 10:59:53 +03:00
:py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`]
2015-11-14 00:43:36 +03:00
"""
2015-11-11 16:45:39 +03:00
self.bind_providers(providers)
2015-11-12 14:43:54 +03:00
super(DynamicCatalog, self).__init__()
2015-11-11 16:45:39 +03:00
2015-11-10 18:58:04 +03:00
def is_bundle_owner(self, bundle):
"""Check if catalog is bundle owner.
:param bundle: Catalog's bundle instance
2015-11-24 10:59:53 +03:00
:type bundle: :py:class:`CatalogBundle`
:rtype: bool
"""
2015-11-10 18:58:04 +03:00
return ensure_is_catalog_bundle(bundle) and bundle.catalog is self
def get_provider_bind_name(self, provider):
"""Return provider's name in catalog.
:param provider: Provider instance
:type provider: :py:class:`dependency_injector.providers.Provider`
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
:return: Provider's name
:rtype: str
"""
2015-11-10 18:58:04 +03:00
if not self.is_provider_bound(provider):
raise Error('Can not find bind name for {0} in catalog {1}'.format(
provider, self))
return self.provider_names[provider]
def is_provider_bound(self, provider):
"""Check if provider is bound to the catalog.
:param provider: Provider instance
:type provider: :py:class:`dependency_injector.providers.Provider`
:rtype: bool
"""
2015-11-10 18:58:04 +03:00
return provider in self.provider_names
def filter(self, provider_type):
"""Return dictionary of providers, that are instance of provided type.
:param provider_type: Provider type
:type provider_type: :py:class:`dependency_injector.providers.Provider`
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
2015-11-10 18:58:04 +03:00
return dict((name, provider)
for name, provider in six.iteritems(self.providers)
if isinstance(provider, provider_type))
@property
def is_overridden(self):
2015-11-20 19:52:19 +03:00
"""Read-only property that is set to ``True`` if catalog is overridden.
:rtype: bool
"""
2015-11-10 18:58:04 +03:00
return bool(self.overridden_by)
@property
def last_overriding(self):
"""Read-only reference to the last overriding catalog, if any.
2015-11-24 10:59:53 +03:00
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
"""
2015-11-10 18:58:04 +03:00
try:
return self.overridden_by[-1]
except (TypeError, IndexError):
raise Error('Catalog {0} is not overridden'.format(self))
def override(self, overriding):
"""Override current catalog providers by overriding catalog providers.
:param overriding: Overriding catalog
2015-11-24 10:59:53 +03:00
:type overriding: :py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`
:rtype: None
2015-11-10 18:58:04 +03:00
"""
self.overridden_by += (overriding,)
for name, provider in six.iteritems(overriding.providers):
2015-11-11 16:45:39 +03:00
self.get_provider(name).override(provider)
2015-11-10 18:58:04 +03:00
def reset_last_overriding(self):
"""Reset last overriding catalog.
:rtype: None
"""
2015-11-10 18:58:04 +03:00
if not self.is_overridden:
raise Error('Catalog {0} is not overridden'.format(self))
self.overridden_by = self.overridden_by[:-1]
for provider in six.itervalues(self.providers):
provider.reset_last_overriding()
def reset_override(self):
"""Reset all overridings for all catalog providers.
:rtype: None
"""
2015-11-10 18:58:04 +03:00
self.overridden_by = tuple()
for provider in six.itervalues(self.providers):
provider.reset_override()
2015-11-11 16:45:39 +03:00
def get_provider(self, name):
"""Return provider with specified name or raise an error.
:param name: Provider's name
:type name: str
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
:return: Provider with specified name
:rtype: :py:class:`dependency_injector.providers.Provider`
"""
2015-11-10 18:58:04 +03:00
try:
return self.providers[name]
except KeyError:
raise UndefinedProviderError('{0} has no provider with such '
'name - {1}'.format(self, name))
2015-11-10 18:58:04 +03:00
2015-11-11 16:45:39 +03:00
def bind_provider(self, name, provider):
"""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:class:`dependency_injector.errors.Error`
:rtype: None
"""
2015-11-11 16:45:39 +03:00
provider = ensure_is_provider(provider)
if name in self.providers:
raise Error('Catalog {0} already has provider with '
'such name - {1}'.format(self, name))
if provider in self.provider_names:
raise Error('Catalog {0} already has such provider '
'instance - {1}'.format(self, provider))
self.providers[name] = provider
self.provider_names[provider] = name
def bind_providers(self, providers):
"""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:class:`dependency_injector.errors.Error`
:rtype: None
"""
2015-11-11 16:45:39 +03:00
for name, provider in six.iteritems(providers):
self.bind_provider(name, provider)
def has_provider(self, name):
"""Check if there is provider with certain name.
:param name: Provider's name
:type name: str
:rtype: bool
"""
2015-11-10 18:58:04 +03:00
return name in self.providers
2015-11-12 17:56:00 +03:00
def unbind_provider(self, name):
"""Remove provider binding.
:param name: Provider's name
:type name: str
:rtype: None
"""
2015-11-12 17:56:00 +03:00
provider = self.get_provider(name)
del self.providers[name]
del self.provider_names[provider]
2015-11-11 16:45:39 +03:00
def __getattr__(self, name):
"""Return provider with specified name or raise en error.
:param name: Attribute's name
:type name: str
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
"""
2015-11-11 16:45:39 +03:00
return self.get_provider(name)
2015-11-12 14:43:54 +03:00
def __setattr__(self, name, value):
"""Handle setting of catalog attributes.
Setting of attributes works as usual, but if value of attribute is
provider, this provider will be bound to catalog.
:param name: Attribute's name
:type name: str
:param value: Attribute's value
:type value: :py:class:`dependency_injector.providers.Provider` |
object
:rtype: None
2015-11-12 14:43:54 +03:00
"""
if is_provider(value):
return self.bind_provider(name, value)
return super(DynamicCatalog, self).__setattr__(name, value)
2015-11-12 17:56:00 +03:00
def __delattr__(self, name):
"""Handle deleting of catalog attibute.
Deleting of attributes works as usual, but if value of attribute is
provider, this provider will be unbound from catalog.
:param name: Attribute's name
:type name: str
:rtype: None
2015-11-12 17:56:00 +03:00
"""
self.unbind_provider(name)
2015-11-10 18:58:04 +03:00
def __repr__(self):
"""Return Python representation of catalog.
:rtype: str
"""
2015-11-11 16:45:39 +03:00
return '<{0}({1})>'.format(self.name,
', '.join(six.iterkeys(self.providers)))
2015-11-10 18:58:04 +03:00
__str__ = __repr__
2015-11-04 17:32:04 +03:00
@six.python_2_unicode_compatible
class DeclarativeCatalogMetaClass(type):
"""Declarative catalog meta class."""
2015-07-17 19:31:44 +03:00
def __new__(mcs, class_name, bases, attributes):
"""Declarative catalog class factory."""
2015-11-10 16:15:48 +03:00
cls_providers = tuple((name, provider)
for name, provider in six.iteritems(attributes)
if is_provider(provider))
inherited_providers = tuple((name, provider)
for base in bases if is_catalog(base)
for name, provider in six.iteritems(
base.providers))
providers = cls_providers + inherited_providers
2015-10-15 20:15:38 +03:00
2015-11-12 14:43:54 +03:00
cls = type.__new__(mcs, class_name, bases, attributes)
2015-11-11 16:45:39 +03:00
2015-11-14 00:43:36 +03:00
cls._catalog = DynamicCatalog()
cls._catalog.name = '.'.join((cls.__module__, cls.__name__))
cls._catalog.bind_providers(dict(providers))
2015-11-11 16:45:39 +03:00
2015-11-10 16:15:48 +03:00
cls.cls_providers = dict(cls_providers)
cls.inherited_providers = dict(inherited_providers)
2015-10-14 17:51:05 +03:00
2015-11-14 00:43:36 +03:00
cls.Bundle = cls._catalog.Bundle
2015-11-11 16:45:39 +03:00
2015-10-14 17:51:05 +03:00
return cls
2015-01-04 17:26:33 +03:00
2015-11-12 14:43:54 +03:00
@property
def name(cls):
"""Read-only property that represents catalog's name.
Catalog's name is catalog's module + catalog's class name.
:type: str
"""
2015-11-14 00:43:36 +03:00
return cls._catalog.name
2015-11-12 14:43:54 +03:00
2015-11-10 18:58:04 +03:00
@property
def providers(cls):
"""Read-only dictionary of all providers.
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
2015-11-14 00:43:36 +03:00
return cls._catalog.providers
2015-11-10 18:58:04 +03:00
@property
def overridden_by(cls):
"""Tuple of overriding catalogs.
:type: tuple[
2015-11-24 10:59:53 +03:00
:py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`]
"""
2015-11-14 00:43:36 +03:00
return cls._catalog.overridden_by
2015-10-16 23:54:51 +03:00
@property
def is_overridden(cls):
2015-11-20 19:52:19 +03:00
"""Read-only property that is set to ``True`` if catalog is overridden.
:rtype: bool
"""
2015-11-14 00:43:36 +03:00
return cls._catalog.is_overridden
@property
def last_overriding(cls):
"""Read-only reference to the last overriding catalog, if any.
2015-11-24 10:59:53 +03:00
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
"""
2015-11-14 00:43:36 +03:00
return cls._catalog.last_overriding
2015-11-12 14:43:54 +03:00
def __getattr__(cls, name):
2015-11-14 00:43:36 +03:00
"""Return provider with specified name or raise en error.
:param name: Attribute's name
:type name: str
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
2015-11-14 00:43:36 +03:00
"""
2015-11-12 14:43:54 +03:00
raise UndefinedProviderError('There is no provider "{0}" in '
'catalog {1}'.format(name, cls))
def __setattr__(cls, name, value):
"""Handle setting of catalog attributes.
Setting of attributes works as usual, but if value of attribute is
provider, this provider will be bound to catalog.
2015-11-14 00:43:36 +03:00
:param name: Attribute's name
:type name: str
:param value: Attribute's value
:type value: :py:class:`dependency_injector.providers.Provider` |
object
2015-11-14 00:43:36 +03:00
:rtype: None
2015-11-12 14:43:54 +03:00
"""
if is_provider(value):
2015-11-14 00:43:36 +03:00
setattr(cls._catalog, name, value)
2015-11-12 14:43:54 +03:00
return super(DeclarativeCatalogMetaClass, cls).__setattr__(name, value)
2015-11-12 17:56:00 +03:00
def __delattr__(cls, name):
"""Handle deleting of catalog attibute.
Deleting of attributes works as usual, but if value of attribute is
provider, this provider will be unbound from catalog.
2015-11-14 00:43:36 +03:00
:param name: Attribute's name
:type name: str
:rtype: None
2015-11-12 17:56:00 +03:00
"""
if is_provider(getattr(cls, name)):
2015-11-14 00:43:36 +03:00
delattr(cls._catalog, name)
2015-11-12 17:56:00 +03:00
return super(DeclarativeCatalogMetaClass, cls).__delattr__(name)
2015-10-11 15:34:21 +03:00
def __repr__(cls):
2015-11-14 00:43:36 +03:00
"""Return string representation of the catalog.
:rtype: str
"""
return '<{0}({1})>'.format(cls.name,
', '.join(six.iterkeys(cls.providers)))
2015-11-04 17:32:04 +03:00
__str__ = __repr__
2015-10-11 15:34:21 +03:00
2015-01-04 17:26:33 +03:00
@six.add_metaclass(DeclarativeCatalogMetaClass)
class DeclarativeCatalog(object):
2015-11-16 14:28:27 +03:00
"""Declarative catalog of providers.
2015-11-20 14:46:57 +03:00
: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).
2015-11-24 11:33:29 +03:00
.. code-block:: python
class Services(DeclarativeCatalog):
auth = providers.Factory(AuthService)
users = providers.Factory(UsersService)
users_service = Services.users()
2015-11-14 00:43:36 +03:00
"""
2015-11-14 00:43:36 +03:00
Bundle = CatalogBundle
"""Catalog's bundle class.
2015-11-24 10:59:53 +03:00
:type: :py:class:`CatalogBundle`
2015-11-14 00:43:36 +03:00
"""
2015-11-14 00:43:36 +03:00
name = str()
"""Read-only property that represents catalog's name.
2015-10-15 20:15:38 +03:00
Catalog's name is catalog's module + catalog's class name.
2015-11-16 14:28:27 +03:00
2015-11-14 00:43:36 +03:00
:type: str
"""
2015-11-14 00:43:36 +03:00
cls_providers = dict()
"""Read-only dictionary of current catalog providers.
2015-11-16 14:28:27 +03:00
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
"""
2015-07-17 19:31:44 +03:00
2015-11-14 00:43:36 +03:00
inherited_providers = dict()
"""Read-only dictionary of inherited providers.
2015-10-15 20:15:38 +03:00
2015-11-16 14:28:27 +03:00
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
2015-11-14 00:43:36 +03:00
"""
2015-10-15 20:15:38 +03:00
providers = dict()
2015-11-14 00:43:36 +03:00
"""Read-only dictionary of all providers.
2015-11-16 14:28:27 +03:00
:type: dict[str, :py:class:`dependency_injector.providers.Provider`]
2015-11-14 00:43:36 +03:00
"""
2015-01-04 17:26:33 +03:00
overridden_by = tuple()
2015-11-14 00:43:36 +03:00
"""Tuple of overriding catalogs.
2015-11-24 10:59:53 +03:00
:type: tuple[:py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`]
2015-11-14 00:43:36 +03:00
"""
is_overridden = bool
2015-11-20 19:52:19 +03:00
"""Read-only property that is set to ``True`` if catalog is overridden.
2015-11-14 00:43:36 +03:00
:type: bool
"""
last_overriding = None
2015-11-14 00:43:36 +03:00
"""Read-only reference to the last overriding catalog, if any.
2015-11-24 10:59:53 +03:00
:type: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
2015-11-14 00:43:36 +03:00
"""
2015-11-14 00:43:36 +03:00
_catalog = DynamicCatalog
__IS_CATALOG__ = True
@classmethod
def is_bundle_owner(cls, bundle):
2015-11-14 00:43:36 +03:00
"""Check if catalog is bundle owner.
2015-11-16 14:28:27 +03:00
:param bundle: Catalog's bundle instance
2015-11-24 10:59:53 +03:00
:type bundle: :py:class:`CatalogBundle`
2015-11-14 00:43:36 +03:00
:rtype: bool
"""
return cls._catalog.is_bundle_owner(bundle)
@classmethod
def get_provider_bind_name(cls, provider):
2015-11-14 00:43:36 +03:00
"""Return provider's name in catalog.
:param provider: Provider instance
2015-11-16 14:28:27 +03:00
:type provider: :py:class:`dependency_injector.providers.Provider`
2015-11-14 00:43:36 +03:00
2015-11-16 14:28:27 +03:00
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
2015-11-14 00:43:36 +03:00
:return: Provider's name
:rtype: str
"""
return cls._catalog.get_provider_bind_name(provider)
@classmethod
def is_provider_bound(cls, provider):
2015-11-14 00:43:36 +03:00
"""Check if provider is bound to the catalog.
:param provider: Provider instance
2015-11-16 14:28:27 +03:00
:type provider: :py:class:`dependency_injector.providers.Provider`
2015-11-14 00:43:36 +03:00
:rtype: bool
"""
return cls._catalog.is_provider_bound(provider)
2015-01-11 19:10:11 +03:00
@classmethod
2015-07-17 19:31:44 +03:00
def filter(cls, provider_type):
"""Return dictionary of providers, that are instance of provided type.
2015-11-14 00:43:36 +03:00
:param provider_type: Provider type
:type provider_type: :py:class:`dependency_injector.providers.Provider`
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
2015-11-14 00:43:36 +03:00
"""
return cls._catalog.filter(provider_type)
2015-01-11 19:10:11 +03:00
@classmethod
2015-03-12 13:45:15 +03:00
def override(cls, overriding):
2015-07-06 16:52:51 +03:00
"""Override current catalog providers by overriding catalog providers.
2015-01-11 19:10:11 +03:00
2015-11-14 00:43:36 +03:00
:param overriding: Overriding catalog
2015-11-24 10:59:53 +03:00
:type overriding: :py:class:`DeclarativeCatalog` |
:py:class:`DynamicCatalog`
2015-11-14 00:43:36 +03:00
:rtype: None
2015-01-11 19:10:11 +03:00
"""
2015-11-14 00:43:36 +03:00
return cls._catalog.override(overriding)
@classmethod
def reset_last_overriding(cls):
2015-11-14 00:43:36 +03:00
"""Reset last overriding catalog.
:rtype: None
"""
cls._catalog.reset_last_overriding()
@classmethod
def reset_override(cls):
2015-11-14 00:43:36 +03:00
"""Reset all overridings for all catalog providers.
:rtype: None
"""
cls._catalog.reset_override()
2015-10-11 15:34:21 +03:00
@classmethod
2015-11-12 14:43:54 +03:00
def get_provider(cls, name):
2015-11-14 00:43:36 +03:00
"""Return provider with specified name or raise an error.
:param name: Provider's name
:type name: str
2015-11-16 14:28:27 +03:00
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
2015-11-14 00:43:36 +03:00
:return: Provider with specified name
2015-11-16 14:28:27 +03:00
:rtype: :py:class:`dependency_injector.providers.Provider`
2015-11-14 00:43:36 +03:00
"""
return cls._catalog.get_provider(name)
2015-10-11 15:34:21 +03:00
2015-11-16 14:28:27 +03:00
get = get_provider # Backward compatibility for versions < 0.11.*
2015-10-11 15:34:21 +03:00
@classmethod
2015-11-12 14:43:54 +03:00
def bind_provider(cls, name, provider):
2015-11-14 00:43:36 +03:00
"""Bind provider to catalog with specified name.
:param name: Name of the provider
:type name: str
:param provider: Provider instance
2015-11-16 14:28:27 +03:00
:type provider: :py:class:`dependency_injector.providers.Provider`
2015-11-14 00:43:36 +03:00
2015-11-16 14:28:27 +03:00
:raise: :py:class:`dependency_injector.errors.Error`
2015-11-14 00:43:36 +03:00
:rtype: None
"""
2015-11-12 17:56:00 +03:00
setattr(cls, name, provider)
2015-11-12 14:43:54 +03:00
@classmethod
def bind_providers(cls, providers):
2015-11-14 00:43:36 +03:00
"""Bind providers dictionary to catalog.
:param providers: Dictionary of providers, where key is a name
and value is a provider
2015-11-16 14:28:27 +03:00
:type providers:
dict[str, :py:class:`dependency_injector.providers.Provider`]
2015-11-14 00:43:36 +03:00
2015-11-16 14:28:27 +03:00
:raise: :py:class:`dependency_injector.errors.Error`
2015-11-14 00:43:36 +03:00
:rtype: None
"""
2015-11-12 17:56:00 +03:00
for name, provider in six.iteritems(providers):
setattr(cls, name, provider)
2015-11-12 14:43:54 +03:00
@classmethod
def has_provider(cls, name):
2015-11-14 00:43:36 +03:00
"""Check if there is provider with certain name.
:param name: Provider's name
:type name: str
:rtype: bool
"""
2015-11-12 17:56:00 +03:00
return hasattr(cls, name)
2015-11-16 14:28:27 +03:00
has = has_provider # Backward compatibility for versions < 0.11.*
2015-11-12 17:56:00 +03:00
@classmethod
def unbind_provider(cls, name):
2015-11-14 00:43:36 +03:00
"""Remove provider binding.
:param name: Provider's name
:type name: str
:rtype: None
"""
2015-11-12 17:56:00 +03:00
delattr(cls, name)
2015-10-11 15:34:21 +03:00
2015-11-16 14:28:27 +03:00
@classmethod
def __getattr__(cls, name): # pragma: no cover
2015-11-16 14:28:27 +03:00
"""Return provider with specified name or raise en error.
:param name: Attribute's name
:type name: str
:raise: :py:class:`dependency_injector.errors.UndefinedProviderError`
"""
raise NotImplementedError('Implementated in metaclass')
@classmethod
def __setattr__(cls, name, value): # pragma: no cover
2015-11-16 14:28:27 +03:00
"""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
2015-11-16 14:28:27 +03:00
"""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')
2015-11-12 14:43:54 +03:00
2015-10-11 15:34:21 +03:00
# Backward compatibility for versions < 0.11.*
AbstractCatalog = DeclarativeCatalog
def override(catalog):
2015-11-20 19:52:19 +03:00
""":py:class:`DeclarativeCatalog` overriding decorator.
:param catalog: Catalog that should be overridden by decorated catalog.
2015-11-24 10:59:53 +03:00
:type catalog: :py:class:`DeclarativeCatalog` | :py:class:`DynamicCatalog`
:return: Declarative catalog's overriding decorator
2015-11-24 10:59:53 +03:00
:rtype: callable(:py:class:`DeclarativeCatalog`)
"""
def decorator(overriding_catalog):
"""Overriding decorator."""
catalog.override(overriding_catalog)
return overriding_catalog
return decorator