diff --git a/dependency_injector/catalogs.py b/dependency_injector/catalogs.py index e8c2dd17..7a704f7e 100644 --- a/dependency_injector/catalogs.py +++ b/dependency_injector/catalogs.py @@ -330,7 +330,7 @@ class DeclarativeCatalogMetaClass(type): @six.add_metaclass(DeclarativeCatalogMetaClass) class DeclarativeCatalog(object): - """Declarative catalog catalog of providers. + """Declarative catalog of providers. ``DeclarativeCatalog`` is a catalog of providers that could be defined in declarative manner. It should cover most of the cases when list of @@ -347,25 +347,27 @@ class DeclarativeCatalog(object): name = str() """Catalog's name. + By default it is catalog's module + class names. + :type: str """ cls_providers = dict() """Read-only dictionary of current catalog providers. - :type: dict[str, dependency_injector.Provider] + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] """ inherited_providers = dict() """Read-only dictionary of inherited providers. - :type: dict[str, dependency_injector.Provider] + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] """ providers = dict() """Read-only dictionary of all providers. - :type: dict[str, dependency_injector.Provider] + :type: dict[str, :py:class:`dependency_injector.providers.Provider`] """ overridden_by = tuple() @@ -384,8 +386,8 @@ class DeclarativeCatalog(object): last_overriding = None """Read-only reference to the last overriding catalog, if any. - :type: dependency_injector.DeclarativeCatalog | - dependency_injector.DynamicCatalog + :type: :py:class:`dependency_injector.catalogs.DeclarativeCatalog` | + :py:class:`dependency_injector.catalogs.DynamicCatalog` | None """ _catalog = DynamicCatalog @@ -396,8 +398,8 @@ class DeclarativeCatalog(object): def is_bundle_owner(cls, bundle): """Check if catalog is bundle owner. - :param bundle: Catalog's bundle - :type bundle: dependency_injector.CatalogBundle + :param bundle: Catalog's bundle instance + :type bundle: :py:class:`dependency_injector.catalogs.CatalogBundle` :rtype: bool """ @@ -408,9 +410,9 @@ class DeclarativeCatalog(object): """Return provider's name in catalog. :param provider: Provider instance - :type provider: dependency_injector.Provider + :type provider: :py:class:`dependency_injector.providers.Provider` - :raise: dependency_injector.UndefinedProviderError + :raise: :py:class:`dependency_injector.errors.UndefinedProviderError` :return: Provider's name :rtype: str @@ -422,7 +424,7 @@ class DeclarativeCatalog(object): """Check if provider is bound to the catalog. :param provider: Provider instance - :type provider: dependency_injector.Provider + :type provider: :py:class:`dependency_injector.providers.Provider` :rtype: bool """ @@ -433,7 +435,7 @@ class DeclarativeCatalog(object): """Return dict of providers, that are instance of provided type. :param provider_type: Provider type - :type provider_type: dependency_injector.Provider + :type provider: :py:class:`dependency_injector.providers.Provider` """ return cls._catalog.filter(provider_type) @@ -442,8 +444,9 @@ class DeclarativeCatalog(object): """Override current catalog providers by overriding catalog providers. :param overriding: Overriding catalog - :type overriding: dependency_injector.DeclarativeCatalog | - dependency_injector.DynamicCatalog + :type overriding: + :py:class:`dependency_injector.catalogs.DeclarativeCatalog` | + :py:class:`dependency_injector.catalogs.DynamicCatalog` :rtype: None """ @@ -472,13 +475,15 @@ class DeclarativeCatalog(object): :param name: Provider's name :type name: str - :raise: dependency_injector.UndefinedProviderError + :raise: :py:class:`dependency_injector.errors.UndefinedProviderError` :return: Provider with specified name - :rtype: dependency_injector.providers.Provider + :rtype: :py:class:`dependency_injector.providers.Provider` """ return cls._catalog.get_provider(name) + get = get_provider # Backward compatibility for versions < 0.11.* + @classmethod def bind_provider(cls, name, provider): """Bind provider to catalog with specified name. @@ -487,9 +492,9 @@ class DeclarativeCatalog(object): :type name: str :param provider: Provider instance - :type provider: dependency_injector.Provider + :type provider: :py:class:`dependency_injector.providers.Provider` - :raise: dependency_injector.Error + :raise: :py:class:`dependency_injector.errors.Error` :rtype: None """ @@ -501,9 +506,10 @@ class DeclarativeCatalog(object): :param providers: Dictionary of providers, where key is a name and value is a provider - :type providers: dict[str, dependency_injector.Provider] + :type providers: + dict[str, :py:class:`dependency_injector.providers.Provider`] - :raise: dependency_injector.Error + :raise: :py:class:`dependency_injector.errors.Error` :rtype: None """ @@ -521,6 +527,8 @@ class DeclarativeCatalog(object): """ return hasattr(cls, name) + has = has_provider # Backward compatibility for versions < 0.11.* + @classmethod def unbind_provider(cls, name): """Remove provider binding. @@ -532,8 +540,48 @@ class DeclarativeCatalog(object): """ delattr(cls, name) - get = get_provider # Backward compatibility for versions < 0.11.* - has = has_provider # Backward compatibility for versions < 0.11.* + @classmethod + def __getattr__(cls, 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` + """ + raise NotImplementedError('Implementated in metaclass') + + @classmethod + 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. + + :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): + """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') # Backward compatibility for versions < 0.11.* diff --git a/dependency_injector/injections.py b/dependency_injector/injections.py index c6e44b60..09132bfd 100644 --- a/dependency_injector/injections.py +++ b/dependency_injector/injections.py @@ -39,7 +39,7 @@ class Injection(object): return self.injectable -class NamedInjection(Injection): +class _NamedInjection(Injection): """Base class of named injections.""" __slots__ = ('name',) @@ -47,7 +47,7 @@ class NamedInjection(Injection): def __init__(self, name, injectable): """Initializer.""" self.name = name - super(NamedInjection, self).__init__(injectable) + super(_NamedInjection, self).__init__(injectable) class Arg(Injection): @@ -56,19 +56,19 @@ class Arg(Injection): __IS_ARG_INJECTION__ = True -class KwArg(NamedInjection): +class KwArg(_NamedInjection): """Keyword argument injection.""" __IS_KWARG_INJECTION__ = True -class Attribute(NamedInjection): +class Attribute(_NamedInjection): """Attribute injection.""" __IS_ATTRIBUTE_INJECTION__ = True -class Method(NamedInjection): +class Method(_NamedInjection): """Method injection.""" __IS_METHOD_INJECTION__ = True diff --git a/docs/api/catalogs.rst b/docs/api/catalogs.rst index ffabcac9..90c22739 100644 --- a/docs/api/catalogs.rst +++ b/docs/api/catalogs.rst @@ -2,6 +2,6 @@ -------------------------------- .. automodule:: dependency_injector.catalogs - :members: - :special-members: - :member-order: bysource + :members: + :member-order: bysource + :special-members: diff --git a/docs/api/errors.rst b/docs/api/errors.rst index 2018c7c5..c58cbf23 100644 --- a/docs/api/errors.rst +++ b/docs/api/errors.rst @@ -2,5 +2,5 @@ ------------------------------ .. automodule:: dependency_injector.errors - :members: - :member-order: bysource + :members: + :member-order: bysource diff --git a/docs/api/index.rst b/docs/api/index.rst index 3c9ca377..453c853d 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -1,12 +1,11 @@ -API -=== - +API Documentation +================= .. toctree:: :maxdepth: 2 - top_level providers + injections catalogs - errors utils + errors diff --git a/docs/api/injections.rst b/docs/api/injections.rst new file mode 100644 index 00000000..d7ef5949 --- /dev/null +++ b/docs/api/injections.rst @@ -0,0 +1,7 @@ +``dependency_injector.injections`` +---------------------------------- + +.. automodule:: dependency_injector.injections + :members: + :member-order: bysource + :inherited-members: diff --git a/docs/api/providers.rst b/docs/api/providers.rst index 3573364f..620960e9 100644 --- a/docs/api/providers.rst +++ b/docs/api/providers.rst @@ -1,8 +1,6 @@ ``dependency_injector.providers`` --------------------------------- -.. automodule:: dependency_injector.providers +.. automodule:: dependency_injector.providers :members: - :special-members: - :private-members: :member-order: bysource diff --git a/docs/api/top_level.rst b/docs/api/top_level.rst index e455f520..af0115e5 100644 --- a/docs/api/top_level.rst +++ b/docs/api/top_level.rst @@ -2,5 +2,3 @@ ----------------------- .. automodule:: dependency_injector - :members: - :special-members: diff --git a/docs/api/utils.rst b/docs/api/utils.rst index 38ea3b70..a999772e 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -3,3 +3,4 @@ .. automodule:: dependency_injector.utils :members: + :member-order: bysource diff --git a/docs/catalogs/declarative.rst b/docs/catalogs/declarative.rst index 58a7e681..321fceab 100644 --- a/docs/catalogs/declarative.rst +++ b/docs/catalogs/declarative.rst @@ -1,17 +1,27 @@ Declarative catalogs -------------------- -:py:class:`dependency_injector.catalogs.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). +.. module:: dependency_injector.catalogs + +: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). Declarative catalogs have to extend base declarative catalog class - :py:class:`dependency_injector.catalogs.DeclarativeCatalog`. -Providers have to be defined like catalog's class attributes. Every provider in -catalog has name. This name should follow ``some_provider`` convention, -that is standard naming convention for attribute names in Python. +Declarative catalog's providers have to be defined like catalog's class +attributes. Every provider in catalog has name. This name should follow +``some_provider`` convention, that is standard naming convention for +attribute names in Python. + +.. note:: + + Declarative catalogs have several features that could be useful + for some kind of operations on catalog's providers, please visit API + documentation for getting full list of features - + :py:class:`dependency_injector.catalogs.DeclarativeCatalog`. .. note:: @@ -31,16 +41,20 @@ Here is an simple example of declarative catalog with several factories: .. literalinclude:: ../../examples/catalogs/declarative.py :language: python -:py:class:`dependency_injector.catalogs.DeclarativeCatalog` has several -features that could be useful for some kind of operations on catalog's -providers (please visit API docs for getting full list of feautes - -:py:class:`dependency_injector.catalogs.DeclarativeCatalog`): +Example of declarative catalogs inheritance: -Example: - -.. image:: /images/catalogs/declarative_api.png +.. image:: /images/catalogs/declarative_inheritance.png :width: 100% :align: center -.. literalinclude:: ../../examples/catalogs/declarative_api.py +.. literalinclude:: ../../examples/catalogs/declarative_inheritance.py + :language: python + +Example of declarative catalog's provider injections: + +.. image:: /images/catalogs/declarative_injections.png + :width: 100% + :align: center + +.. literalinclude:: ../../examples/catalogs/declarative_injections.py :language: python diff --git a/docs/catalogs/dynamic.rst b/docs/catalogs/dynamic.rst index e10c951e..68d36218 100644 --- a/docs/catalogs/dynamic.rst +++ b/docs/catalogs/dynamic.rst @@ -1,2 +1,4 @@ Dynamic catalogs ---------------- + +.. module:: dependency_injector.catalogs diff --git a/docs/images/catalogs/bundles.png b/docs/images/catalogs/bundles.png deleted file mode 100644 index 29ff4e48..00000000 Binary files a/docs/images/catalogs/bundles.png and /dev/null differ diff --git a/docs/images/catalogs/declarative.png b/docs/images/catalogs/declarative.png index cbed0781..81d3740f 100644 Binary files a/docs/images/catalogs/declarative.png and b/docs/images/catalogs/declarative.png differ diff --git a/docs/images/catalogs/declarative_api.png b/docs/images/catalogs/declarative_api.png deleted file mode 100644 index bf81c5cc..00000000 Binary files a/docs/images/catalogs/declarative_api.png and /dev/null differ diff --git a/docs/images/catalogs/declarative_inheritance.png b/docs/images/catalogs/declarative_inheritance.png new file mode 100644 index 00000000..53dc40c1 Binary files /dev/null and b/docs/images/catalogs/declarative_inheritance.png differ diff --git a/docs/images/catalogs/declarative_injections.png b/docs/images/catalogs/declarative_injections.png new file mode 100644 index 00000000..2a487d32 Binary files /dev/null and b/docs/images/catalogs/declarative_injections.png differ diff --git a/docs/images/catalogs/operating_with_providers.png b/docs/images/catalogs/operating_with_providers.png deleted file mode 100644 index 759ce094..00000000 Binary files a/docs/images/catalogs/operating_with_providers.png and /dev/null differ diff --git a/examples/catalogs/declarative.py b/examples/catalogs/declarative.py index 3b4c1d09..c35c7d3a 100644 --- a/examples/catalogs/declarative.py +++ b/examples/catalogs/declarative.py @@ -1,4 +1,4 @@ -"""Declarative catalog example.""" +"""Declarative catalog simple example.""" from dependency_injector import catalogs from dependency_injector import providers diff --git a/examples/catalogs/declarative_api.py b/examples/catalogs/declarative_inheritance.py similarity index 95% rename from examples/catalogs/declarative_api.py rename to examples/catalogs/declarative_inheritance.py index 8e3b13b0..d73b71a7 100644 --- a/examples/catalogs/declarative_api.py +++ b/examples/catalogs/declarative_inheritance.py @@ -1,4 +1,4 @@ -"""Declarative catalog API example.""" +"""Declarative catalogs inheritance example.""" from dependency_injector import catalogs from dependency_injector import providers diff --git a/examples/catalogs/declarative_injections.py b/examples/catalogs/declarative_injections.py new file mode 100644 index 00000000..52c5855b --- /dev/null +++ b/examples/catalogs/declarative_injections.py @@ -0,0 +1,50 @@ +"""Declarative catalog's provider injections example.""" + +import sqlite3 + +from dependency_injector import catalogs +from dependency_injector import providers + + +class UsersService(object): + """Users service, that has dependency on database.""" + + def __init__(self, db): + """Initializer.""" + self.db = db + + +class AuthService(object): + """Auth service, that has dependencies on users service and database.""" + + def __init__(self, db, users_service): + """Initializer.""" + self.db = db + self.users_service = users_service + + +class Services(catalogs.DeclarativeCatalog): + """Catalog of service providers.""" + + database = providers.Singleton(sqlite3.connect, ':memory:') + """:type: providers.Provider -> sqlite3.Connection""" + + users = providers.Factory(UsersService, + db=database) + """:type: providers.Provider -> UsersService""" + + auth = providers.Factory(AuthService, + db=database, + users_service=users) + """:type: providers.Provider -> AuthService""" + + +# Retrieving catalog providers: +users_service = Services.users() +auth_service = Services.auth() + +# Making some asserts: +assert users_service.db is auth_service.db is Services.database() +assert isinstance(auth_service.users_service, UsersService) +assert users_service is not Services.users() +assert auth_service is not Services.auth()