Update catalog bundle and dynamic catalog api docs

This commit is contained in:
Roman Mogilatov 2015-11-16 19:50:16 +02:00
parent 9e4138da96
commit 801716fd92

View File

@ -16,14 +16,28 @@ class CatalogBundle(object):
"""Bundle of catalog providers.""" """Bundle of catalog providers."""
catalog = None catalog = None
""":type: DeclarativeCatalog""" """Bundle's catalog.
:type: :py:class:`dependency_injector.catalogs.DeclarativeCatalog` |
:py:class:`dependency_injector.catalogs.DynamicCatalog`
"""
__IS_CATALOG_BUNDLE__ = True __IS_CATALOG_BUNDLE__ = True
__slots__ = ('providers', '__dict__') __slots__ = ('providers', '__dict__')
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
@ -32,15 +46,25 @@ class CatalogBundle(object):
@classmethod @classmethod
def sub_cls_factory(cls, catalog): def sub_cls_factory(cls, catalog):
"""Create bundle class for catalog. """Create bundle subclass for catalog.
:rtype: CatalogBundle :return: Subclass of
:return: Subclass of CatalogBundle :py:class:`dependency_injector.catalogs.CatalogBundle`
:rtype: :py:class:`dependency_injector.catalogs.CatalogBundle`
""" """
return type('BundleSubclass', (cls,), dict(catalog=catalog)) 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:class:`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 +72,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:class:`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 +107,7 @@ 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."""
__IS_CATALOG__ = True __IS_CATALOG__ = True
__slots__ = ('name', 'providers', 'provider_names', 'overridden_by', __slots__ = ('name', 'providers', 'provider_names', 'overridden_by',
@ -77,52 +116,107 @@ 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.name = '.'.join((self.__class__.__module__,
self.__class__.__name__))
self.providers = dict()
self.provider_names = dict()
self.overridden_by = tuple()
self.Bundle = CatalogBundle.sub_cls_factory(self) self.Bundle = CatalogBundle.sub_cls_factory(self)
"""Catalog's bundle class. """Catalog's bundle class.
:type: :py:class:`dependency_injector.catalogs.CatalogBundle` :type: :py:class:`dependency_injector.catalogs.CatalogBundle`
""" """
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
"""
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:`dependency_injector.catalogs.DeclarativeCatalog` |
:py:class:`dependency_injector.catalogs.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:`dependency_injector.catalogs.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:class:`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 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.
:type: :py:class:`dependency_injector.catalogs.DeclarativeCatalog` |
:py:class:`dependency_injector.catalogs.DynamicCatalog`
"""
try: try:
return self.overridden_by[-1] return self.overridden_by[-1]
except (TypeError, IndexError): except (TypeError, IndexError):
@ -131,14 +225,22 @@ class DynamicCatalog(object):
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:`dependency_injector.catalogs.DeclarativeCatalog` |
:py:class:`dependency_injector.catalogs.DynamicCatalog`
:rtype: None
""" """
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]
@ -146,13 +248,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:class:`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:
@ -160,7 +274,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:class:`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:
@ -174,29 +299,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:class:`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:class:`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)
@ -206,12 +368,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)))
@ -278,7 +448,7 @@ class DeclarativeCatalogMetaClass(type):
@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.
:rtype: bool :rtype: bool
""" """
@ -453,10 +623,12 @@ class DeclarativeCatalog(object):
@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.
:param provider_type: Provider type :param provider_type: Provider type
:type provider: :py:class:`dependency_injector.providers.Provider` :type provider_type: :py:class:`dependency_injector.providers.Provider`
:rtype: dict[str, :py:class:`dependency_injector.providers.Provider`]
""" """
return cls._catalog.filter(provider_type) return cls._catalog.filter(provider_type)