From 06f9855140c0d3032f55e1ca795aa002d45e8664 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Thu, 5 Aug 2021 16:52:08 -0400 Subject: [PATCH 1/3] Update types and add tests (#480) --- src/dependency_injector/containers.c | 101 ++++++++---------- src/dependency_injector/containers.pyx | 10 +- tests/unit/containers/test_dynamic_py2_py3.py | 33 ++++++ 3 files changed, 83 insertions(+), 61 deletions(-) diff --git a/src/dependency_injector/containers.c b/src/dependency_injector/containers.c index 89238d76..1716d27a 100644 --- a/src/dependency_injector/containers.c +++ b/src/dependency_injector/containers.c @@ -2591,12 +2591,6 @@ static CYTHON_INLINE int __Pyx_IterFinish(void); /* UnpackItemEndCheck.proto */ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); -/* ArgTypeTest.proto */ -#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ - ((likely((Py_TYPE(obj) == type) | (none_allowed && (obj == Py_None)))) ? 1 :\ - __Pyx__ArgTypeTest(obj, type, name, exact)) -static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); - /* IncludeStringH.proto */ #include @@ -2963,6 +2957,12 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /* None.proto */ static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely((Py_TYPE(obj) == type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + /* UnpackUnboundCMethod.proto */ typedef struct { PyObject *type; @@ -5185,7 +5185,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ * * return copied # <<<<<<<<<<<<<< * - * def __setattr__(self, str name, object value): + * def __setattr__(self, name, value): */ __Pyx_XDECREF(__pyx_r); __Pyx_INCREF(__pyx_v_copied); @@ -5222,14 +5222,14 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ /* "dependency_injector/containers.pyx":106 * return copied * - * def __setattr__(self, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(self, name, value): # <<<<<<<<<<<<<< * """Set instance attribute. * */ /* Python wrapper */ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_5__setattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_4__setattr__[] = "Set instance attribute.\n\n If value of attribute is provider, it will be added into providers\n dictionary.\n\n :param name: Attribute's name\n :type name: str\n\n :param value: Attribute's value\n :type value: object\n\n :rtype: None\n "; +static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_4__setattr__[] = "Set instance attribute.\n\n If value of attribute is provider, it will be added into providers\n dictionary.\n\n :param name: Attribute's name\n :type name: object\n\n :param value: Attribute's value\n :type value: object\n\n :rtype: None\n "; static PyMethodDef __pyx_mdef_19dependency_injector_10containers_16DynamicContainer_5__setattr__ = {"__setattr__", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_19dependency_injector_10containers_16DynamicContainer_5__setattr__, METH_VARARGS|METH_KEYWORDS, __pyx_doc_19dependency_injector_10containers_16DynamicContainer_4__setattr__}; static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_5__setattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_self = 0; @@ -5286,7 +5286,7 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_ values[2] = PyTuple_GET_ITEM(__pyx_args, 2); } __pyx_v_self = values[0]; - __pyx_v_name = ((PyObject*)values[1]); + __pyx_v_name = values[1]; __pyx_v_value = values[2]; } goto __pyx_L4_argument_unpacking_done; @@ -5297,14 +5297,9 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_ __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) __PYX_ERR(0, 106, __pyx_L1_error) __pyx_r = __pyx_pf_19dependency_injector_10containers_16DynamicContainer_4__setattr__(__pyx_self, __pyx_v_self, __pyx_v_name, __pyx_v_value); /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } @@ -5375,8 +5370,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ * */ __pyx_t_4 = (__Pyx_PyString_Equals(__pyx_v_name, __pyx_n_s_parent, Py_NE)); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 122, __pyx_L1_error) - __pyx_t_5 = (__pyx_t_4 != 0); - __pyx_t_1 = __pyx_t_5; + __pyx_t_1 = __pyx_t_4; __pyx_L4_bool_binop_done:; /* "dependency_injector/containers.pyx":120 @@ -5425,8 +5419,8 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_1 = PyObject_IsInstance(__pyx_v_value, __pyx_t_3); if (unlikely(__pyx_t_1 == ((int)-1))) __PYX_ERR(0, 127, __pyx_L1_error) __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = (__pyx_t_1 != 0); - if (__pyx_t_5) { + __pyx_t_4 = (__pyx_t_1 != 0); + if (__pyx_t_4) { /* "dependency_injector/containers.pyx":128 * @@ -5477,7 +5471,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ * * super(DynamicContainer, self).__setattr__(name, value) # <<<<<<<<<<<<<< * - * def __delattr__(self, str name): + * def __delattr__(self, name): */ __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_DynamicContainer); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); @@ -5545,7 +5539,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ /* "dependency_injector/containers.pyx":106 * return copied * - * def __setattr__(self, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(self, name, value): # <<<<<<<<<<<<<< * """Set instance attribute. * */ @@ -5569,14 +5563,14 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ /* "dependency_injector/containers.pyx":132 * super(DynamicContainer, self).__setattr__(name, value) * - * def __delattr__(self, str name): # <<<<<<<<<<<<<< + * def __delattr__(self, name): # <<<<<<<<<<<<<< * """Delete instance attribute. * */ /* Python wrapper */ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_7__delattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_6__delattr__[] = "Delete instance attribute.\n\n If value of attribute is provider, it will be deleted from providers\n dictionary.\n\n :param name: Attribute's name\n :type name: str\n\n :rtype: None\n "; +static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_6__delattr__[] = "Delete instance attribute.\n\n If value of attribute is provider, it will be deleted from providers\n dictionary.\n\n :param name: Attribute's name\n :type name: object\n\n :rtype: None\n "; static PyMethodDef __pyx_mdef_19dependency_injector_10containers_16DynamicContainer_7__delattr__ = {"__delattr__", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_19dependency_injector_10containers_16DynamicContainer_7__delattr__, METH_VARARGS|METH_KEYWORDS, __pyx_doc_19dependency_injector_10containers_16DynamicContainer_6__delattr__}; static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_7__delattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_self = 0; @@ -5623,7 +5617,7 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_ values[1] = PyTuple_GET_ITEM(__pyx_args, 1); } __pyx_v_self = values[0]; - __pyx_v_name = ((PyObject*)values[1]); + __pyx_v_name = values[1]; } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; @@ -5633,14 +5627,9 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_ __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) __PYX_ERR(0, 132, __pyx_L1_error) __pyx_r = __pyx_pf_19dependency_injector_10containers_16DynamicContainer_6__delattr__(__pyx_self, __pyx_v_self, __pyx_v_name); /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } @@ -5736,7 +5725,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_16DynamicContainer_ /* "dependency_injector/containers.pyx":132 * super(DynamicContainer, self).__setattr__(name, value) * - * def __delattr__(self, str name): # <<<<<<<<<<<<<< + * def __delattr__(self, name): # <<<<<<<<<<<<<< * """Delete instance attribute. * */ @@ -6273,7 +6262,7 @@ static PyObject *__pyx_gb_19dependency_injector_10containers_16DynamicContainer_ /* Python wrapper */ static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_14set_providers(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_13set_providers[] = "Set container providers.\n\n :param providers: Dictionary of providers\n :type providers:\n dict[str, :py:class:`dependency_injector.providers.Provider`]\n\n :rtype: None\n "; +static char __pyx_doc_19dependency_injector_10containers_16DynamicContainer_13set_providers[] = "Set container providers.\n\n :param providers: Dictionary of providers\n :type providers:\n dict[object, :py:class:`dependency_injector.providers.Provider`]\n\n :rtype: None\n "; static PyMethodDef __pyx_mdef_19dependency_injector_10containers_16DynamicContainer_14set_providers = {"set_providers", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_19dependency_injector_10containers_16DynamicContainer_14set_providers, METH_VARARGS|METH_KEYWORDS, __pyx_doc_19dependency_injector_10containers_16DynamicContainer_13set_providers}; static PyObject *__pyx_pw_19dependency_injector_10containers_16DynamicContainer_14set_providers(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_self = 0; @@ -26744,7 +26733,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { /* "dependency_injector/containers.pyx":106 * return copied * - * def __setattr__(self, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(self, name, value): # <<<<<<<<<<<<<< * """Set instance attribute. * */ @@ -26756,7 +26745,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { /* "dependency_injector/containers.pyx":132 * super(DynamicContainer, self).__setattr__(name, value) * - * def __delattr__(self, str name): # <<<<<<<<<<<<<< + * def __delattr__(self, name): # <<<<<<<<<<<<<< * """Delete instance attribute. * */ @@ -28240,7 +28229,7 @@ if (!__Pyx_RefNanny) { /* "dependency_injector/containers.pyx":106 * return copied * - * def __setattr__(self, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(self, name, value): # <<<<<<<<<<<<<< * """Set instance attribute. * */ @@ -28252,7 +28241,7 @@ if (!__Pyx_RefNanny) { /* "dependency_injector/containers.pyx":132 * super(DynamicContainer, self).__setattr__(name, value) * - * def __delattr__(self, str name): # <<<<<<<<<<<<<< + * def __delattr__(self, name): # <<<<<<<<<<<<<< * """Delete instance attribute. * */ @@ -29934,27 +29923,6 @@ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) { return 0; } -/* ArgTypeTest */ -static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) -{ - if (unlikely(!type)) { - PyErr_SetString(PyExc_SystemError, "Missing type object"); - return 0; - } - else if (exact) { - #if PY_MAJOR_VERSION == 2 - if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; - #endif - } - else { - if (likely(__Pyx_TypeCheck(obj, type))) return 1; - } - PyErr_Format(PyExc_TypeError, - "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)", - name, type->tp_name, Py_TYPE(obj)->tp_name); - return 0; -} - /* BytesEquals */ static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { #if CYTHON_COMPILING_IN_PYPY @@ -32800,6 +32768,27 @@ static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) { PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname); } +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)", + name, type->tp_name, Py_TYPE(obj)->tp_name); + return 0; +} + /* UnpackUnboundCMethod */ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) { PyObject *method; diff --git a/src/dependency_injector/containers.pyx b/src/dependency_injector/containers.pyx index 2b1c6b00..49509453 100644 --- a/src/dependency_injector/containers.pyx +++ b/src/dependency_injector/containers.pyx @@ -103,14 +103,14 @@ class DynamicContainer(Container): return copied - def __setattr__(self, str name, object value): + def __setattr__(self, name, value): """Set instance attribute. If value of attribute is provider, it will be added into providers dictionary. :param name: Attribute's name - :type name: str + :type name: object :param value: Attribute's value :type value: object @@ -129,14 +129,14 @@ class DynamicContainer(Container): super(DynamicContainer, self).__setattr__(name, value) - def __delattr__(self, str name): + def __delattr__(self, name): """Delete instance attribute. If value of attribute is provider, it will be deleted from providers dictionary. :param name: Attribute's name - :type name: str + :type name: object :rtype: None """ @@ -169,7 +169,7 @@ class DynamicContainer(Container): :param providers: Dictionary of providers :type providers: - dict[str, :py:class:`dependency_injector.providers.Provider`] + dict[object, :py:class:`dependency_injector.providers.Provider`] :rtype: None """ diff --git a/tests/unit/containers/test_dynamic_py2_py3.py b/tests/unit/containers/test_dynamic_py2_py3.py index bfcf766a..64699939 100644 --- a/tests/unit/containers/test_dynamic_py2_py3.py +++ b/tests/unit/containers/test_dynamic_py2_py3.py @@ -686,3 +686,36 @@ class SelfTests(unittest.TestCase): self.assertIs(container.__self__(), container) self.assertIs(container.sub_container().__self__(), container.sub_container()) + + +class DynamicContainerWithCustomStringTests(unittest.TestCase): + # See: https://github.com/ets-labs/python-dependency-injector/issues/479 + + class CustomString(str): + pass + + class CustomClass: + thing = None + + def setUp(self): + self.object = self.CustomClass() + self.container = containers.DynamicContainer() + self.provider = providers.Provider() + + def test_setattr(self): + setattr(self.container, self.CustomString('test_attr'), self.provider) + self.assertIs(self.container.test_attr, self.provider) + + def test_delattr(self): + setattr(self.container, self.CustomString('test_attr'), self.provider) + delattr(self.container, self.CustomString('test_attr')) + with self.assertRaises(AttributeError): + self.container.test_attr + + def test_set_provider(self): + self.container.set_provider(self.CustomString('test_attr'), self.provider) + self.assertIs(self.container.test_attr, self.provider) + + def test_set_providers(self): + self.container.set_providers(**{self.CustomString('test_attr'): self.provider}) + self.assertIs(self.container.test_attr, self.provider) From 384117db9c322ca8e5efad7c2874b1aa0183aa32 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Thu, 5 Aug 2021 17:01:53 -0400 Subject: [PATCH 2/3] Update declarative container to support custom string types --- src/dependency_injector/containers.c | 45 +++++++------------ src/dependency_injector/containers.pyx | 8 ++-- .../containers/test_declarative_py2_py3.py | 27 +++++++++++ tests/unit/containers/test_dynamic_py2_py3.py | 1 - 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/dependency_injector/containers.c b/src/dependency_injector/containers.c index 1716d27a..25fb1fa2 100644 --- a/src/dependency_injector/containers.c +++ b/src/dependency_injector/containers.c @@ -13783,7 +13783,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai * * return cls # <<<<<<<<<<<<<< * - * def __setattr__(cls, str name, object value): + * def __setattr__(cls, name, value): */ __Pyx_XDECREF(__pyx_r); __Pyx_INCREF(((PyObject *)__pyx_v_cls)); @@ -13832,14 +13832,14 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai /* "dependency_injector/containers.pyx":472 * return cls * - * def __setattr__(cls, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(cls, name, value): # <<<<<<<<<<<<<< * """Set class attribute. * */ /* Python wrapper */ static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContainerMetaClass_3__setattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_19dependency_injector_10containers_29DeclarativeContainerMetaClass_2__setattr__[] = "Set class attribute.\n\n If value of attribute is provider, it will be added into providers\n dictionary.\n\n :param name: Attribute's name\n :type name: str\n\n :param value: Attribute's value\n :type value: object\n\n :rtype: None\n "; +static char __pyx_doc_19dependency_injector_10containers_29DeclarativeContainerMetaClass_2__setattr__[] = "Set class attribute.\n\n If value of attribute is provider, it will be added into providers\n dictionary.\n\n :param name: Attribute's name\n :type name: object\n\n :param value: Attribute's value\n :type value: object\n\n :rtype: None\n "; static PyMethodDef __pyx_mdef_19dependency_injector_10containers_29DeclarativeContainerMetaClass_3__setattr__ = {"__setattr__", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_19dependency_injector_10containers_29DeclarativeContainerMetaClass_3__setattr__, METH_VARARGS|METH_KEYWORDS, __pyx_doc_19dependency_injector_10containers_29DeclarativeContainerMetaClass_2__setattr__}; static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContainerMetaClass_3__setattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_cls = 0; @@ -13896,7 +13896,7 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContai values[2] = PyTuple_GET_ITEM(__pyx_args, 2); } __pyx_v_cls = values[0]; - __pyx_v_name = ((PyObject*)values[1]); + __pyx_v_name = values[1]; __pyx_v_value = values[2]; } goto __pyx_L4_argument_unpacking_done; @@ -13907,14 +13907,9 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContai __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) __PYX_ERR(0, 472, __pyx_L1_error) __pyx_r = __pyx_pf_19dependency_injector_10containers_29DeclarativeContainerMetaClass_2__setattr__(__pyx_self, __pyx_v_cls, __pyx_v_name, __pyx_v_value); /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } @@ -13956,8 +13951,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai goto __pyx_L4_bool_binop_done; } __pyx_t_5 = (__Pyx_PyString_Equals(__pyx_v_name, __pyx_n_s_self, Py_NE)); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 486, __pyx_L1_error) - __pyx_t_4 = (__pyx_t_5 != 0); - __pyx_t_1 = __pyx_t_4; + __pyx_t_1 = __pyx_t_5; __pyx_L4_bool_binop_done:; if (__pyx_t_1) { @@ -13986,8 +13980,8 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_1 = PyObject_IsInstance(__pyx_v_value, __pyx_t_2); if (unlikely(__pyx_t_1 == ((int)-1))) __PYX_ERR(0, 489, __pyx_L1_error) __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = (__pyx_t_1 != 0); - if (__pyx_t_4) { + __pyx_t_5 = (__pyx_t_1 != 0); + if (__pyx_t_5) { /* "dependency_injector/containers.pyx":490 * @@ -14062,7 +14056,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai * cls.cls_providers[name] = value * super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) # <<<<<<<<<<<<<< * - * def __delattr__(cls, str name): + * def __delattr__(cls, name): */ __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_DeclarativeContainerMetaClass_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 494, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); @@ -14130,7 +14124,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai /* "dependency_injector/containers.pyx":472 * return cls * - * def __setattr__(cls, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(cls, name, value): # <<<<<<<<<<<<<< * """Set class attribute. * */ @@ -14154,14 +14148,14 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai /* "dependency_injector/containers.pyx":496 * super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) * - * def __delattr__(cls, str name): # <<<<<<<<<<<<<< + * def __delattr__(cls, name): # <<<<<<<<<<<<<< * """Delete class attribute. * */ /* Python wrapper */ static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContainerMetaClass_5__delattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_19dependency_injector_10containers_29DeclarativeContainerMetaClass_4__delattr__[] = "Delete class attribute.\n\n If value of attribute is provider, it will be deleted from providers\n dictionary.\n\n :param name: Attribute's name\n :type name: str\n\n :rtype: None\n "; +static char __pyx_doc_19dependency_injector_10containers_29DeclarativeContainerMetaClass_4__delattr__[] = "Delete class attribute.\n\n If value of attribute is provider, it will be deleted from providers\n dictionary.\n\n :param name: Attribute's name\n :type name: object\n\n :rtype: None\n "; static PyMethodDef __pyx_mdef_19dependency_injector_10containers_29DeclarativeContainerMetaClass_5__delattr__ = {"__delattr__", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_19dependency_injector_10containers_29DeclarativeContainerMetaClass_5__delattr__, METH_VARARGS|METH_KEYWORDS, __pyx_doc_19dependency_injector_10containers_29DeclarativeContainerMetaClass_4__delattr__}; static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContainerMetaClass_5__delattr__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_cls = 0; @@ -14208,7 +14202,7 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContai values[1] = PyTuple_GET_ITEM(__pyx_args, 1); } __pyx_v_cls = values[0]; - __pyx_v_name = ((PyObject*)values[1]); + __pyx_v_name = values[1]; } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; @@ -14218,14 +14212,9 @@ static PyObject *__pyx_pw_19dependency_injector_10containers_29DeclarativeContai __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) __PYX_ERR(0, 496, __pyx_L1_error) __pyx_r = __pyx_pf_19dependency_injector_10containers_29DeclarativeContainerMetaClass_4__delattr__(__pyx_self, __pyx_v_cls, __pyx_v_name); /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } @@ -14346,7 +14335,7 @@ static PyObject *__pyx_pf_19dependency_injector_10containers_29DeclarativeContai /* "dependency_injector/containers.pyx":496 * super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) * - * def __delattr__(cls, str name): # <<<<<<<<<<<<<< + * def __delattr__(cls, name): # <<<<<<<<<<<<<< * """Delete class attribute. * */ @@ -27030,7 +27019,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { /* "dependency_injector/containers.pyx":472 * return cls * - * def __setattr__(cls, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(cls, name, value): # <<<<<<<<<<<<<< * """Set class attribute. * */ @@ -27042,7 +27031,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { /* "dependency_injector/containers.pyx":496 * super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) * - * def __delattr__(cls, str name): # <<<<<<<<<<<<<< + * def __delattr__(cls, name): # <<<<<<<<<<<<<< * """Delete class attribute. * */ @@ -28574,7 +28563,7 @@ if (!__Pyx_RefNanny) { /* "dependency_injector/containers.pyx":472 * return cls * - * def __setattr__(cls, str name, object value): # <<<<<<<<<<<<<< + * def __setattr__(cls, name, value): # <<<<<<<<<<<<<< * """Set class attribute. * */ @@ -28586,7 +28575,7 @@ if (!__Pyx_RefNanny) { /* "dependency_injector/containers.pyx":496 * super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) * - * def __delattr__(cls, str name): # <<<<<<<<<<<<<< + * def __delattr__(cls, name): # <<<<<<<<<<<<<< * """Delete class attribute. * */ diff --git a/src/dependency_injector/containers.pyx b/src/dependency_injector/containers.pyx index 49509453..907264ea 100644 --- a/src/dependency_injector/containers.pyx +++ b/src/dependency_injector/containers.pyx @@ -469,14 +469,14 @@ class DeclarativeContainerMetaClass(type): return cls - def __setattr__(cls, str name, object value): + def __setattr__(cls, name, value): """Set class attribute. If value of attribute is provider, it will be added into providers dictionary. :param name: Attribute's name - :type name: str + :type name: object :param value: Attribute's value :type value: object @@ -493,14 +493,14 @@ class DeclarativeContainerMetaClass(type): cls.cls_providers[name] = value super(DeclarativeContainerMetaClass, cls).__setattr__(name, value) - def __delattr__(cls, str name): + def __delattr__(cls, name): """Delete class attribute. If value of attribute is provider, it will be deleted from providers dictionary. :param name: Attribute's name - :type name: str + :type name: object :rtype: None """ diff --git a/tests/unit/containers/test_declarative_py2_py3.py b/tests/unit/containers/test_declarative_py2_py3.py index 8bf8b8e2..a58a57f9 100644 --- a/tests/unit/containers/test_declarative_py2_py3.py +++ b/tests/unit/containers/test_declarative_py2_py3.py @@ -496,3 +496,30 @@ class DeclarativeContainerTests(unittest.TestCase): str(context.exception), 'Dependency "Container.child_container.dependency" is not defined', ) + + +class DeclarativeContainerWithCustomStringTests(unittest.TestCase): + # See: https://github.com/ets-labs/python-dependency-injector/issues/479 + + class CustomString(str): + pass + + class CustomClass: + thing = None + + class CustomContainer(containers.DeclarativeContainer): + pass + + def setUp(self): + self.container = self.CustomContainer + self.provider = providers.Provider() + + def test_setattr(self): + setattr(self.container, self.CustomString('test_attr'), self.provider) + self.assertIs(self.container.test_attr, self.provider) + + def test_delattr(self): + setattr(self.container, self.CustomString('test_attr'), self.provider) + delattr(self.container, self.CustomString('test_attr')) + with self.assertRaises(AttributeError): + self.container.test_attr diff --git a/tests/unit/containers/test_dynamic_py2_py3.py b/tests/unit/containers/test_dynamic_py2_py3.py index 64699939..1c722be8 100644 --- a/tests/unit/containers/test_dynamic_py2_py3.py +++ b/tests/unit/containers/test_dynamic_py2_py3.py @@ -698,7 +698,6 @@ class DynamicContainerWithCustomStringTests(unittest.TestCase): thing = None def setUp(self): - self.object = self.CustomClass() self.container = containers.DynamicContainer() self.provider = providers.Provider() From f376628dfa222910021ce965ec3599516d8a4a01 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Thu, 5 Aug 2021 17:05:17 -0400 Subject: [PATCH 3/3] Bump version to 4.35.1 --- docs/main/changelog.rst | 6 ++++++ src/dependency_injector/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 7ee862fc..4cb0a6c9 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -7,6 +7,12 @@ that were made in every particular version. From version 0.7.6 *Dependency Injector* framework strictly follows `Semantic versioning`_ +4.35.1 +------ +- Fix a container issue with supporting custom string types. + See issue `#479 `_. + Thanks to `@ilsurih `_ for reporting the issue. + 4.35.0 ------ - Add support of six 1.16.0. diff --git a/src/dependency_injector/__init__.py b/src/dependency_injector/__init__.py index b3116716..e265332b 100644 --- a/src/dependency_injector/__init__.py +++ b/src/dependency_injector/__init__.py @@ -1,6 +1,6 @@ """Top-level package.""" -__version__ = '4.35.0' +__version__ = '4.35.1' """Version number. :type: str