(
cls: PyObjectRef,
subclass: PyObjectRef,
vm: &VirtualMachine,
)
| 320 | /// Internal ABC helper for subclass checks. Should be never used outside abc module. |
| 321 | #[pyfunction] |
| 322 | fn _abc_subclasscheck( |
| 323 | cls: PyObjectRef, |
| 324 | subclass: PyObjectRef, |
| 325 | vm: &VirtualMachine, |
| 326 | ) -> PyResult<bool> { |
| 327 | // Type check |
| 328 | if !subclass.class().fast_issubclass(vm.ctx.types.type_type) { |
| 329 | return Err(vm.new_type_error("issubclass() arg 1 must be a class")); |
| 330 | } |
| 331 | |
| 332 | let impl_data = get_impl(&cls, vm)?; |
| 333 | |
| 334 | // 1. Check cache |
| 335 | if in_weak_set(&impl_data.cache, &subclass, vm)? { |
| 336 | return Ok(true); |
| 337 | } |
| 338 | |
| 339 | // 2. Check negative cache; may have to invalidate |
| 340 | let invalidation_counter = get_invalidation_counter(); |
| 341 | if impl_data.get_cache_version() < invalidation_counter { |
| 342 | // Invalidate the negative cache |
| 343 | // Clone set ref and drop lock before calling into VM to avoid reentrancy |
| 344 | let set = impl_data.negative_cache.read().clone(); |
| 345 | if let Some(ref set) = set { |
| 346 | vm.call_method(set.as_ref(), "clear", ())?; |
| 347 | } |
| 348 | impl_data.set_cache_version(invalidation_counter); |
| 349 | } else if in_weak_set(&impl_data.negative_cache, &subclass, vm)? { |
| 350 | return Ok(false); |
| 351 | } |
| 352 | |
| 353 | // 3. Check the subclass hook |
| 354 | let ok = vm.call_method(&cls, "__subclasshook__", (subclass.clone(),))?; |
| 355 | if ok.is(&vm.ctx.true_value) { |
| 356 | add_to_weak_set(&impl_data.cache, &subclass, vm)?; |
| 357 | return Ok(true); |
| 358 | } |
| 359 | if ok.is(&vm.ctx.false_value) { |
| 360 | add_to_weak_set(&impl_data.negative_cache, &subclass, vm)?; |
| 361 | return Ok(false); |
| 362 | } |
| 363 | if !ok.is(&vm.ctx.not_implemented) { |
| 364 | return Err(vm.new_exception_msg( |
| 365 | vm.ctx.exceptions.assertion_error.to_owned(), |
| 366 | "__subclasshook__ must return either False, True, or NotImplemented".into(), |
| 367 | )); |
| 368 | } |
| 369 | |
| 370 | // 4. Check if it's a direct subclass |
| 371 | let subclass_type: PyTypeRef = subclass |
| 372 | .clone() |
| 373 | .downcast() |
| 374 | .map_err(|_| vm.new_type_error("expected a type object"))?; |
| 375 | let cls_type: PyTypeRef = cls |
| 376 | .clone() |
| 377 | .downcast() |
| 378 | .map_err(|_| vm.new_type_error("expected a type object"))?; |
| 379 | if subclass_type.fast_issubclass(&cls_type) { |
no test coverage detected