summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanyam Khurana <8039608+CuriousLearner@users.noreply.github.com>2017-12-10 05:44:22 +0530
committerNick Coghlan <ncoghlan@gmail.com>2017-12-10 10:14:22 +1000
commit780acc89bccf9999332d334a27887684cc942eb6 (patch)
tree80423316c9121c442620787bfcfc0b657f43b11c
parent60ed1308304964e5648d8bfc9b74bd549570fa83 (diff)
downloadcpython-git-780acc89bccf9999332d334a27887684cc942eb6.tar.gz
bpo-31506: Improve the error message logic for class instantiation (GH-4740)
The error messages in `object.__new__` and `object.__init__` now aim to point the user more directly at the name of the class being instantiated in cases where they *haven't* been overridden (on the assumption that the actual problem is a missing `__new__` or `__init__` definition in the class body). When they *have* been overridden, the errors still report themselves as coming from object, on the assumption that the problem is with the call up to the base class in the method implementation, rather than with the way the constructor is being called.
-rw-r--r--Lib/test/test_class.py49
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2017-12-07-23-44-29.bpo-31506.j1U2fU.rst2
-rw-r--r--Objects/typeobject.c6
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) {