diff --git a/docs/catalogs/index.rst b/docs/catalogs/index.rst index 637d8352..e1888cab 100644 --- a/docs/catalogs/index.rst +++ b/docs/catalogs/index.rst @@ -24,4 +24,5 @@ Catalogs module API docs - :py:mod:`dependency_injector.catalogs`. declarative dynamic bundles + specialization overriding diff --git a/docs/catalogs/specialization.rst b/docs/catalogs/specialization.rst new file mode 100644 index 00000000..9e52e4d9 --- /dev/null +++ b/docs/catalogs/specialization.rst @@ -0,0 +1,41 @@ +Specialization of catalogs +-------------------------- + +.. currentmodule:: dependency_injector.catalogs + +:py:class:`DeclarativeCatalog` and :py:class:`DynamicCatalog` could be +specialized for any kind of needs via declaring its subclasses. + +One of such `builtin` features is a limitation to +:py:class:`DeclarativeCatalog` (and :py:class:`DynamicCatalog`) provider type. + +Next example shows usage of this feature with :py:class:`DeclarativeCatalog` +in couple with feature of :py:class:`dependency_injector.providers.Factory` +for limitation of its provided type: + + +Listing of `services.py`: + +.. literalinclude:: ../../examples/catalogs/declarative_provider_type/services.py + :language: python + +Listing of `catalog.py`: + +.. literalinclude:: ../../examples/catalogs/declarative_provider_type/catalog.py + :language: python + +Limitation to provider type could be used with :py:class:`DynamicCatalog` +as well. + +Next example does the same that previous one, but use +:py:class:`DynamicCatalog` instead of :py:class:`DeclarativeCatalog`: + +Listing of `services.py`: + +.. literalinclude:: ../../examples/catalogs/dynamic_provider_type/services.py + :language: python + +Listing of `catalog.py`: + +.. literalinclude:: ../../examples/catalogs/dynamic_provider_type/catalog.py + :language: python diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 9b05a400..524d2ad4 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -11,6 +11,8 @@ Development version ------------------- - Add possibility to specialize ``Factory`` provided type. - Add possibility to specialize ``Singleton`` provided type. +- Add possibility to specialize ``DeclarativeCatalog`` provider type. +- Add possibility to specialize ``DynamicCatalog`` provider type. - Make some refactorings for providers. 1.11.2 diff --git a/examples/catalogs/declarative_provider_type/catalog.py b/examples/catalogs/declarative_provider_type/catalog.py new file mode 100644 index 00000000..d7ed6b9c --- /dev/null +++ b/examples/catalogs/declarative_provider_type/catalog.py @@ -0,0 +1,75 @@ +"""Specialized declarative catalog example.""" + +import services + +from dependency_injector import providers +from dependency_injector import errors + + +class UsersService(services.Base): + """Users service.""" + + def __init__(self, config): + """Initializer.""" + self.config = config + super(UsersService, self).__init__() + + +class AuthService(services.Base): + """Auth service.""" + + def __init__(self, config, users_service): + """Initializer.""" + self.config = config + self.users_service = users_service + super(AuthService, self).__init__() + + +class Services(services.Catalog): + """Services catalog.""" + + users = services.Provider(UsersService, + config={'option1': '111', + 'option2': '222'}) + """:type: services.Provider -> UsersService""" + + auth = services.Provider(AuthService, + config={'option3': '333', + 'option4': '444'}, + users_service=users) + """:type: services.Provider -> AuthService""" + + +# Creating users & auth services: +users_service = Services.users() +auth_service = Services.auth() + +# Making some asserts: +assert users_service.config == {'option1': '111', + 'option2': '222'} +assert auth_service.config == {'option3': '333', + 'option4': '444'} +assert isinstance(auth_service.users_service, UsersService) + +# Trying to declare services catalog with other provider type: +try: + class Services1(services.Catalog): + """Services catalog.""" + + users = providers.Factory(UsersService) +except errors.Error as exception: + print exception + # <__main__.Services1()> can contain only + # instances + +# Trying to declare services catalog with correct provider by invalid provided +# type: +try: + class Services2(services.Catalog): + """Services catalog.""" + + users = services.Provider(object) +except errors.Error as exception: + print exception + # can provide only + # instances diff --git a/examples/catalogs/declarative_provider_type/services.py b/examples/catalogs/declarative_provider_type/services.py new file mode 100644 index 00000000..7a1f0432 --- /dev/null +++ b/examples/catalogs/declarative_provider_type/services.py @@ -0,0 +1,26 @@ +"""Base classes for services.""" + +from dependency_injector import catalogs +from dependency_injector import providers + + +class Base(object): + """Base service class.""" + + +class Provider(providers.Factory): + """Service provider. + + Can provide :py:class:`Base` only. + """ + + provided_type = Base + + +class Catalog(catalogs.DeclarativeCatalog): + """Base catalog of services. + + Can include :py:class:`Provider`'s only. + """ + + provider_type = Provider diff --git a/examples/catalogs/dynamic_provider_type/catalog.py b/examples/catalogs/dynamic_provider_type/catalog.py new file mode 100644 index 00000000..7578c492 --- /dev/null +++ b/examples/catalogs/dynamic_provider_type/catalog.py @@ -0,0 +1,63 @@ +"""Specialized dynamic catalog example.""" + +import services + +from dependency_injector import providers +from dependency_injector import errors + + +class UsersService(services.Base): + """Users service.""" + + def __init__(self, config): + """Initializer.""" + self.config = config + super(UsersService, self).__init__() + + +class AuthService(services.Base): + """Auth service.""" + + def __init__(self, config, users_service): + """Initializer.""" + self.config = config + self.users_service = users_service + super(AuthService, self).__init__() + + +services_catalog = services.Catalog() +services_catalog.users = services.Provider(UsersService, + config={'option1': '111', + 'option2': '222'}) +services_catalog.auth = services.Provider(AuthService, + config={'option3': '333', + 'option4': '444'}, + users_service=services_catalog.users) + +# Creating users & auth services: +users_service = services_catalog.users() +auth_service = services_catalog.auth() + +# Making some asserts: +assert users_service.config == {'option1': '111', + 'option2': '222'} +assert auth_service.config == {'option3': '333', + 'option4': '444'} +assert isinstance(auth_service.users_service, UsersService) + +# Trying to declare services catalog with other provider type: +try: + services_catalog.users = providers.Factory(UsersService) +except errors.Error as exception: + print exception + # can contain only + # instances + +# Trying to declare services catalog with correct provider by invalid provided +# type: +try: + services_catalog.users = services.Provider(object) +except errors.Error as exception: + print exception + # can provide only + # instances diff --git a/examples/catalogs/dynamic_provider_type/services.py b/examples/catalogs/dynamic_provider_type/services.py new file mode 100644 index 00000000..853ea1b4 --- /dev/null +++ b/examples/catalogs/dynamic_provider_type/services.py @@ -0,0 +1,26 @@ +"""Base classes for services.""" + +from dependency_injector import catalogs +from dependency_injector import providers + + +class Base(object): + """Base service class.""" + + +class Provider(providers.Factory): + """Service provider. + + Can provide :py:class:`Base` only. + """ + + provided_type = Base + + +class Catalog(catalogs.DynamicCatalog): + """Base catalog of services. + + Can include :py:class:`Provider`'s only. + """ + + provider_type = Provider