From 7e61412b8adbe9b21ed74458ebdabbc19c8f1c83 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Tue, 8 Oct 2019 14:45:12 -0400 Subject: [PATCH] 231 Fix object provider copies provided object issue (#233) * Add test that reproduces the issue * Fix the issue * Add a note about fix in changelog --- docs/main/changelog.rst | 7 +++++++ src/dependency_injector/providers.c | 18 ++++-------------- src/dependency_injector/providers.pyx | 2 +- tests/unit/providers/test_base_py2_py3.py | 11 +++++++++++ 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 637e1d22..809e709c 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -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 issue causing creation of a copy of provided object by ``Object`` provider when it was a + part of ``DeclarativeContainer`` and this container was instantiated (thanks to + `davidcim `_, issue details are + `here `_). + 3.14.10 ------ + Make spelling fix for the list of contributors. diff --git a/src/dependency_injector/providers.c b/src/dependency_injector/providers.c index 78671a69..d4e36733 100644 --- a/src/dependency_injector/providers.c +++ b/src/dependency_injector/providers.c @@ -6355,7 +6355,6 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_6Object_2__deepcopy__ PyObject *__pyx_t_4 = NULL; int __pyx_t_5; int __pyx_t_6; - struct __pyx_opt_args_19dependency_injector_9providers_deepcopy __pyx_t_7; __Pyx_RefNannySetupContext("__deepcopy__", 0); /* "dependency_injector/providers.pyx":256 @@ -6404,7 +6403,7 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_6Object_2__deepcopy__ * if copied is not None: * return copied # <<<<<<<<<<<<<< * - * copied = self.__class__(deepcopy(self.__provides, memo)) + * copied = self.__class__(self.__provides) */ __Pyx_XDECREF(__pyx_r); __Pyx_INCREF(__pyx_v_copied); @@ -6423,20 +6422,12 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_6Object_2__deepcopy__ /* "dependency_injector/providers.pyx":260 * return copied * - * copied = self.__class__(deepcopy(self.__provides, memo)) # <<<<<<<<<<<<<< + * copied = self.__class__(self.__provides) # <<<<<<<<<<<<<< * * self._copy_overridings(copied, memo) */ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 260, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __pyx_v_self->__pyx___provides; - __Pyx_INCREF(__pyx_t_3); - if (!(likely(PyDict_CheckExact(__pyx_v_memo))||((__pyx_v_memo) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "dict", Py_TYPE(__pyx_v_memo)->tp_name), 0))) __PYX_ERR(1, 260, __pyx_L1_error) - __pyx_t_7.__pyx_n = 1; - __pyx_t_7.memo = ((PyObject*)__pyx_v_memo); - __pyx_t_4 = __pyx_f_19dependency_injector_9providers_deepcopy(__pyx_t_3, 0, &__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 260, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = NULL; if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); @@ -6447,9 +6438,8 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_6Object_2__deepcopy__ __Pyx_DECREF_SET(__pyx_t_2, function); } } - __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_3, __pyx_t_4) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); + __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_3, __pyx_v_self->__pyx___provides) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_self->__pyx___provides); __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 260, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; @@ -6457,7 +6447,7 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_6Object_2__deepcopy__ __pyx_t_1 = 0; /* "dependency_injector/providers.pyx":262 - * copied = self.__class__(deepcopy(self.__provides, memo)) + * copied = self.__class__(self.__provides) * * self._copy_overridings(copied, memo) # <<<<<<<<<<<<<< * diff --git a/src/dependency_injector/providers.pyx b/src/dependency_injector/providers.pyx index 322678d7..c9ca867b 100644 --- a/src/dependency_injector/providers.pyx +++ b/src/dependency_injector/providers.pyx @@ -257,7 +257,7 @@ cdef class Object(Provider): if copied is not None: return copied - copied = self.__class__(deepcopy(self.__provides, memo)) + copied = self.__class__(self.__provides) self._copy_overridings(copied, memo) diff --git a/tests/unit/providers/test_base_py2_py3.py b/tests/unit/providers/test_base_py2_py3.py index 2f929cbf..b017edfd 100644 --- a/tests/unit/providers/test_base_py2_py3.py +++ b/tests/unit/providers/test_base_py2_py3.py @@ -193,6 +193,17 @@ class ObjectProviderTests(unittest.TestCase): self.assertIsNot(overriding_provider, overriding_provider_copy) self.assertIsInstance(overriding_provider_copy, providers.Provider) + def test_deepcopy_doesnt_copy_provided_object(self): + # Fixes bug #231 + # Details: https://github.com/ets-labs/python-dependency-injector/issues/231 + some_object = object() + provider = providers.Object(some_object) + + provider_copy = providers.deepcopy(provider) + + self.assertIs(provider(), some_object) + self.assertIs(provider_copy(), some_object) + def test_repr(self): some_object = object() provider = providers.Object(some_object)