import math import re import textwrap import operator import numpy as np import unittest from numba.core.compiler import compile_isolated from numba import jit from numba.core import types from numba.core.errors import TypingError from numba.core.types.functions import _header_lead from numba.tests.support import TestCase def what(): pass def foo(): return what() def bar(x): return x.a def issue_868(a): return a.shape * 2 def impossible_return_type(x): if x > 0: return () else: return 1j def bad_hypot_usage(): return math.hypot(1) def imprecise_list(): l = [] return len(l) def using_imprecise_list(): a = np.array([]) return a.astype(np.int32) def unknown_module(): return numpyz.int32(0) def nop(x, y, z): pass def array_setitem_invalid_cast(): arr = np.empty(1, dtype=np.float64) arr[0] = 1j # invalid cast from complex to float return arr class Foo(object): def __repr__(self): return "" class TestTypingError(unittest.TestCase): def test_unknown_function(self): try: compile_isolated(foo, ()) except TypingError as e: self.assertIn("Untyped global name 'what'", str(e)) else: self.fail("Should raise error") def test_unknown_attrs(self): try: compile_isolated(bar, (types.int32,)) except TypingError as e: self.assertIn("Unknown attribute 'a' of type int32", str(e)) else: self.fail("Should raise error") def test_unknown_module(self): # This used to print "'object' object has no attribute 'int32'" with self.assertRaises(TypingError) as raises: compile_isolated(unknown_module, ()) self.assertIn("name 'numpyz' is not defined", str(raises.exception)) def test_issue_868(self): ''' Summary: multiplying a scalar by a non-scalar would cause a crash in type inference because TimeDeltaMixOp always assumed at least one of its operands was an NPTimeDelta in its generic() method. ''' with self.assertRaises(TypingError) as raises: compile_isolated(issue_868, (types.Array(types.int32, 1, 'C'),)) expected = ((_header_lead + " Function() found " "for signature:\n \n >>> mul(UniTuple({} x 1), {})") .format(str(types.intp), types.IntegerLiteral(2))) self.assertIn(expected, str(raises.exception)) self.assertIn("During: typing of", str(raises.exception)) def test_return_type_unification(self): with self.assertRaises(TypingError) as raises: compile_isolated(impossible_return_type, (types.int32,)) msg = ("Can't unify return type from the following types: Tuple(), " "complex128") self.assertIn(msg, str(raises.exception)) def test_bad_hypot_usage(self): with self.assertRaises(TypingError) as raises: compile_isolated(bad_hypot_usage, ()) errmsg = str(raises.exception) # Make sure it listed the known signatures. # This is sensitive to the formatting of the error message. self.assertIn(" * (float64, float64) -> float64", errmsg) # find the context lines ctx_lines = [x for x in errmsg.splitlines() if "During:" in x ] # Check contextual msg self.assertTrue(re.search(r'.*During: resolving callee type: Function.*hypot', ctx_lines[0])) self.assertTrue(re.search(r'.*During: typing of call .*test_typingerror.py', ctx_lines[1])) def test_imprecise_list(self): """ Type inference should catch that a list type's remain imprecise, instead of letting lowering fail. """ with self.assertRaises(TypingError) as raises: compile_isolated(imprecise_list, ()) errmsg = str(raises.exception) msg = ("Cannot infer the type of variable 'l', have imprecise type: " "list(undefined)") self.assertIn(msg, errmsg) # check help message has gone in self.assertIn("For Numba to be able to compile a list", errmsg) def test_using_imprecise_list(self): """ Type inference should report informative error about untyped list. TODO: #2931 """ with self.assertRaises(TypingError) as raises: compile_isolated(using_imprecise_list, ()) errmsg = str(raises.exception) self.assertIn("Undecided type", errmsg) def test_array_setitem_invalid_cast(self): with self.assertRaises(TypingError) as raises: compile_isolated(array_setitem_invalid_cast, ()) errmsg = str(raises.exception) self.assertIn( _header_lead + " Function({})".format(operator.setitem), errmsg, ) self.assertIn( "(array(float64, 1d, C), Literal[int](0), complex128)", errmsg, ) def test_template_rejection_error_message_cascade(self): from numba import njit @njit def foo(): z = 1 for a, b in enumerate(z): pass return z with self.assertRaises(TypingError) as raises: foo() errmsg = str(raises.exception) expected = "No match." self.assertIn(expected, errmsg) ctx_lines = [x for x in errmsg.splitlines() if "During:" in x ] search = [r'.*During: resolving callee type: Function.*enumerate', r'.*During: typing of call .*test_typingerror.py'] for i, x in enumerate(search): self.assertTrue(re.search(x, ctx_lines[i])) class TestArgumentTypingError(unittest.TestCase): """ Test diagnostics of typing errors caused by argument inference failure. """ def test_unsupported_array_dtype(self): # See issue #1943 cfunc = jit(nopython=True)(nop) a = np.ones(3) a = a.astype(a.dtype.newbyteorder()) with self.assertRaises(TypingError) as raises: cfunc(1, a, a) expected = f"Unsupported array dtype: {a.dtype}" self.assertIn(expected, str(raises.exception)) def test_unsupported_type(self): cfunc = jit(nopython=True)(nop) foo = Foo() with self.assertRaises(TypingError) as raises: cfunc(1, foo, 1) expected=re.compile(("This error may have been caused by the following " "argument\(s\):\\n- argument 1:.*Cannot determine " "Numba type of " "")) self.assertTrue(expected.search(str(raises.exception)) is not None) class TestCallError(unittest.TestCase): def test_readonly_array(self): @jit("(f8[:],)", nopython=True) def inner(x): return x @jit(nopython=True) def outer(): return inner(gvalues) gvalues = np.ones(10, dtype=np.float64) with self.assertRaises(TypingError) as raises: outer() got = str(raises.exception) pat = r"Invalid use of.*readonly array\(float64, 1d, C\)" self.assertIsNotNone(re.search(pat, got)) if __name__ == '__main__': unittest.main()