mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-21 17:16:46 +03:00
Optimize provider calls
This commit is contained in:
parent
f0f5822d14
commit
0e5ec6956e
|
@ -1,7 +1,6 @@
|
|||
"""Injections module."""
|
||||
|
||||
import sys
|
||||
import itertools
|
||||
|
||||
import six
|
||||
|
||||
|
@ -247,8 +246,14 @@ def inject(*args, **kwargs):
|
|||
@six.wraps(callback)
|
||||
def decorated(*args, **kwargs):
|
||||
"""Decorated with dependency injection callback."""
|
||||
return callback(*_get_injectable_args(args, decorated.args),
|
||||
**_get_injectable_kwargs(kwargs, decorated.kwargs))
|
||||
if decorated.args:
|
||||
args = tuple(arg.value for arg in decorated.args) + args
|
||||
|
||||
for kwarg in decorated.kwargs:
|
||||
if kwarg.name not in kwargs:
|
||||
kwargs[kwarg.name] = kwarg.value
|
||||
|
||||
return callback(*args, **kwargs)
|
||||
|
||||
decorated.args = arg_injections
|
||||
decorated.kwargs = kwarg_injections
|
||||
|
@ -274,16 +279,3 @@ def _parse_kwargs_injections(args, kwargs):
|
|||
kwarg_injections += tuple(KwArg(name, value)
|
||||
for name, value in six.iteritems(kwargs))
|
||||
return kwarg_injections
|
||||
|
||||
|
||||
def _get_injectable_args(context_args, arg_injections):
|
||||
"""Return tuple of positional arguments, patched with injections."""
|
||||
return itertools.chain((arg.value for arg in arg_injections), context_args)
|
||||
|
||||
|
||||
def _get_injectable_kwargs(context_kwargs, kwarg_injections):
|
||||
"""Return dictionary of keyword arguments, patched with injections."""
|
||||
injectable_kwargs = dict((kwarg.name, kwarg.value)
|
||||
for kwarg in kwarg_injections)
|
||||
injectable_kwargs.update(context_kwargs)
|
||||
return injectable_kwargs
|
||||
|
|
|
@ -4,8 +4,6 @@ import six
|
|||
|
||||
from .injections import _parse_args_injections
|
||||
from .injections import _parse_kwargs_injections
|
||||
from .injections import _get_injectable_args
|
||||
from .injections import _get_injectable_kwargs
|
||||
|
||||
from .utils import ensure_is_provider
|
||||
from .utils import is_attribute_injection
|
||||
|
@ -62,18 +60,10 @@ class Provider(object):
|
|||
Tuple of overriding providers, if any.
|
||||
|
||||
:type: tuple[:py:class:`Provider`] | None
|
||||
"""
|
||||
|
||||
__IS_PROVIDER__ = True
|
||||
__slots__ = ('overridden_by',)
|
||||
.. py:method:: __call__
|
||||
|
||||
def __init__(self):
|
||||
"""Initializer."""
|
||||
self.overridden_by = None
|
||||
super(Provider, self).__init__()
|
||||
|
||||
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.
|
||||
|
@ -81,10 +71,22 @@ class Provider(object):
|
|||
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)
|
||||
|
||||
:return: Provided instance
|
||||
:rtype: object
|
||||
"""
|
||||
|
||||
__IS_PROVIDER__ = True
|
||||
__OPTIMIZED_CALLS__ = True
|
||||
__slots__ = ('overridden_by', '__call__')
|
||||
|
||||
def __init__(self):
|
||||
"""Initializer."""
|
||||
self.overridden_by = None
|
||||
super(Provider, self).__init__()
|
||||
# Enable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
self.__call__ = self._provide
|
||||
|
||||
def _provide(self, *args, **kwargs):
|
||||
"""Providing strategy implementation.
|
||||
|
@ -95,6 +97,10 @@ class Provider(object):
|
|||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _call_last_overriding(self, *args, **kwargs):
|
||||
"""Call last overriding provider and return result."""
|
||||
return self.last_overriding(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def is_overridden(self):
|
||||
"""Read-only property that is set to ``True`` if provider is overridden.
|
||||
|
@ -127,6 +133,10 @@ class Provider(object):
|
|||
else:
|
||||
self.overridden_by += (ensure_is_provider(provider),)
|
||||
|
||||
# Disable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
self.__call__ = self._call_last_overriding
|
||||
|
||||
def reset_last_overriding(self):
|
||||
"""Reset last overriding provider.
|
||||
|
||||
|
@ -139,6 +149,11 @@ class Provider(object):
|
|||
raise Error('Provider {0} is not overridden'.format(str(self)))
|
||||
self.overridden_by = self.overridden_by[:-1]
|
||||
|
||||
if not self.is_overridden:
|
||||
# Enable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
self.__call__ = self._provide
|
||||
|
||||
def reset_override(self):
|
||||
"""Reset all overriding providers.
|
||||
|
||||
|
@ -146,6 +161,10 @@ class Provider(object):
|
|||
"""
|
||||
self.overridden_by = None
|
||||
|
||||
# Enable __call__() / _provide() optimization
|
||||
if self.__class__.__OPTIMIZED_CALLS__:
|
||||
self.__call__ = self._provide
|
||||
|
||||
def delegate(self):
|
||||
"""Return provider's delegate.
|
||||
|
||||
|
@ -306,8 +325,14 @@ class Callable(Provider):
|
|||
|
||||
:rtype: object
|
||||
"""
|
||||
return self.provides(*_get_injectable_args(args, self.args),
|
||||
**_get_injectable_kwargs(kwargs, self.kwargs))
|
||||
if self.args:
|
||||
args = tuple(arg.value for arg in self.args) + args
|
||||
|
||||
for kwarg in self.kwargs:
|
||||
if kwarg.name not in kwargs:
|
||||
kwargs[kwarg.name] = kwarg.value
|
||||
|
||||
return self.provides(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
"""Return string representation of provider.
|
||||
|
@ -466,7 +491,14 @@ class Factory(Callable):
|
|||
|
||||
:rtype: object
|
||||
"""
|
||||
instance = super(Factory, self)._provide(*args, **kwargs)
|
||||
if self.args:
|
||||
args = tuple(arg.value for arg in self.args) + args
|
||||
|
||||
for kwarg in self.kwargs:
|
||||
if kwarg.name not in kwargs:
|
||||
kwargs[kwarg.name] = kwarg.value
|
||||
|
||||
instance = self.provides(*args, **kwargs)
|
||||
|
||||
for attribute in self.attributes:
|
||||
setattr(instance, attribute.name, attribute.value)
|
||||
|
@ -625,10 +657,12 @@ class Singleton(Factory):
|
|||
|
||||
:rtype: object
|
||||
"""
|
||||
if self.instance:
|
||||
return self.instance
|
||||
|
||||
with GLOBAL_LOCK:
|
||||
if not self.instance:
|
||||
self.instance = super(Singleton, self)._provide(*args,
|
||||
**kwargs)
|
||||
self.instance = super(Singleton, self)._provide(*args, **kwargs)
|
||||
|
||||
return self.instance
|
||||
|
||||
|
||||
|
@ -709,6 +743,7 @@ class ExternalDependency(Provider):
|
|||
:type: type
|
||||
"""
|
||||
|
||||
__OPTIMIZED_CALLS__ = False
|
||||
__slots__ = ('instance_of',)
|
||||
|
||||
def __init__(self, instance_of):
|
||||
|
|
8
tox.ini
8
tox.ini
|
@ -20,8 +20,8 @@ commands=
|
|||
coverage run --rcfile=./.coveragerc -m unittest2 discover tests []
|
||||
coverage html --rcfile=./.coveragerc
|
||||
|
||||
flake8 --max-complexity=8 dependency_injector/
|
||||
flake8 --max-complexity=8 examples/
|
||||
flake8 --max-complexity=10 dependency_injector/
|
||||
flake8 --max-complexity=10 examples/
|
||||
|
||||
pep257 dependency_injector/
|
||||
pep257 examples/
|
||||
|
@ -50,8 +50,8 @@ basepython=python2.7
|
|||
deps=
|
||||
flake8
|
||||
commands=
|
||||
flake8 --max-complexity=8 dependency_injector/
|
||||
flake8 --max-complexity=8 examples/
|
||||
flake8 --max-complexity=10 dependency_injector/
|
||||
flake8 --max-complexity=10 examples/
|
||||
|
||||
[testenv:pep257]
|
||||
basepython=python2.7
|
||||
|
|
Loading…
Reference in New Issue
Block a user