diff --git a/builtin/builtin.go b/builtin/builtin.go index b009090a..145da84c 100644 --- a/builtin/builtin.go +++ b/builtin/builtin.go @@ -44,7 +44,7 @@ func init() { // py.MustNewMethod("hex", builtin_hex, 0, hex_doc), // py.MustNewMethod("id", builtin_id, 0, id_doc), // py.MustNewMethod("input", builtin_input, 0, input_doc), - // py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc), + py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc), // py.MustNewMethod("issubclass", builtin_issubclass, 0, issubclass_doc), py.MustNewMethod("iter", builtin_iter, 0, iter_doc), py.MustNewMethod("len", builtin_len, 0, len_doc), @@ -826,6 +826,45 @@ object. The globals and locals are dictionaries, defaulting to the current globals and locals. If only globals is given, locals defaults to it.` +const isinstance_doc = `isinstance(obj, class_or_tuple) -> bool + +Return whether an object is an instance of a class or of a subclass thereof. + +A tuple, as in isinstance(x, (A, B, ...)), may be given as the target to +check against. This is equivalent to isinstance(x, A) or isinstance(x, B) +or ... etc. +` + +func isinstance(obj py.Object, classOrTuple py.Object) (py.Bool, error) { + switch classOrTuple.(type) { + case py.Tuple: + var class_tuple = classOrTuple.(py.Tuple) + for idx := range class_tuple { + res, _ := isinstance(obj, class_tuple[idx]) + if res { + return res, nil + } + } + return false, nil + default: + if classOrTuple.Type().ObjectType != py.TypeType { + return false, py.ExceptionNewf(py.TypeError, "isinstance() arg 2 must be a type or tuple of types") + } + return obj.Type() == classOrTuple, nil + } +} + +func builtin_isinstance(self py.Object, args py.Tuple) (py.Object, error) { + var obj py.Object + var classOrTuple py.Object + err := py.UnpackTuple(args, nil, "isinstance", 2, 2, &obj, &classOrTuple) + if err != nil { + return nil, err + } + + return isinstance(obj, classOrTuple) +} + const iter_doc = `iter(iterable) -> iterator iter(callable, sentinel) -> iterator diff --git a/vm/tests/builtin.py b/vm/tests/builtin.py index c50e1dd3..94f2e3a7 100644 --- a/vm/tests/builtin.py +++ b/vm/tests/builtin.py @@ -1,6 +1,7 @@ # Copyright 2018 The go-python Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +from libtest import assertRaises doc="eval" assert eval("1+2") == 3 @@ -65,4 +66,13 @@ else: assert False, "SyntaxError not raised" +doc="isinstance" +class A: + pass +a = A() +assert True, isinstance(1, (str, tuple, int)) +assert True, isinstance(a, (str, (tuple, (A, )))) +assertRaises(TypeError, isinstance, 1, (A, ), "foo") +assertRaises(TypeError, isinstance, 1, [A, "foo"]) + doc="finished" diff --git a/vm/tests/libtest.py b/vm/tests/libtest.py new file mode 100644 index 00000000..feebd7ee --- /dev/null +++ b/vm/tests/libtest.py @@ -0,0 +1,17 @@ +# Copyright 2018 The go-python Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +""" +Simple test harness +""" + +def assertRaises(expecting, fn, *args, **kwargs): + """Check the exception was raised - don't check the text""" + try: + fn(*args, **kwargs) + except expecting as e: + pass + else: + assert False, "%s not raised" % (expecting,) + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy