(
function: PyRef<PyFunction>,
name: PyStrRef,
bases: PosArgs,
mut kwargs: KwArgs,
vm: &VirtualMachine,
)
| 1163 | |
| 1164 | #[pyfunction] |
| 1165 | pub fn __build_class__( |
| 1166 | function: PyRef<PyFunction>, |
| 1167 | name: PyStrRef, |
| 1168 | bases: PosArgs, |
| 1169 | mut kwargs: KwArgs, |
| 1170 | vm: &VirtualMachine, |
| 1171 | ) -> PyResult { |
| 1172 | let name_obj: PyObjectRef = name.clone().into(); |
| 1173 | |
| 1174 | // Update bases. |
| 1175 | let mut new_bases: Option<Vec<PyObjectRef>> = None; |
| 1176 | let bases = PyTuple::new_ref(bases.into_vec(), &vm.ctx); |
| 1177 | for (i, base) in bases.iter().enumerate() { |
| 1178 | if base.fast_isinstance(vm.ctx.types.type_type) { |
| 1179 | if let Some(bases) = &mut new_bases { |
| 1180 | bases.push(base.clone()); |
| 1181 | } |
| 1182 | continue; |
| 1183 | } |
| 1184 | let mro_entries = |
| 1185 | vm.get_attribute_opt(base.clone(), identifier!(vm, __mro_entries__))?; |
| 1186 | let entries = match mro_entries { |
| 1187 | Some(meth) => meth.call((bases.clone(),), vm)?, |
| 1188 | None => { |
| 1189 | if let Some(bases) = &mut new_bases { |
| 1190 | bases.push(base.clone()); |
| 1191 | } |
| 1192 | continue; |
| 1193 | } |
| 1194 | }; |
| 1195 | let entries: PyTupleRef = entries |
| 1196 | .downcast() |
| 1197 | .map_err(|_| vm.new_type_error("__mro_entries__ must return a tuple"))?; |
| 1198 | let new_bases = new_bases.get_or_insert_with(|| bases[..i].to_vec()); |
| 1199 | new_bases.extend_from_slice(&entries); |
| 1200 | } |
| 1201 | |
| 1202 | let new_bases = new_bases.map(|v| PyTuple::new_ref(v, &vm.ctx)); |
| 1203 | let (orig_bases, bases) = match new_bases { |
| 1204 | Some(new) => (Some(bases), new), |
| 1205 | None => (None, bases), |
| 1206 | }; |
| 1207 | |
| 1208 | // Use downcast_exact to keep ref to old object on error. |
| 1209 | let metaclass = kwargs |
| 1210 | .pop_kwarg("metaclass") |
| 1211 | .map(|metaclass| { |
| 1212 | metaclass |
| 1213 | .downcast_exact::<PyType>(vm) |
| 1214 | .map(|m| m.into_pyref()) |
| 1215 | }) |
| 1216 | .unwrap_or_else(|| { |
| 1217 | // if there are no bases, use type; else get the type of the first base |
| 1218 | Ok(if bases.is_empty() { |
| 1219 | vm.ctx.types.type_type.to_owned() |
| 1220 | } else { |
| 1221 | bases.first().unwrap().class().to_owned() |
| 1222 | }) |
nothing calls this directly
no test coverage detected