diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 16af0c8a3..f65b1f629 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -149,8 +149,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): self.assertEqual(D.foo(), 4) self.assertEqual(D().foo(), 4) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_object_new_with_one_abstractmethod(self): class C(metaclass=abc_ABCMeta): @abc.abstractmethod @@ -159,8 +157,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): msg = r"class C with abstract method method_one" self.assertRaisesRegex(TypeError, msg, C) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_object_new_with_many_abstractmethods(self): class C(metaclass=abc_ABCMeta): @abc.abstractmethod @@ -525,8 +521,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): self.assertEqual(A.__abstractmethods__, set()) A() - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_update_new_abstractmethods(self): class A(metaclass=abc_ABCMeta): @abc.abstractmethod @@ -543,8 +537,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): msg = "class A with abstract methods bar, foo" self.assertRaisesRegex(TypeError, msg, A) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_update_implementation(self): class A(metaclass=abc_ABCMeta): @abc.abstractmethod @@ -596,8 +588,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): A() self.assertFalse(hasattr(A, '__abstractmethods__')) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_update_del_implementation(self): class A(metaclass=abc_ABCMeta): @abc.abstractmethod @@ -617,8 +607,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): msg = "class B with abstract method foo" self.assertRaisesRegex(TypeError, msg, B) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_update_layered_implementation(self): class A(metaclass=abc_ABCMeta): @abc.abstractmethod diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 6bd9d37fa..33bd9d0cb 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3676,8 +3676,6 @@ class TestAbstract(unittest.TestCase): self.assertFalse(inspect.isabstract(Date)) self.assertGreater(Date(2020,12,25), Date(2020,8,31)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_maintain_abc(self): class A(abc.ABC): @abc.abstractmethod diff --git a/extra_tests/snippets/stdlib_abc.py b/extra_tests/snippets/stdlib_abc.py index a4c200241..30b4ef370 100644 --- a/extra_tests/snippets/stdlib_abc.py +++ b/extra_tests/snippets/stdlib_abc.py @@ -13,9 +13,8 @@ class CustomInterface(abc.ABC): return NotImplemented -# TODO raise an error if there are in any abstract methods not fulfilled -# with assert_raises(TypeError): -# CustomInterface() +with assert_raises(TypeError): + CustomInterface() class Concrete: diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 7228b5d64..1a9159544 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -6,6 +6,7 @@ use crate::{ types::{Constructor, PyComparisonOp}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; +use itertools::Itertools; /// object() /// -- @@ -38,10 +39,29 @@ impl Constructor for PyBaseObject { // Ensure that all abstract methods are implemented before instantiating instance. if let Some(abs_methods) = cls.get_attr(identifier!(vm, __abstractmethods__)) { if let Some(unimplemented_abstract_method_count) = abs_methods.length_opt(vm) { - if unimplemented_abstract_method_count? > 0 { - return Err( - vm.new_type_error("You must implement the abstract methods".to_owned()) - ); + let methods: Vec = abs_methods.try_to_value(vm)?; + let methods: String = + Itertools::intersperse(methods.iter().map(|name| name.as_str()), ", ") + .collect(); + + let unimplemented_abstract_method_count = unimplemented_abstract_method_count?; + let name = cls.name().to_string(); + + match unimplemented_abstract_method_count { + 0 => {} + 1 => { + return Err(vm.new_type_error(format!( + "Can't instantiate abstract class {} with abstract method {}", + name, methods + ))); + } + 2.. => { + return Err(vm.new_type_error(format!( + "Can't instantiate abstract class {} with abstract methods {}", + name, methods + ))); + } + _ => unreachable!("unimplemented_abstract_method_count is always positive"), } } }