From a72f3c5b6cda80891a3866b68c7bba095e2c447d Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Wed, 25 Aug 2021 09:36:12 -0400 Subject: [PATCH] Fix deepcopying --- src/dependency_injector/providers.c | 41 +++++++++---------- src/dependency_injector/providers.pyx | 2 +- .../unit/providers/test_factories_py2_py3.py | 19 +++++++++ 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/dependency_injector/providers.c b/src/dependency_injector/providers.c index f884eaa8..38490105 100644 --- a/src/dependency_injector/providers.c +++ b/src/dependency_injector/providers.c @@ -49205,7 +49205,7 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_16FactoryAggregate_2_ * return copied * * copied = _memorized_duplicate(self, memo) # <<<<<<<<<<<<<< - * copied.set_factories(**deepcopy(self.factories, memo)) + * copied.set_factories(deepcopy(self.factories, memo)) * */ 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, 2501, __pyx_L1_error) @@ -49217,12 +49217,12 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_16FactoryAggregate_2_ /* "dependency_injector/providers.pyx":2502 * * copied = _memorized_duplicate(self, memo) - * copied.set_factories(**deepcopy(self.factories, memo)) # <<<<<<<<<<<<<< + * copied.set_factories(deepcopy(self.factories, memo)) # <<<<<<<<<<<<<< * * self._copy_overridings(copied, memo) */ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_copied, __pyx_n_s_set_factories); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2502, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_copied, __pyx_n_s_set_factories); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 2502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_factories); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 2502, __pyx_L1_error) __Pyx_GOTREF(__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, 2502, __pyx_L1_error) @@ -49231,27 +49231,26 @@ static PyObject *__pyx_pf_19dependency_injector_9providers_16FactoryAggregate_2_ __pyx_t_4 = __pyx_f_19dependency_injector_9providers_deepcopy(__pyx_t_3, 0, &__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 2502, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(__pyx_t_4 == Py_None)) { - PyErr_SetString(PyExc_TypeError, "argument after ** must be a mapping, not NoneType"); - __PYX_ERR(1, 2502, __pyx_L1_error) + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } } - if (likely(PyDict_CheckExact(__pyx_t_4))) { - __pyx_t_2 = PyDict_Copy(__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 2502, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - } else { - __pyx_t_2 = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 2502, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - } - __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_empty_tuple, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 2502, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __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_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, 2502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "dependency_injector/providers.pyx":2504 - * copied.set_factories(**deepcopy(self.factories, memo)) + * copied.set_factories(deepcopy(self.factories, memo)) * * self._copy_overridings(copied, memo) # <<<<<<<<<<<<<< * diff --git a/src/dependency_injector/providers.pyx b/src/dependency_injector/providers.pyx index 6f25c0e7..2c407fdb 100644 --- a/src/dependency_injector/providers.pyx +++ b/src/dependency_injector/providers.pyx @@ -2499,7 +2499,7 @@ cdef class FactoryAggregate(Provider): return copied copied = _memorized_duplicate(self, memo) - copied.set_factories(**deepcopy(self.factories, memo)) + copied.set_factories(deepcopy(self.factories, memo)) self._copy_overridings(copied, memo) diff --git a/tests/unit/providers/test_factories_py2_py3.py b/tests/unit/providers/test_factories_py2_py3.py index c6c11b51..29526889 100644 --- a/tests/unit/providers/test_factories_py2_py3.py +++ b/tests/unit/providers/test_factories_py2_py3.py @@ -5,6 +5,7 @@ import sys import unittest from dependency_injector import ( + containers, providers, errors, ) @@ -663,6 +664,24 @@ class FactoryAggregateTests(unittest.TestCase): self.assertIsInstance(self.factory_aggregate.example_b, type(provider_copy.example_b)) self.assertIs(self.factory_aggregate.example_b.cls, provider_copy.example_b.cls) + def test_deepcopy_with_non_string_keys(self): + factory_aggregate = providers.FactoryAggregate({ + self.ExampleA: self.example_a_factory, + self.ExampleB: self.example_b_factory, + }) + provider_copy = providers.deepcopy(factory_aggregate) + + self.assertIsNot(factory_aggregate, provider_copy) + self.assertIsInstance(provider_copy, type(factory_aggregate)) + + self.assertIsNot(factory_aggregate.factories[self.ExampleA], provider_copy.factories[self.ExampleA]) + self.assertIsInstance(factory_aggregate.factories[self.ExampleA], type(provider_copy.factories[self.ExampleA])) + self.assertIs(factory_aggregate.factories[self.ExampleA].cls, provider_copy.factories[self.ExampleA].cls) + + self.assertIsNot(factory_aggregate.factories[self.ExampleB], provider_copy.factories[self.ExampleB]) + self.assertIsInstance(factory_aggregate.factories[self.ExampleB], type(provider_copy.factories[self.ExampleB])) + self.assertIs(factory_aggregate.factories[self.ExampleB].cls, provider_copy.factories[self.ExampleB].cls) + def test_repr(self): self.assertEqual(repr(self.factory_aggregate), '