diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index cd04817a1..c64fa6883 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -138,6 +138,11 @@ impl PyBaseObject { Ok(vm.ctx.not_implemented()) } + #[pyclassmethod(magic)] + fn init_subclass(_cls: PyClassRef, vm: &VirtualMachine) -> PyResult { + Ok(vm.ctx.none()) + } + #[pymethod(magic)] pub fn dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { let attributes: PyAttributes = obj.class().get_attributes(); diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index efffead6c..cd7e8a56b 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -2,6 +2,7 @@ use parking_lot::RwLock; use std::collections::{HashMap, HashSet}; use std::fmt; +use super::objclassmethod::PyClassMethod; use super::objdict::PyDictRef; use super::objlist::PyList; use super::objmappingproxy::PyMappingProxy; @@ -14,7 +15,7 @@ use crate::pyobject::{ IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyLease, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; -use crate::slots::{PyClassSlots, PyTpFlags}; +use crate::slots::{PyClassSlots, PyTpFlags, SlotDescriptor}; use crate::vm::VirtualMachine; use itertools::Itertools; use std::ops::Deref; @@ -301,6 +302,12 @@ impl PyClassRef { } } + if let Some(f) = attributes.get_mut("__init_subclass__") { + if f.class().is(&vm.ctx.function_type()) { + *f = PyClassMethod::new(f.clone()).into_ref(vm).into_object(); + } + } + let typ = new(metatype, name.as_str(), base.clone(), bases, attributes) .map_err(|e| vm.new_type_error(e))?; @@ -327,6 +334,20 @@ impl PyClassRef { } } + if let Some(initter) = typ.get_super_attr("__init_subclass__") { + let initter = PyClassMethod::descr_get( + vm, + initter, + None, + OptionalArg::Present(typ.clone().into_object()), + )?; + let init_args = PyFuncArgs { + args: Vec::new(), + kwargs: args.kwargs, + }; + vm.invoke(&initter, init_args)?; + }; + Ok(typ.into_object()) }