mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 11:04:01 +03:00
235 Fix Delegate cannot be used in overridden container (#236)
* Add test for bug #235 * Fix issue + refactoring * Update changelog
This commit is contained in:
parent
fb264a8379
commit
08de710b2f
|
@ -7,6 +7,13 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
Development version
|
||||
-------------------
|
||||
+ Fix ``3.14.11`` degradation issue causing inability of using ``Delegate`` provider in
|
||||
``DeclarativeContainer`` when this container is instantiated with overriding of delegating
|
||||
provider (thanks to `GitterRemote <https://github .com/GitterRemote>`_, issue details are
|
||||
`here <https://github.com/ets-labs/python-dependency-injector/issues/235>`_).
|
||||
|
||||
3.14.11
|
||||
-------
|
||||
+ Fix issue causing creation of a copy of provided object by ``Object`` provider when it was a
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -21,8 +21,10 @@ cdef class Object(Provider):
|
|||
cpdef object _provide(self, tuple args, dict kwargs)
|
||||
|
||||
|
||||
cdef class Delegate(Object):
|
||||
pass
|
||||
cdef class Delegate(Provider):
|
||||
cdef object __provides
|
||||
|
||||
cpdef object _provide(self, tuple args, dict kwargs)
|
||||
|
||||
|
||||
cdef class Dependency(Provider):
|
||||
|
|
|
@ -291,7 +291,7 @@ cdef class Object(Provider):
|
|||
return self.__provides
|
||||
|
||||
|
||||
cdef class Delegate(Object):
|
||||
cdef class Delegate(Provider):
|
||||
"""Delegate provider returns provider "as is".
|
||||
|
||||
.. py:attribute:: provides
|
||||
|
@ -305,9 +305,49 @@ cdef class Delegate(Object):
|
|||
"""Initializer.
|
||||
|
||||
:param provides: Value that have to be provided.
|
||||
:type provides: object
|
||||
:type provides: :py:class:`Provider`
|
||||
"""
|
||||
super(Delegate, self).__init__(ensure_is_provider(provides))
|
||||
self.__provides = ensure_is_provider(provides)
|
||||
super(Delegate, self).__init__()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""Create and return full copy of provider."""
|
||||
copied = memo.get(id(self))
|
||||
if copied is not None:
|
||||
return copied
|
||||
|
||||
copied = self.__class__(deepcopy(self.__provides, memo))
|
||||
|
||||
self._copy_overridings(copied, memo)
|
||||
|
||||
return copied
|
||||
|
||||
def __str__(self):
|
||||
"""Return string representation of provider.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return represent_provider(provider=self, provides=self.__provides)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return string representation of provider.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return self.__str__()
|
||||
|
||||
cpdef object _provide(self, tuple args, dict 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.__provides
|
||||
|
||||
|
||||
cdef class Dependency(Provider):
|
||||
|
@ -834,7 +874,7 @@ cdef class CallableDelegate(Delegate):
|
|||
if isinstance(callable, Callable) is False:
|
||||
raise Error('{0} can wrap only {1} providers'.format(
|
||||
self.__class__, Callable))
|
||||
super(Delegate, self).__init__(callable)
|
||||
super(CallableDelegate, self).__init__(callable)
|
||||
|
||||
|
||||
cdef class Coroutine(Callable):
|
||||
|
@ -1416,7 +1456,7 @@ cdef class FactoryDelegate(Delegate):
|
|||
if isinstance(factory, Factory) is False:
|
||||
raise Error('{0} can wrap only {1} providers'.format(
|
||||
self.__class__, Factory))
|
||||
super(Delegate, self).__init__(factory)
|
||||
super(FactoryDelegate, self).__init__(factory)
|
||||
|
||||
|
||||
cdef class FactoryAggregate(Provider):
|
||||
|
@ -1923,7 +1963,7 @@ cdef class SingletonDelegate(Delegate):
|
|||
if isinstance(singleton, BaseSingleton) is False:
|
||||
raise Error('{0} can wrap only {1} providers'.format(
|
||||
self.__class__, BaseSingleton))
|
||||
super(Delegate, self).__init__(singleton)
|
||||
super(SingletonDelegate, self).__init__(singleton)
|
||||
|
||||
|
||||
cdef class Injection(object):
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""Dependency injector declarative container unit tests."""
|
||||
|
||||
import collections
|
||||
import unittest2 as unittest
|
||||
|
||||
from dependency_injector import (
|
||||
|
@ -313,3 +314,19 @@ class DeclarativeContainerTests(unittest.TestCase):
|
|||
self.assertIs(container.p2.cls, container.p1)
|
||||
self.assertIs(_Container.p2.cls, _Container.p1)
|
||||
self.assertIsNot(container.p2.cls, _Container.p1)
|
||||
|
||||
def test_init_with_dependency_delegation(self):
|
||||
# Bug:
|
||||
# https://github.com/ets-labs/python-dependency-injector/issues/235
|
||||
A = collections.namedtuple('A', [])
|
||||
B = collections.namedtuple('B', ['fa'])
|
||||
C = collections.namedtuple('B', ['a'])
|
||||
|
||||
class Services(containers.DeclarativeContainer):
|
||||
a = providers.Dependency()
|
||||
c = providers.Factory(C, a=a)
|
||||
b = providers.Factory(B, fa=a.delegate())
|
||||
|
||||
a = providers.Factory(A)
|
||||
assert isinstance(Services(a=a).c().a, A) # ok
|
||||
Services(a=a).b().fa()
|
||||
|
|
Loading…
Reference in New Issue
Block a user