diff --git a/tests/snippets/builtin_callable.py b/tests/snippets/builtin_callable.py new file mode 100644 index 000000000..c22db0779 --- /dev/null +++ b/tests/snippets/builtin_callable.py @@ -0,0 +1,26 @@ +assert not callable(1) +def f(): pass +# TODO uncomment when callable types get unified __call__ (or equivalent) +#assert callable(f) +#assert callable(len) +#assert callable(lambda: 1) +assert callable(int) + +class C: + def __init__(self): + # must be defined on class + self.__call__ = lambda self: 1 + def f(self): pass +assert callable(C) +assert not callable(C()) +#assert callable(C().f) + +class C: + def __call__(self): pass +assert callable(C()) +class C1(C): pass +assert callable(C1()) +class C: + __call__ = 1 +# CPython returns true here, but fails when actually calling it +assert callable(C()) diff --git a/tests/snippets/weakrefs.py b/tests/snippets/weakrefs.py index 81f3b46c5..ffc61f427 100644 --- a/tests/snippets/weakrefs.py +++ b/tests/snippets/weakrefs.py @@ -8,5 +8,6 @@ class X: a = X() b = ref(a) +assert callable(b) assert b() is a diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 4de79ba25..b8e4ca638 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -101,8 +101,7 @@ fn builtin_bin(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn builtin_callable(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, None)]); - // TODO: is this a sufficiently thorough check? - let is_callable = obj.has_attr("__call__"); + let is_callable = obj.typ().has_attr("__call__"); Ok(vm.new_bool(is_callable)) }