Add DeclarativeCatalog API docs

This commit is contained in:
Roman Mogilatov 2015-11-13 23:43:36 +02:00
parent 4683ada2ce
commit da4976e3c7
9 changed files with 258 additions and 94 deletions

View File

@ -86,6 +86,10 @@ class DynamicCatalog(object):
self.overridden_by = tuple() self.overridden_by = tuple()
self.Bundle = CatalogBundle.sub_cls_factory(self) self.Bundle = CatalogBundle.sub_cls_factory(self)
"""Catalog's bundle class.
:type: :py:class:`dependency_injector.catalogs.CatalogBundle`
"""
self.bind_providers(providers) self.bind_providers(providers)
super(DynamicCatalog, self).__init__() super(DynamicCatalog, self).__init__()
@ -233,44 +237,50 @@ 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.""" """Return catalog's name."""
return cls.catalog.name return cls._catalog.name
@property @property
def providers(cls): def providers(cls):
"""Return dict of catalog's providers.""" """Return dict of catalog's providers."""
return cls.catalog.providers return cls._catalog.providers
@property @property
def overridden_by(cls): def overridden_by(cls):
"""Return tuple of overriding catalogs.""" """Return tuple of overriding catalogs."""
return cls.catalog.overridden_by return cls._catalog.overridden_by
@property @property
def is_overridden(cls): def is_overridden(cls):
"""Check if catalog is overridden by another catalog.""" """Check if catalog is overridden by another catalog."""
return cls.catalog.is_overridden return cls._catalog.is_overridden
@property @property
def last_overriding(cls): def last_overriding(cls):
"""Return last overriding catalog.""" """Return last overriding catalog."""
return cls.catalog.last_overriding 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: dependency_injector.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))
@ -279,9 +289,17 @@ class DeclarativeCatalogMetaClass(type):
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 correctly.
:param name: Attribute's name
:type name: str
:param value: Attribute's value
:type value: dependency_injector.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):
@ -289,13 +307,21 @@ class DeclarativeCatalogMetaClass(type):
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 correctly.
: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)))
@ -306,115 +332,204 @@ class DeclarativeCatalogMetaClass(type):
class DeclarativeCatalog(object): class DeclarativeCatalog(object):
"""Declarative catalog catalog of providers. """Declarative catalog catalog of providers.
:type name: str ``DeclarativeCatalog`` is a catalog of providers that could be defined in
:param name: Catalog's name declarative manner. It should cover most of the cases when list of
providers that would be included in catalog is deterministic (catalog will
:type catalog: DynamicCatalog not change its structure in runtime).
:param catalog: Instance of dynamic catalog
:type Bundle: CatalogBundle
:param Bundle: Catalog's bundle class
:type providers: dict[str, dependency_injector.Provider]
:param providers: Dict of all catalog providers, including inherited from
parent catalogs
:type cls_providers: dict[str, dependency_injector.Provider]
:param cls_providers: Dict of current catalog providers
:type inherited_providers: dict[str, dependency_injector.Provider]
:param inherited_providers: Dict of providers, that are inherited from
parent catalogs
:type overridden_by: tuple[DeclarativeCatalog]
:param overridden_by: Tuple of overriding catalogs
:type is_overridden: bool
:param is_overridden: Read-only, evaluated in runtime, property that is
set to True if catalog is overridden
:type last_overriding: DeclarativeCatalog | None
:param last_overriding: Reference to the last overriding catalog, if any
""" """
Bundle = CatalogBundle Bundle = CatalogBundle
"""Catalog's bundle class.
:type: :py:class:`dependency_injector.catalogs.CatalogBundle`
"""
name = str() name = str()
"""Catalog's name.
:type: str
"""
cls_providers = dict() cls_providers = dict()
"""Read-only dictionary of current catalog providers.
:type: dict[str, dependency_injector.Provider]
"""
inherited_providers = dict() inherited_providers = dict()
"""Read-only dictionary of inherited providers.
:type: dict[str, dependency_injector.Provider]
"""
providers = dict() providers = dict()
"""Read-only dictionary of all providers.
:type: dict[str, dependency_injector.Provider]
"""
overridden_by = tuple() overridden_by = tuple()
is_overridden = bool """Tuple of overriding catalogs.
last_overriding = None
catalog = DynamicCatalog :type: tuple[:py:class:`dependency_injector.catalogs.DeclarativeCatalog` |
:py:class:`dependency_injector.catalogs.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: dependency_injector.DeclarativeCatalog |
dependency_injector.DynamicCatalog
"""
_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
:type bundle: dependency_injector.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: dependency_injector.Provider
:raise: dependency_injector.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: dependency_injector.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 dict of providers, that are instance of provided type.
return cls.catalog.filter(provider_type)
:param provider_type: Provider type
:type provider_type: dependency_injector.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: dependency_injector.DeclarativeCatalog |
dependency_injector.DynamicCatalog
:rtype: None
""" """
return cls.catalog.override(overriding) 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: dependency_injector.UndefinedProviderError
:return: Provider with specified name
:rtype: dependency_injector.providers.Provider
"""
return cls._catalog.get_provider(name)
@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: dependency_injector.Provider
:raise: dependency_injector.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, dependency_injector.Provider]
:raise: dependency_injector.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)
@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.* get = get_provider # Backward compatibility for versions < 0.11.*

62
docs/api/catalogs.rst Normal file
View File

@ -0,0 +1,62 @@
dependency_injector.catalogs
----------------------------
.. automodule:: dependency_injector.catalogs
Declarative catalog
-------------------
.. autoclass:: DeclarativeCatalog
:member-order: bysource
:members:
.. classmethod:: __getattr__(name)
Return provider with specified name or raise en error.
:param name: Attribute's name
:type name: str
:raise: dependency_injector.UndefinedProviderError
.. classmethod:: __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 correctly.
:param name: Attribute's name
:type name: str
:param value: Attribute's value
:type value: dependency_injector.Provider | object
:rtype: None
.. classmethod:: __delattr__(cls, name)
Handle deleting of catalog attibute.
Deleting of attributes works as usual, but if value of attribute is
provider, this provider will be unbound from catalog correctly.
:param name: Attribute's name
:type name: str
:rtype: None
.. classmethod:: __repr__(cls, name)
Return string representation of the catalog.
:rtype: str
Dynamic catalog
---------------
.. autoclass:: DynamicCatalog
:member-order: bysource
:members:
:special-members:

9
docs/api/index.rst Normal file
View File

@ -0,0 +1,9 @@
API
===
.. toctree::
:maxdepth: 1
providers
catalogs

3
docs/api/providers.rst Normal file
View File

@ -0,0 +1,3 @@
dependency_injector.providers
-----------------------------

View File

@ -6,9 +6,6 @@ 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 that would be included in catalog is deterministic (catalog will not change
its structure in runtime). its structure in runtime).
Definition of declarative catalogs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Declarative catalogs have to extend base declarative catalog class - Declarative catalogs have to extend base declarative catalog class -
``di.DeclarativeCatalog``. ``di.DeclarativeCatalog``.
@ -33,27 +30,10 @@ Here is an simple example of declarative catalog with several factories:
.. literalinclude:: ../../examples/catalogs/declarative.py .. literalinclude:: ../../examples/catalogs/declarative.py
:language: python :language: python
Declarative catalogs API
~~~~~~~~~~~~~~~~~~~~~~~~
``di.DeclarativeCatalog`` has several features that could be useful for some ``di.DeclarativeCatalog`` has several features that could be useful for some
kind of operations on catalog's providers: kind of operations on catalog's providers (please visit API docs for
getting full list of feautes -
- ``di.DeclarativeCatalog.providers`` is read-only attribute that contains :py:class:`dependency_injector.catalogs.DeclarativeCatalog`):
``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: Example:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 165 KiB

View File

@ -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

View File

@ -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