Skip to content

Commit 81dd5fa

Browse files
committed
Accept a tuple for the second argument of isinstance and issubclass
1 parent 2c7f3b5 commit 81dd5fa

File tree

3 files changed

+48
-14
lines changed

3 files changed

+48
-14
lines changed

tests/snippets/types_snippet.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
assert isinstance(type, type)
2828
assert issubclass(type, type)
2929

30+
assert not isinstance(type, (int, float))
31+
assert isinstance(type, (int, object))
32+
33+
assert not issubclass(type, (int, float))
34+
assert issubclass(type, (int, type))
35+
3036
class A: pass
3137
class B(A): pass
3238
class C(A): pass

vm/src/builtins.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ use crate::obj::objtype::{self, PyClassRef};
2020
use crate::frame::Scope;
2121
use crate::function::{Args, KwArgs, OptionalArg, PyFuncArgs};
2222
use crate::pyobject::{
23-
IdProtocol, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
23+
Either, IdProtocol, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
2424
TypeProtocol,
2525
};
2626
use crate::vm::VirtualMachine;
2727

2828
use crate::obj::objcode::PyCodeRef;
29+
use crate::obj::objtuple::PyTupleRef;
2930
#[cfg(not(target_arch = "wasm32"))]
3031
use crate::stdlib::io::io_open;
3132

@@ -312,19 +313,42 @@ fn builtin_id(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
312313

313314
// builtin_input
314315

315-
fn builtin_isinstance(obj: PyObjectRef, typ: PyClassRef, vm: &VirtualMachine) -> PyResult<bool> {
316-
vm.isinstance(&obj, &typ)
316+
fn builtin_isinstance(
317+
obj: PyObjectRef,
318+
typ: Either<PyClassRef, PyTupleRef>,
319+
vm: &VirtualMachine,
320+
) -> PyResult<bool> {
321+
match typ {
322+
Either::A(ref cls) => vm.isinstance(&obj, cls),
323+
Either::B(ref tuple) => {
324+
for cls_obj in tuple.elements.borrow().iter() {
325+
let cls = PyClassRef::try_from_object(vm, cls_obj.clone())?;
326+
if vm.isinstance(&obj, &cls)? {
327+
return Ok(true);
328+
}
329+
}
330+
Ok(false)
331+
}
332+
}
317333
}
318334

319-
fn builtin_issubclass(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
320-
arg_check!(
321-
vm,
322-
args,
323-
required = [(subclass, Some(vm.get_type())), (cls, Some(vm.get_type()))]
324-
);
325-
326-
let issubclass = vm.issubclass(subclass, cls)?;
327-
Ok(vm.context().new_bool(issubclass))
335+
fn builtin_issubclass(
336+
subclass: PyClassRef,
337+
typ: Either<PyClassRef, PyTupleRef>,
338+
vm: &VirtualMachine,
339+
) -> PyResult<bool> {
340+
match typ {
341+
Either::A(ref cls) => vm.issubclass(&subclass, cls),
342+
Either::B(ref tuple) => {
343+
for cls_obj in tuple.elements.borrow().iter() {
344+
let cls = PyClassRef::try_from_object(vm, cls_obj.clone())?;
345+
if vm.issubclass(&subclass, &cls)? {
346+
return Ok(true);
347+
}
348+
}
349+
Ok(false)
350+
}
351+
}
328352
}
329353

330354
fn builtin_iter(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {

vm/src/vm.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,12 @@ impl VirtualMachine {
304304

305305
/// Determines if `subclass` is a subclass of `cls`, either directly, indirectly or virtually
306306
/// via the __subclasscheck__ magic method.
307-
pub fn issubclass(&self, subclass: &PyObjectRef, cls: &PyObjectRef) -> PyResult<bool> {
308-
let ret = self.call_method(cls, "__subclasscheck__", vec![subclass.clone()])?;
307+
pub fn issubclass(&self, subclass: &PyClassRef, cls: &PyClassRef) -> PyResult<bool> {
308+
let ret = self.call_method(
309+
cls.as_object(),
310+
"__subclasscheck__",
311+
vec![subclass.clone().into_object()],
312+
)?;
309313
objbool::boolval(self, ret)
310314
}
311315

0 commit comments

Comments
 (0)