Ignore AttributeError for missing __prepare__.

This commit is contained in:
jfh committed 2021-10-16 20:16:33 +03:00
1 parent 69f436378d
commit 2f3f3f8505
2 files changed
+20 -7

No files matched your search

+10
View File
@@ -1,3 +1,4 @@
from testutils import assert_raises
__name__ = "class"
@@ -287,3 +288,12 @@ assert type(type.mro).__name__ == 'method_descriptor'
B('x', (int,), {}).x()
A()
# Check that any appropriate callable can be used as metaclass key:
meta = lambda *a, **k: type(*a, **k)
class _(metaclass=meta): pass
# check that non-callables don't fail on an absent prepare:
with assert_raises(TypeError, _msg="'int' object not callable"):
class _(metaclass=20): pass
+10 -7
View File
@@ -872,13 +872,16 @@ mod builtins {
let bases: PyObjectRef = bases.into();
// Prepare uses full __getattribute__ resolution chain.
// TODO RUSTPYTHON: Doesn't do what we want all the time:
// e.g class M(metaclass=2): pass should fail with 'int not callable'.
let prepare = vm.get_attribute(metaclass.clone(), "__prepare__")?;
let namespace = vm.invoke(
&prepare,
FuncArgs::new(vec![name_obj.clone().into(), bases.clone()], kwargs.clone()),
)?;
// If an AttributeError was raised (None), return an empty dict,
// else invoke prepare callable.
let namespace = vm
.get_attribute_opt(metaclass.clone(), "__prepare__")?
.map_or(Ok(vm.ctx.new_dict().into()), |prepare| {
vm.invoke(
&prepare,
FuncArgs::new(vec![name_obj.clone().into(), bases.clone()], kwargs.clone()),
)
})?;
// Accept any PyMapping as namespace.
let namespace = PyMapping::try_from_object(vm, namespace.clone()).map_err(|_| {