mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Ignore AttributeError for missing __prepare__.
This commit is contained in:
1 parent
69f436378d
commit
2f3f3f8505
2 files changed
+20
-7
No files matched your search
@@ -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
|
||||
@@ -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(|_| {
|
||||
|
||||
Reference in new issue
Block a user