import gc import itertools import numpy as np import unittest from numba import jit, njit from numba.core import types from numba.tests.support import TestCase from numba.np import numpy_support def identity(x): return x def addition(x, y): return x + y def equality(x, y): return x == y def foobar(x, y, z): return x class TestConversion(TestCase): """ Testing Python to Native conversion """ def test_complex_identity(self): pyfunc = identity cfunc = njit(types.complex64(types.complex64))(pyfunc) xs = [1.0j, (1+1j), (-1-1j), (1+0j)] for x in xs: self.assertEqual(cfunc(x), x) for x in np.complex64(xs): self.assertEqual(cfunc(x), x) cfunc = njit(types.complex128(types.complex128))(pyfunc) xs = [1.0j, (1+1j), (-1-1j), (1+0j)] for x in xs: self.assertEqual(cfunc(x), x) for x in np.complex128(xs): self.assertEqual(cfunc(x), x) def test_complex_addition(self): pyfunc = addition cfunc = njit(types.complex64(types.complex64, types.complex64))(pyfunc) xs = [1.0j, (1+1j), (-1-1j), (1+0j)] for x in xs: y = x self.assertEqual(cfunc(x, y), x + y) for x in np.complex64(xs): y = x self.assertEqual(cfunc(x, y), x + y) cfunc = njit(types.complex128(types.complex128, types.complex128))(pyfunc) xs = [1.0j, (1+1j), (-1-1j), (1+0j)] for x in xs: y = x self.assertEqual(cfunc(x, y), x + y) for x in np.complex128(xs): y = x self.assertEqual(cfunc(x, y), x + y) def test_boolean_as_int(self): pyfunc = equality cfunc = njit((types.boolean, types.intp))(pyfunc) xs = True, False ys = -1, 0, 1 for xs, ys in itertools.product(xs, ys): self.assertEqual(pyfunc(xs, ys), cfunc(xs, ys)) def test_boolean_as_float(self): pyfunc = equality cfunc = njit((types.boolean, types.float64))(pyfunc) xs = True, False ys = -1, 0, 1 for xs, ys in itertools.product(xs, ys): self.assertEqual(pyfunc(xs, ys), cfunc(xs, ys)) def test_boolean_eq_boolean(self): pyfunc = equality cfunc = njit((types.boolean, types.boolean))(pyfunc) xs = True, False ys = True, False for xs, ys in itertools.product(xs, ys): self.assertEqual(pyfunc(xs, ys), cfunc(xs, ys)) # test when a function parameters are jitted as unsigned types # the function is called with negative parameters the Python error # that it generates is correctly handled -- a Python error is returned to the user # For more info, see the comment in Include/longobject.h for _PyArray_AsByteArray # which PyLong_AsUnsignedLongLong calls def test_negative_to_unsigned(self): def f(x): return x with self.assertRaises(OverflowError): jit('uintp(uintp)', nopython=True)(f)(-5) # test the switch logic in callwraper.py:build_wrapper() works for more than one argument # and where the error occurs def test_multiple_args_negative_to_unsigned(self): pyfunc = foobar cfunc = njit(types.uint64(types.uint64, types.uint64, types.uint64),)(pyfunc) test_fail_args = ((-1, 0, 1), (0, -1, 1), (0, 1, -1)) with self.assertRaises(OverflowError): for a, b, c in test_fail_args: cfunc(a, b, c) # test switch logic of callwraper.py:build_wrapper() with records as function parameters def test_multiple_args_records(self): pyfunc = foobar mystruct_dt = np.dtype([('p', np.float64), ('row', np.float64), ('col', np.float64)]) mystruct = numpy_support.from_dtype(mystruct_dt) cfunc = njit(mystruct[:](mystruct[:], types.uint64, types.uint64),)(pyfunc) st1 = np.recarray(3, dtype=mystruct_dt) st1.p = np.arange(st1.size) + 1 st1.row = np.arange(st1.size) + 1 st1.col = np.arange(st1.size) + 1 with self.assertRefCount(st1): test_fail_args = ((st1, -1, 1), (st1, 1, -1)) for a, b, c in test_fail_args: with self.assertRaises(OverflowError): cfunc(a, b, c) del test_fail_args, a, b, c gc.collect() # test switch logic of callwraper.py:build_wrapper() with no function parameters def test_with_no_parameters(self): def f(): pass self.assertEqual(f(), jit('()', nopython=True)(f)()) def check_argument_cleanup(self, typ, obj): """ Check that argument cleanup doesn't leak references. """ def f(x, y): pass def _objects(obj): objs = [obj] if isinstance(obj, tuple): for v in obj: objs += _objects(v) return objs objects = _objects(obj) cfunc = njit((typ, types.uint32))(f) with self.assertRefCount(*objects): cfunc(obj, 1) with self.assertRefCount(*objects): with self.assertRaises(OverflowError): cfunc(obj, -1) cfunc = njit((types.uint32, typ))(f) with self.assertRefCount(*objects): cfunc(1, obj) with self.assertRefCount(*objects): with self.assertRaises(OverflowError): cfunc(-1, obj) def test_cleanup_buffer(self): mem = memoryview(bytearray(b"xyz")) self.check_argument_cleanup(types.MemoryView(types.byte, 1, 'C'), mem) def test_cleanup_record(self): dtype = np.dtype([('x', np.float64), ('y', np.float64)]) recarr = np.zeros(1, dtype=dtype) self.check_argument_cleanup(numpy_support.from_dtype(dtype), recarr[0]) def test_cleanup_tuple(self): mem = memoryview(bytearray(b"xyz")) tp = types.UniTuple(types.MemoryView(types.byte, 1, 'C'), 2) self.check_argument_cleanup(tp, (mem, mem)) def test_cleanup_optional(self): mem = memoryview(bytearray(b"xyz")) tp = types.Optional(types.MemoryView(types.byte, 1, 'C')) self.check_argument_cleanup(tp, mem) def test_stringliteral_to_unicode(self): # See issue #6907, explicit signature on bar() takes a unicode_type but # the call to bar() in foo() is with a StringLiteral @jit(types.void(types.unicode_type), nopython=True) def bar(string): pass @jit(types.void(), nopython=True) def foo2(): bar("literal string") if __name__ == '__main__': unittest.main()