Determines if `self` is a subclass of `cls`, either directly, indirectly or virtually via the __subclasscheck__ magic method. PyObject_IsSubclass/object_issubclass
(&self, cls: &Self, vm: &VirtualMachine)
| 532 | /// via the __subclasscheck__ magic method. |
| 533 | /// PyObject_IsSubclass/object_issubclass |
| 534 | pub fn is_subclass(&self, cls: &Self, vm: &VirtualMachine) -> PyResult<bool> { |
| 535 | let derived = self; |
| 536 | // PyType_CheckExact(cls) |
| 537 | if cls.class().is(vm.ctx.types.type_type) { |
| 538 | if derived.is(cls) { |
| 539 | return Ok(true); |
| 540 | } |
| 541 | return derived.recursive_issubclass(cls, vm); |
| 542 | } |
| 543 | |
| 544 | // Check for Union type - CPython handles this before tuple |
| 545 | let cls = if cls.class().is(vm.ctx.types.union_type) { |
| 546 | // Get the __args__ attribute which contains the union members |
| 547 | // Match CPython's _Py_union_args which directly accesses the args field |
| 548 | let union = cls |
| 549 | .downcast_ref::<crate::builtins::PyUnion>() |
| 550 | .expect("union is already checked"); |
| 551 | union.args().as_object() |
| 552 | } else { |
| 553 | cls |
| 554 | }; |
| 555 | |
| 556 | // Check if cls is a tuple |
| 557 | if let Some(tuple) = cls.downcast_ref::<PyTuple>() { |
| 558 | for item in tuple { |
| 559 | if vm.with_recursion("in __subclasscheck__", || derived.is_subclass(item, vm))? { |
| 560 | return Ok(true); |
| 561 | } |
| 562 | } |
| 563 | return Ok(false); |
| 564 | } |
| 565 | |
| 566 | // Check for __subclasscheck__ method using lookup_special (matches CPython) |
| 567 | if let Some(checker) = cls.lookup_special(identifier!(vm, __subclasscheck__), vm) { |
| 568 | let res = vm.with_recursion("in __subclasscheck__", || { |
| 569 | checker.call((derived.to_owned(),), vm) |
| 570 | })?; |
| 571 | return res.try_to_bool(vm); |
| 572 | } |
| 573 | |
| 574 | derived.recursive_issubclass(cls, vm) |
| 575 | } |
| 576 | |
| 577 | // _PyObject_RealIsInstance |
| 578 | pub(crate) fn real_is_instance(&self, cls: &Self, vm: &VirtualMachine) -> PyResult<bool> { |
no test coverage detected