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