Update catalog bundles docs

This commit is contained in:
Roman Mogilatov 2015-11-20 13:46:57 +02:00
parent b29387abdd
commit e55f6ed212
7 changed files with 93 additions and 55 deletions

View File

@ -13,7 +13,23 @@ 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
"""Bundle's catalog. """Bundle's catalog.
@ -25,6 +41,16 @@ class CatalogBundle(object):
__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:`dependency_injector.catalogs.CatalogBundle`
:rtype: :py:class:`dependency_injector.catalogs.CatalogBundle`
"""
return type('BundleSubclass', (cls,), dict(catalog=catalog))
def __init__(self, *providers): def __init__(self, *providers):
"""Initializer. """Initializer.
@ -44,16 +70,6 @@ class CatalogBundle(object):
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 subclass for catalog.
:return: Subclass of
:py:class:`dependency_injector.catalogs.CatalogBundle`
:rtype: :py:class:`dependency_injector.catalogs.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.
@ -523,10 +539,10 @@ class DeclarativeCatalogMetaClass(type):
class DeclarativeCatalog(object): class DeclarativeCatalog(object):
"""Declarative catalog of providers. """Declarative catalog of providers.
``DeclarativeCatalog`` is a catalog of providers that could be defined in :py:class:`DeclarativeCatalog` is a catalog of providers that could be
declarative manner. It should cover most of the cases when list of defined in declarative manner. It should cover most of the cases when list
providers that would be included in catalog is deterministic (catalog will of providers that would be included in catalog is deterministic (catalog
not change its structure in runtime). will not change its structure in runtime).
""" """
Bundle = CatalogBundle Bundle = CatalogBundle

View File

@ -1,23 +1,43 @@
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

View File

@ -4,9 +4,9 @@ Declarative catalogs
.. module:: dependency_injector.catalogs .. module:: dependency_injector.catalogs
:py:class:`DeclarativeCatalog` is a catalog of providers that could be :py:class:`DeclarativeCatalog` is a catalog of providers that could be
defined in declarative manner. It should cover most of the cases when defined in declarative manner. It should cover most of the cases when list
list of providers that would be included in catalog is deterministic of providers that would be included in catalog is deterministic (catalog
(catalog will not change its structure in runtime). will not change its structure in runtime).
Declarative catalogs have to extend base declarative catalog class - Declarative catalogs have to extend base declarative catalog class -
:py:class:`dependency_injector.catalogs.DeclarativeCatalog`. :py:class:`dependency_injector.catalogs.DeclarativeCatalog`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

View File

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

View File

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

View File

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