8000 gh-98284: better error message for undefined abstractmethod (#97971) · python/cpython@67ade40 · GitHub
[go: up one dir, main page]

Skip to content

Commit 67ade40

Browse files
authored
gh-98284: better error message for undefined abstractmethod (#97971)
1 parent b5f7111 commit 67ade40

File tree

6 files changed

+23
-19
lines changed

6 files changed

+23
-19
lines changed

Include/internal/pycore_global_strings.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ struct _Py_global_strings {
3737
STRUCT_FOR_STR(anon_string, "<string>")
3838
STRUCT_FOR_STR(anon_unknown, "<unknown>")
3939
STRUCT_FOR_STR(close_br, "}")
40-
STRUCT_FOR_STR(comma_sep, ", ")
4140
STRUCT_FOR_STR(dbl_close_br, "}}")
4241
STRUCT_FOR_STR(dbl_open_br, "{{")
4342
STRUCT_FOR_STR(dbl_percent, "%%")

Include/internal/pycore_runtime_init_generated.h

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_abc.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class C(metaclass=abc_ABCMeta):
154154
@abc.abstractmethod
155155
def method_one(self):
156156
pass
157-
msg = r"class C without an implementation for abstract method method_one"
157+
msg = r"class C without an implementation for abstract method 'method_one'"
158158
self.assertRaisesRegex(TypeError, msg, C)
159159

160160
def test_object_new_with_many_abstractmethods(self):
@@ -165,7 +165,7 @@ def method_one(self):
165165
@abc.abstractmethod
166166
def method_two(self):
167167
pass
168-
msg = r"class C without an implementation for abstract methods method_one, method_two"
168+
msg = r"class C without an implementation for abstract methods 'method_one', 'method_two'"
10000
169169
self.assertRaisesRegex(TypeError, msg, C)
170170

171171
def test_abstractmethod_integration(self):
@@ -535,7 +535,7 @@ def updated_foo(self):
535535
A.foo = updated_foo
536536
abc.update_abstractmethods(A)
537537
self.assertEqual(A.__abstractmethods__, {'foo', 'bar'})
538-
msg = "class A without an implementation for abstract methods bar, foo"
538+
msg = "class A without an implementation for abstract methods 'bar', 'foo'"
539539
self.assertRaisesRegex(TypeError, msg, A)
540540

541541
def test_update_implementation(self):
@@ -547,7 +547,7 @@ def foo(self):
547547
class B(A):
548548
pass
549549

550-
msg = "class B without an implementation for abstract method foo"
550+
msg = "class B without an implementation for abstract method 'foo'"
551551
self.assertRaisesRegex(TypeError, msg, B)
552552
self.assertEqual(B.__abstractmethods__, {'foo'})
553553

@@ -605,7 +605,7 @@ def foo(self):
605605

606606
abc.update_abstractmethods(B)
607607

608-
msg = "class B without an implementation for abstract method foo"
608+
msg = "class B without an implementation for abstract method 'foo'"
609609
self.assertRaisesRegex(TypeError, msg, B)
610610

611611
def test_update_layered_implementation(self):
@@ -627,7 +627,7 @@ def foo(self):
627627

628628
abc.update_abstractmethods(C)
629629

630-
msg = "class C without an implementation for abstract method foo"
630+
msg = "class C without an implementation for abstract method 'foo'"
631631
self.assertRaisesRegex(TypeError, msg, C)
632632

633633
def test_update_multi_inheritance(self):

Lib/test/test_dataclasses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3970,7 +3970,7 @@ class Date(A):
39703970
day: 'int'
39713971

39723972
self.assertTrue(inspect.isabstract(Date))
3973-
msg = 'class Date without an implementation for abstract method foo'
3973+
msg = "class Date without an implementation for abstract method 'foo'"
39743974
self.assertRaisesRegex(TypeError, msg, Date)
39753975

39763976

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Improved :class:`TypeError` message for undefined abstract methods of a
2+
:class:`abc.ABC` instance. The names of the missing methods are surrounded
3+
by single-quotes to highlight them.

Objects/typeobject.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4955,9 +4955,10 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
49554955
PyObject *abstract_methods;
49564956
PyObject *sorted_methods;
49574957
PyObject *joined;
4958+
PyObject* comma_w_quotes_sep;
49584959
Py_ssize_t method_count;
49594960

4960-
/* Compute ", ".join(sorted(type.__abstractmethods__))
4961+
/* Compute "', '".join(sorted(type.__abstractmethods__))
49614962
into joined. */
49624963
abstract_methods = type_abstractmethods(type, NULL);
49634964
if (abstract_methods == NULL)
@@ -4970,22 +4971,28 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
49704971
Py_DECREF(sorted_methods);
49714972
return NULL;
49724973
}
4973-
_Py_DECLARE_STR(comma_sep, ", ");
4974-
joined = PyUnicode_Join(&_Py_STR(comma_sep), sorted_methods);
4974+
comma_w_quotes_sep = PyUnicode_FromString("', '");
4975+
joined = PyUnicode_Join(comma_w_quotes_sep, sorted_methods);
49754976
method_count = PyObject_Length(sorted_methods);
49764977
Py_DECREF(sorted_methods);
4977-
if (joined == NULL)
4978+
if (joined == NULL) {
4979+
Py_DECREF(comma_w_quotes_sep);
49784980
return NULL;
4979-
if (method_count == -1)
4981+
}
4982+
if (method_count == -1) {
4983+
Py_DECREF(comma_w_quotes_sep);
4984+
Py_DECREF(joined);
49804985
return NULL;
4986+
}
49814987

49824988
PyErr_Format(PyExc_TypeError,
49834989
"Can't instantiate abstract class %s "
4984-
"without an implementation for abstract method%s %U",
4990+
"without an implementation for abstract method%s '%U'",
49854991
type->tp_name,
49864992
method_count > 1 ? "s" : "",
49874993
joined);
49884994
Py_DECREF(joined);
4995+
Py_DECREF(comma_w_quotes_sep);
49894996
return NULL;
49904997
}
49914998
PyObject *obj = type->tp_alloc(type, 0);

0 commit comments

Comments
 (0)
0