Skip to content

Commit 0e24cf4

Browse files
authored
Fix abc error message (RustPython#4987)
* Print correct error message for abc instantiation * Update dataclasses abc test
1 parent e864e26 commit 0e24cf4

File tree

4 files changed

+26
-21
lines changed

4 files changed

+26
-21
lines changed

Lib/test/test_abc.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ def foo(): return 4
149149
self.assertEqual(D.foo(), 4)
150150
self.assertEqual(D().foo(), 4)
151151

152-
# TODO: RUSTPYTHON
153-
@unittest.expectedFailure
154152
def test_object_new_with_one_abstractmethod(self):
155153
class C(metaclass=abc_ABCMeta):
156154
@abc.abstractmethod
@@ -159,8 +157,6 @@ def method_one(self):
159157
msg = r"class C with abstract method method_one"
160158
self.assertRaisesRegex(TypeError, msg, C)
161159

162-
# TODO: RUSTPYTHON
163-
@unittest.expectedFailure
164160
def test_object_new_with_many_abstractmethods(self):
165161
class C(metaclass=abc_ABCMeta):
166162
@abc.abstractmethod
@@ -525,8 +521,6 @@ def foo(self):
525521
self.assertEqual(A.__abstractmethods__, set())
526522
A()
527523

528-
# TODO: RUSTPYTHON
529-
@unittest.expectedFailure
530524
def test_update_new_abstractmethods(self):
531525
class A(metaclass=abc_ABCMeta):
532526
@abc.abstractmethod
@@ -543,8 +537,6 @@ def updated_foo(self):
543537
msg = "class A with abstract methods bar, foo"
544538
self.assertRaisesRegex(TypeError, msg, A)
545539

546-
# TODO: RUSTPYTHON
547-
@unittest.expectedFailure
548540
def test_update_implementation(self):
549541
class A(metaclass=abc_ABCMeta):
550542
@abc.abstractmethod
@@ -596,8 +588,6 @@ def updated_foo(self):
596588
A()
597589
self.assertFalse(hasattr(A, '__abstractmethods__'))
598590

599-
# TODO: RUSTPYTHON
600-
@unittest.expectedFailure
601591
def test_update_del_implementation(self):
602592
class A(metaclass=abc_ABCMeta):
603593
@abc.abstractmethod
@@ -617,8 +607,6 @@ def foo(self):
617607
msg = "class B with abstract method foo"
618608
self.assertRaisesRegex(TypeError, msg, B)
619609

620-
# TODO: RUSTPYTHON
621-
@unittest.expectedFailure
622610
def test_update_layered_implementation(self):
623611
class A(metaclass=abc_ABCMeta):
624612
@abc.abstractmethod

Lib/test/test_dataclasses.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3676,8 +3676,6 @@ class Date(Ordered):
36763676
self.assertFalse(inspect.isabstract(Date))
36773677
self.assertGreater(Date(2020,12,25), Date(2020,8,31))
36783678

3679-
# TODO: RUSTPYTHON
3680-
@unittest.expectedFailure
36813679
def test_maintain_abc(self):
36823680
class A(abc.ABC):
36833681
@abc.abstractmethod

extra_tests/snippets/stdlib_abc.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ def __subclasshook__(cls, subclass):
1313
return NotImplemented
1414

1515

16-
# TODO raise an error if there are in any abstract methods not fulfilled
17-
# with assert_raises(TypeError):
18-
# CustomInterface()
16+
with assert_raises(TypeError):
17+
CustomInterface()
1918

2019

2120
class Concrete:

vm/src/builtins/object.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
types::{Constructor, PyComparisonOp},
77
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
88
};
9+
use itertools::Itertools;
910

1011
/// object()
1112
/// --
@@ -38,10 +39,29 @@ impl Constructor for PyBaseObject {
3839
// Ensure that all abstract methods are implemented before instantiating instance.
3940
if let Some(abs_methods) = cls.get_attr(identifier!(vm, __abstractmethods__)) {
4041
if let Some(unimplemented_abstract_method_count) = abs_methods.length_opt(vm) {
41-
if unimplemented_abstract_method_count? > 0 {
42-
return Err(
43-
vm.new_type_error("You must implement the abstract methods".to_owned())
44-
);
42+
let methods: Vec<PyStrRef> = abs_methods.try_to_value(vm)?;
43+
let methods: String =
44+
Itertools::intersperse(methods.iter().map(|name| name.as_str()), ", ")
45+
.collect();
46+
47+
let unimplemented_abstract_method_count = unimplemented_abstract_method_count?;
48+
let name = cls.name().to_string();
49+
50+
match unimplemented_abstract_method_count {
51+
0 => {}
52+
1 => {
53+
return Err(vm.new_type_error(format!(
54+
"Can't instantiate abstract class {} with abstract method {}",
55+
name, methods
56+
)));
57+
}
58+
2.. => {
59+
return Err(vm.new_type_error(format!(
60+
"Can't instantiate abstract class {} with abstract methods {}",
61+
name, methods
62+
)));
63+
}
64+
_ => unreachable!("unimplemented_abstract_method_count is always positive"),
4565
}
4666
}
4767
}

0 commit comments

Comments
 (0)