diff --git a/dependency_injector/providers.py b/dependency_injector/providers.py index 7b89a192..5f0be721 100644 --- a/dependency_injector/providers.py +++ b/dependency_injector/providers.py @@ -293,7 +293,18 @@ class Singleton(Provider): __slots__ = ('instance', 'factory') def __init__(self, provides, *args, **kwargs): - """Initializer.""" + """Initializer. + + :param provides: Class or other callable that provides object + for creation. + :type provides: type | callable + + :param args: Tuple of injections. + :type args: tuple + + :param kwargs: Dictionary of injections. + :type kwargs: dict + """ self.instance = None """Read-only reference to singleton's instance. @@ -492,33 +503,78 @@ class Value(StaticProvider): class Callable(Provider): - """Callable provider. + """:py:class:`Callable` provider calls wrapped callable on every call. - Callable provider provides callable that is called on every provider call - with some predefined dependency injections. + :py:class:`Callable` provider provides callable that is called on every + provider call with some predefined dependency injections. + + :py:class:`Callable` syntax of passing injections is the same like + :py:class:`Factory` one: + + .. code-block:: python + + some_function = Callable(some_function, 'arg1', 'arg2', arg3=3, arg4=4) + result = some_function() """ __slots__ = ('callback', 'args', 'kwargs') def __init__(self, callback, *args, **kwargs): - """Initializer.""" + """Initializer. + + :param callback: wrapped callable. + :type callback: callable + + :param args: Tuple of injections. + :type args: tuple + + :param kwargs: Dictionary of injections. + :type kwargs: dict + """ if not callable(callback): raise Error('Callable expected, got {0}'.format(str(callback))) self.callback = callback - self.args = _parse_args_injections(args) - self.kwargs = _parse_kwargs_injections(args, kwargs) - super(Callable, self).__init__() + """Wrapped callable. - def _provide(self, *args, **kwargs): - """Return provided instance.""" - return self.callback(*_get_injectable_args(args, self.args), - **_get_injectable_kwargs(kwargs, self.kwargs)) + :type: callable + """ + + self.args = _parse_args_injections(args) + """Tuple of positional argument injections. + + :type: tuple[:py:class:`dependency_injector.injections.Arg`] + """ + + self.kwargs = _parse_kwargs_injections(args, kwargs) + """Tuple of keyword argument injections. + + :type: tuple[:py:class:`dependency_injector.injections.KwArg`] + """ + + super(Callable, self).__init__() @property def injections(self): - """Return tuple of all injections.""" + """Read-only tuple of all injections. + + :rtype: tuple[:py:class:`dependency_injector.injections.Injection`] + """ return self.args + self.kwargs + def _provide(self, *args, **kwargs): + """Return provided instance. + + :param args: tuple of context positional arguments + :type args: tuple[object] + + :param kwargs: dictionary of context keyword arguments + :type kwargs: dict[str, object] + + :rtype: object + """ + return self.callback(*_get_injectable_args(args, self.args), + **_get_injectable_kwargs(kwargs, self.kwargs)) + class Config(Provider): """Config provider. diff --git a/docs/images/providers/callable.png b/docs/images/providers/callable.png index 4e3c20a2..76271ad3 100644 Binary files a/docs/images/providers/callable.png and b/docs/images/providers/callable.png differ diff --git a/docs/providers/callable.rst b/docs/providers/callable.rst index 0fcf0944..624c5f0d 100644 --- a/docs/providers/callable.rst +++ b/docs/providers/callable.rst @@ -1,40 +1,43 @@ Callable providers ------------------ -``di.Callable`` provider is a provider that wraps particular callable with +.. module:: dependency_injector.providers + +:py:class:`Callable` provider is a provider that wraps particular callable with some injections. Every call of this provider returns result of call of initial callable. Callable providers and injections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``di.Callable`` takes a various number of positional and keyword arguments -that are used as decorated callable injections. Every time, when -``di.Callable`` is called, positional and keyword argument injections would be -passed as an callable arguments. +:py:class:`Callable` takes a various number of positional and keyword +arguments that are used as decorated callable injections. Every time, when +:py:class:`Callable` is called, positional and keyword argument injections +would be passed as an callable arguments. Such behaviour is very similar to the standard Python ``functools.partial`` object, except of one thing: all injectable values are provided -*"as is"*, except of providers (subclasses of ``di.Provider``). Providers +*"as is"*, except of providers (subclasses of :py:class:`Provider`). Providers will be called every time, when injection needs to be done. For example, -if injectable value of injection is a ``di.Factory``, it will provide new one -instance (as a result of its call) every time, when injection needs to be done. +if injectable value of injection is a :py:class:`Factory`, it will provide +new one instance (as a result of its call) every time, when injection needs +to be done. -``di.Callable`` behaviour with context positional and keyword arguments is -very like a standard Python ``functools.partial``: +:py:class:`Callable` behaviour with context positional and keyword arguments +is very like a standard Python ``functools.partial``: -- Positional context arguments will be appended after ``di.Callable`` +- Positional context arguments will be appended after :py:class:`Callable` positional injections. -- Keyword context arguments have priority on ``di.Callable`` keyword +- Keyword context arguments have priority on :py:class:`Callable` keyword injections and will be merged over them. -Example that shows usage of ``di.Callable`` with positional argument +Example that shows usage of :py:class:`Callable` with positional argument injections: .. literalinclude:: ../../examples/providers/callable_args.py :language: python -Next one example shows usage of ``di.Callable`` with keyword argument +Next one example shows usage of :py:class:`Callable` with keyword argument injections: .. image:: /images/providers/callable.png @@ -47,13 +50,13 @@ injections: Callable providers delegation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``di.Callable`` provider could be delegated to any other provider via any kind -of injection. Delegation of ``di.Callable`` providers is the same as -``di.Factory`` and ``di.Singleton`` providers delegation, please follow -*Factory providers delegation* section for example. +:py:class:`Callable` provider could be delegated to any other provider via any +kind of injection. Delegation of :py:class:`Callable` providers is the same as +:py:class:`Factory` and :py:class:`Singleton` providers delegation, please +follow *Factory providers delegation* section for example. -``di.Callable`` delegate could be created obviously using -``di.Delegate(di.Callable())`` or by calling ``di.Callable.delegate()`` method. +:py:class:`Callable` delegate could be created obviously using +``Delegate(Callable(...))`` or by calling ``Callable(...).delegate()`` method. Example: diff --git a/examples/providers/callable_args.py b/examples/providers/callable_args.py index 3be82b6f..9a854d5b 100644 --- a/examples/providers/callable_args.py +++ b/examples/providers/callable_args.py @@ -1,11 +1,11 @@ -"""`di.Callable` providers with positional arguments example.""" +"""`Callable` providers with positional arguments example.""" -import dependency_injector as di +from dependency_injector import providers # Creating even and odd filter providers: -even_filter = di.Callable(filter, lambda x: x % 2 == 0) -odd_filter = di.Callable(filter, lambda x: x % 2 != 0) +even_filter = providers.Callable(filter, lambda x: x % 2 == 0) +odd_filter = providers.Callable(filter, lambda x: x % 2 != 0) # Creating even and odd ranges using xrange() and filter providers: even_range = even_filter(xrange(1, 10)) diff --git a/examples/providers/callable_delegation.py b/examples/providers/callable_delegation.py index a4985982..4a59e004 100644 --- a/examples/providers/callable_delegation.py +++ b/examples/providers/callable_delegation.py @@ -1,13 +1,14 @@ -"""`di.Callable` providers delegation example.""" +"""`Callable` providers delegation example.""" import sys -import dependency_injector as di + +from dependency_injector import providers # Creating some callable provider and few delegates of it: -callable_provider = di.Callable(sys.exit) +callable_provider = providers.Callable(sys.exit) callable_provider_delegate1 = callable_provider.delegate() -callable_provider_delegate2 = di.Delegate(callable_provider) +callable_provider_delegate2 = providers.Delegate(callable_provider) # Making some asserts: assert callable_provider_delegate1() is callable_provider diff --git a/examples/providers/callable_kwargs.py b/examples/providers/callable_kwargs.py index 7119667d..0880940a 100644 --- a/examples/providers/callable_kwargs.py +++ b/examples/providers/callable_kwargs.py @@ -1,14 +1,16 @@ -"""`di.Callable` providers with keyword arguments example.""" +"""`Callable` providers with keyword arguments example.""" import passlib.hash -import dependency_injector as di + +from dependency_injector import providers + # Password hasher and verifier providers (hash function could be changed # anytime (for example, to sha512) without any changes in client's code): -password_hasher = di.Callable(passlib.hash.sha256_crypt.encrypt, - salt_size=16, - rounds=10000) -password_verifier = di.Callable(passlib.hash.sha256_crypt.verify) +password_hasher = providers.Callable(passlib.hash.sha256_crypt.encrypt, + salt_size=16, + rounds=10000) +password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify) # Making some asserts: hashed_password = password_hasher('super secret')