Update factory provider API docs

This commit is contained in:
Roman Mogilatov 2015-11-23 13:48:07 +02:00
parent 7eed1cf880
commit fb6deaec96
2 changed files with 162 additions and 31 deletions

View File

@ -16,7 +16,23 @@ from .errors import Error
class Provider(object):
"""Base provider class."""
"""Base provider class.
:py:class:`Provider` is callable (implements ``__call__`` method). Every
call to provider object returns provided result, according to the providing
strategy of particular provider. This ``callable`` functionality is a
regular part of providers API and it should be the same for all provider's
subclasses.
:py:class:`Provider` implements provider overriding logic that should be
also common for all providers.
Implementation of particular providing strategy should be done in
:py:meth:`Provider._provide` of :py:class:`Provider` subclass. Current
method is called every time when not overridden provider is called.
All providers should extend this class.
"""
__IS_PROVIDER__ = True
__slots__ = ('overridden_by',)
@ -26,7 +42,15 @@ class Provider(object):
self.overridden_by = None
def __call__(self, *args, **kwargs):
"""Return provided instance."""
"""Return provided instance.
Implementation of current method adds ``callable`` functionality for
providers API and it should be common for all provider's subclasses.
Also this method implements provider overriding logic that is also
common for all providers. Implementation of particular providing
strategy should be done in :py:meth:`Provider._provide` of
:py:class:`Provider` subclass.
"""
if self.overridden_by:
return self.last_overriding(*args, **kwargs)
return self._provide(*args, **kwargs)
@ -40,12 +64,33 @@ class Provider(object):
"""
raise NotImplementedError()
def delegate(self):
"""Return provider's delegate."""
return Delegate(self)
@property
def is_overridden(self):
"""Read-only property that is set to ``True`` if provider is overridden.
:rtype: bool
"""
return bool(self.overridden_by)
@property
def last_overriding(self):
"""Read-only reference to the last overriding provider, if any.
:type: :py:class:`Provider`
"""
try:
return self.overridden_by[-1]
except (TypeError, IndexError):
raise Error('Provider {0} is not overridden'.format(str(self)))
def override(self, provider):
"""Override provider with another provider."""
"""Override provider with another provider.
:param provider: overriding provider
:type provider: :py:class:`Provider`
:raise: :py:exc:`dependency_injector.errors.Error`
"""
if provider is self:
raise Error('Provider {0} could not be overridden '
'with itself'.format(self))
@ -54,29 +99,29 @@ class Provider(object):
else:
self.overridden_by += (ensure_is_provider(provider),)
@property
def is_overridden(self):
"""Check if provider is overridden by another provider."""
return bool(self.overridden_by)
@property
def last_overriding(self):
"""Return last overriding provider."""
try:
return self.overridden_by[-1]
except (TypeError, IndexError):
raise Error('Provider {0} is not overridden'.format(str(self)))
def reset_last_overriding(self):
"""Reset last overriding provider."""
"""Reset last overriding provider.
:rtype: None
"""
if not self.is_overridden:
raise Error('Provider {0} is not overridden'.format(str(self)))
self.overridden_by = self.overridden_by[:-1]
def reset_override(self):
"""Reset all overriding providers."""
"""Reset all overriding providers.
:rtype: None
"""
self.overridden_by = None
def delegate(self):
"""Return provider's delegate.
:rtype: :py:class:`Delegate`
"""
return Delegate(self)
class Delegate(Provider):
"""Provider's delegate."""
@ -92,36 +137,126 @@ class Delegate(Provider):
super(Delegate, self).__init__()
def _provide(self, *args, **kwargs):
"""Return provided instance."""
"""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.delegated
class Factory(Provider):
"""Factory provider.
""":py:class:`Factory` provider creates new instance on every call.
Factory provider creates new instance of specified class on every call.
:py:class:`Factory` supports different syntaxes of passing injections:
+ simplified one syntax for passing positional and keyword argument
injections only:
.. code-block:: python
factory = Factory(SomeClass, 'arg1', 'arg2', arg3=3, arg4=4)
- extended (full) one syntax for passing any type of injections:
.. code-block:: python
factory = Factory(SomeClass,
injections.Arg(1),
injections.Arg(2),
injections.KwArg('some_arg', 3),
injections.KwArg('other_arg', 4),
injections.Attribute('some_attribute', 5))
Retrieving of provided instance can be performed via calling
:py:class:`Factory` object:
.. code-block:: python
factory = Factory(SomeClass,
some_arg1=1,
some_arg2=2)
some_object = factory()
"""
__slots__ = ('provides', 'args', 'kwargs', 'attributes', 'methods')
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
"""
if not callable(provides):
raise Error('Factory provider expects to get callable, ' +
'got {0} instead'.format(str(provides)))
self.provides = provides
"""Class or other callable that provides object for creation.
:type: 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`]
"""
self.attributes = tuple(injection
for injection in args
if is_attribute_injection(injection))
"""Tuple of attribute injections.
:type: tuple[:py:class:`dependency_injector.injections.Attribute`]
"""
self.methods = tuple(injection
for injection in args
if is_method_injection(injection))
"""Tuple of method injections.
:type: tuple[:py:class:`dependency_injector.injections.Method`]
"""
super(Factory, self).__init__()
@property
def injections(self):
"""Read-only tuple of all injections.
:rtype: tuple[:py:class:`dependency_injector.injections.Injection`]
"""
return self.args + self.kwargs + self.attributes + self.methods
def _provide(self, *args, **kwargs):
"""Return provided instance."""
"""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
"""
instance = self.provides(*_get_injectable_args(args, self.args),
**_get_injectable_kwargs(kwargs, self.kwargs))
for attribute in self.attributes:
@ -131,11 +266,6 @@ class Factory(Provider):
return instance
@property
def injections(self):
"""Return tuple of all injections."""
return self.args + self.kwargs + self.attributes + self.methods
class Singleton(Provider):
"""Singleton provider.

View File

@ -4,3 +4,4 @@
.. automodule:: dependency_injector.providers
:members:
:member-order: bysource
:inherited-members: