diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs
index be14327542..d0e5ed9db2 100644
--- a/vm/src/builtins/object.rs
+++ b/vm/src/builtins/object.rs
@@ -400,11 +400,59 @@ impl PyBaseObject {
     }
 
     #[pyslot]
-    #[pymethod(magic)]
-    fn init(_zelf: PyObjectRef, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<()> {
+    fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
+        let typ = zelf.class();
+        eprintln!("called init of {}", zelf.class().name());
+        if typ.slots.init.load().map_or(0, |f| f as usize)
+            == vm
+                .ctx
+                .types
+                .object_type
+                .slots
+                .init
+                .load()
+                .map_or(0, |f| f as usize)
+        {
+            return Ok(());
+        }
+        if !args.is_empty() {
+            // if typ.slots.init.load().map_or(0, |f| f as usize) != vm.ctx.types.object_type.slots.init.load().map_or(0, |f| f as usize) {
+            //     return Err(vm.new_type_error(format!(
+            //         "object.__init__() takes exactly one argument (the instance to initialize)",
+            //     )));
+            // }
+            if typ.slots.new.load().map_or(0, |f| f as usize)
+                == vm
+                    .ctx
+                    .types
+                    .object_type
+                    .slots
+                    .new
+                    .load()
+                    .map_or(0, |f| f as usize)
+            {
+                return Err(vm.new_type_error(format!(
+                    "{:.200}.__init__() takes exactly one argument (the instance to initialize)",
+                    typ.name()
+                )));
+            }
+        }
         Ok(())
     }
 
+    #[pymethod(magic)]
+    fn init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
+        if zelf.class().is(vm.ctx.types.object_type) {
+            return Ok(());
+        }
+        eprintln!("{:?}", zelf.class().name());
+        let init = zelf
+            .class()
+            .mro_find_map(|cls| cls.slots.init.load())
+            .unwrap();
+        (init)(zelf, args, vm)
+    }
+
     #[pygetset(name = "__class__")]
     fn get_class(obj: PyObjectRef) -> PyTypeRef {
         obj.class().to_owned()
diff --git a/vm/src/builtins/super.rs b/vm/src/builtins/super.rs
index 442d162c78..d20757f751 100644
--- a/vm/src/builtins/super.rs
+++ b/vm/src/builtins/super.rs
@@ -125,8 +125,8 @@ impl Initializer for PySuper {
             (typ, obj)
         };
 
-        let mut inner = PySuperInner::new(typ, obj, vm)?;
-        std::mem::swap(&mut inner, &mut zelf.inner.write());
+        let inner = PySuperInner::new(typ, obj, vm)?;
+        let _ = std::mem::replace::<PySuperInner>(&mut zelf.inner.write(), inner);
 
         Ok(())
     }
@@ -173,14 +173,19 @@ impl GetAttr for PySuper {
                 .skip(1) // skip su->type (if any)
                 .collect();
             for cls in mro.iter() {
+                println!("traversing mro: {}", cls.name());
                 if let Some(descr) = cls.get_direct_attr(name) {
+                    // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267)
+                    let obj = if obj.is(&start_type) {
+                        None
+                    } else {
+                        println!("getattr {}.{} as {}", obj.class().name(), name, cls.name());
+
+                        Some(obj)
+                    };
+                    let cls = cls.as_object().to_owned();
                     return vm
-                        .call_get_descriptor_specific(
-                            &descr,
-                            // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267)
-                            if obj.is(&start_type) { None } else { Some(obj) },
-                            Some(start_type.as_object().to_owned()),
-                        )
+                        .call_get_descriptor_specific(&descr, obj, Some(cls))
                         .unwrap_or(Ok(descr));
                 }
             }
diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs
index a0c7ee58ff..fb653a4311 100644
--- a/vm/src/builtins/type.rs
+++ b/vm/src/builtins/type.rs
@@ -301,6 +301,9 @@ impl PyType {
         let mut slot_name_set = std::collections::HashSet::new();
 
         for cls in self.mro.read().iter() {
+            if !cls.slots.flags.contains(PyTypeFlags::HEAPTYPE) {
+                continue;
+            }
             for &name in cls.attributes.read().keys() {
                 if name == identifier!(ctx, __new__) {
                     continue;
diff --git a/vm/src/stdlib/ast/python.rs b/vm/src/stdlib/ast/python.rs
index 74c4db888a..de1f0b4a85 100644
--- a/vm/src/stdlib/ast/python.rs
+++ b/vm/src/stdlib/ast/python.rs
@@ -15,7 +15,6 @@ pub(crate) mod _ast {
     #[pyclass(flags(BASETYPE, HAS_DICT))]
     impl NodeAst {
         #[pyslot]
-        #[pymethod(magic)]
         fn init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
             let fields = zelf.get_attr("_fields", vm)?;
             let fields: Vec<PyStrRef> = fields.try_to_value(vm)?;
diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs
index 3e1979e3d0..5301e8e311 100644
--- a/vm/src/stdlib/io.rs
+++ b/vm/src/stdlib/io.rs
@@ -1402,17 +1402,12 @@ mod _io {
         #[pyslot]
         fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
             let zelf: PyRef<Self> = zelf.try_into_value(vm)?;
-            zelf.__init__(args, vm)
-        }
-
-        #[pymethod]
-        fn __init__(&self, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
             let (raw, BufferSize { buffer_size }): (PyObjectRef, _) =
                 args.bind(vm).map_err(|e| {
                     let msg = format!("{}() {}", Self::CLASS_NAME, *e.str(vm));
                     vm.new_exception_msg(e.class().to_owned(), msg)
                 })?;
-            self.init(raw, BufferSize { buffer_size }, vm)
+            zelf.init(raw, BufferSize { buffer_size }, vm)
         }
 
         fn init(
diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs
index e2121973ec..a9192e96f0 100644
--- a/vm/src/types/slot.rs
+++ b/vm/src/types/slot.rs
@@ -363,7 +363,10 @@ fn descr_set_wrapper(
 fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
     let res = vm.call_special_method(&obj, identifier!(vm, __init__), args)?;
     if !vm.is_none(&res) {
-        return Err(vm.new_type_error("__init__ must return None".to_owned()));
+        return Err(vm.new_type_error(format!(
+            "__init__ should return None, not '{:.200}'",
+            res.class().name()
+        )));
     }
     Ok(())
 }
@@ -511,6 +514,7 @@ impl PyType {
                 update_slot!(descr_set, descr_set_wrapper);
             }
             _ if name == identifier!(ctx, __init__) => {
+                eprintln!("init of {:?}", self.name());
                 toggle_slot!(init, init_wrapper);
             }
             _ if name == identifier!(ctx, __new__) => {
@@ -829,12 +833,6 @@ pub trait Initializer: PyPayload {
         Self::init(zelf, args, vm)
     }
 
-    #[pymethod]
-    #[inline]
-    fn __init__(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
-        Self::init(zelf, args, vm)
-    }
-
     fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()>;
 }