diff options
-rw-r--r-- | Lib/test/test_class.py | 49 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2017-12-07-23-44-29.bpo-31506.j1U2fU.rst | 2 | ||||
-rw-r--r-- | Objects/typeobject.c | 6 |
3 files changed, 54 insertions, 3 deletions
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index ecc01f2779..a916e878b7 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -595,5 +595,54 @@ class ClassTests(unittest.TestCase): with self.assertRaises(TypeError): type.__setattr__(A, b'x', None) + def testConstructorErrorMessages(self): + # bpo-31506: Improves the error message logic for object_new & object_init + + # Class without any method overrides + class C: + pass + + with self.assertRaisesRegex(TypeError, r'C\(\) takes no arguments'): + C(42) + + with self.assertRaisesRegex(TypeError, r'C\(\) takes no arguments'): + C.__new__(C, 42) + + with self.assertRaisesRegex(TypeError, r'C\(\).__init__\(\) takes no arguments'): + C().__init__(42) + + with self.assertRaisesRegex(TypeError, r'C\(\) takes no arguments'): + object.__new__(C, 42) + + with self.assertRaisesRegex(TypeError, r'C\(\).__init__\(\) takes no arguments'): + object.__init__(C(), 42) + + # Class with both `__init__` & `__new__` method overriden + class D: + def __new__(cls, *args, **kwargs): + super().__new__(cls, *args, **kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + with self.assertRaisesRegex(TypeError, r'object.__new__\(\) takes no argument'): + D(42) + + with self.assertRaisesRegex(TypeError, r'object.__new__\(\) takes no argument'): + D.__new__(D, 42) + + with self.assertRaisesRegex(TypeError, r'object.__new__\(\) takes no argument'): + object.__new__(D, 42) + + # Class that only overrides __init__ + class E: + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + with self.assertRaisesRegex(TypeError, r'object.__init__\(\) takes no argument'): + E().__init__(42) + + with self.assertRaisesRegex(TypeError, r'object.__init__\(\) takes no argument'): + object.__init__(E(), 42) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-12-07-23-44-29.bpo-31506.j1U2fU.rst b/Misc/NEWS.d/next/Core and Builtins/2017-12-07-23-44-29.bpo-31506.j1U2fU.rst new file mode 100644 index 0000000000..ceb9ee2ce8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-12-07-23-44-29.bpo-31506.j1U2fU.rst @@ -0,0 +1,2 @@ +Improve the error message logic for object.__new__ and object.__init__. +Patch by Sanyam Khurana. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2a8118b43c..73f94e76c9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3592,11 +3592,11 @@ object_init(PyObject *self, PyObject *args, PyObject *kwds) PyTypeObject *type = Py_TYPE(self); if (excess_args(args, kwds)) { if (type->tp_init != object_init) { - PyErr_SetString(PyExc_TypeError, "object() takes no arguments"); + PyErr_SetString(PyExc_TypeError, "object.__init__() takes no arguments"); return -1; } if (type->tp_new == object_new) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments", + PyErr_Format(PyExc_TypeError, "%.200s().__init__() takes no arguments", type->tp_name); return -1; } @@ -3609,7 +3609,7 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (excess_args(args, kwds)) { if (type->tp_new != object_new) { - PyErr_SetString(PyExc_TypeError, "object() takes no arguments"); + PyErr_SetString(PyExc_TypeError, "object.__new__() takes no arguments"); return NULL; } if (type->tp_init == object_init) { |