Repository: numba/numba

Issue:
Untyped global name 'prange': cannot determine Numba type of <class 'numba.ir.UndefinedType'>
```python
@jit(nopython=True, parallel=True)
def pos_stream(pos, vel, acc, dt):
	pos_new = np.zeros((N,1))			
	for i in prange(N):
		pos_new[i,0] = pos[i,0] + vel[i,0]*dt + 0.5*acc*(dt**2)
	return pos_new
```
trying to run this code in parallel and got below error:
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'prange': cannot determine Numba type of <class 'numba.ir.UndefinedType'>

File "Poisseuille_Compile.py", line 36:
def pos_stream(pos, vel, acc, dt):
    <source elided>
	pos_new = np.zeros((N,1))			
	for i in prange(N):
 ^

This is not usually a problem with Numba itself but instead often caused by
the use of unsupported features or an issue in resolving types.

To see Python/NumPy features supported by the latest release of Numba visit:
http://numba.pydata.org/numba-doc/dev/reference/pysupported.html
and
http://numba.pydata.org/numba-doc/dev/reference/numpysupported.html

For more information about typing errors and how to debug them visit:
http://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-doesn-t-compile

If you think your code should work with Numba, please report the error message
and traceback, along with a minimal reproducer at:
https://github.com/numba/numba/issues/new

then removed nopython=True and got this error

global name 'prange' is not defined



Discussion:
Thanks for the report. To use `prange` it needs to be imported from the `numba` module like `from numba import prange`. This works:
```python
from numba import jit, prange
import numpy as np

N = 10

@jit(nopython=True, parallel=True)
def pos_stream(pos, vel, acc, dt):
    pos_new = np.zeros((N, 1))
    for i in prange(N):
        pos_new[i,0] = pos[i,0] + vel[i,0]*dt + 0.5*acc*(dt**2)
    return pos_new

pos_stream(np.zeros((N, 1)), np.zeros((N, 1)), 1.0, 2.0)
```

Resolving patch:
diff --git a/numba/typeinfer.py b/numba/typeinfer.py
--- a/numba/typeinfer.py
+++ b/numba/typeinfer.py
@@ -1323,8 +1323,19 @@ def typeof_global(self, inst, target, gvar):
                 # as a global variable
                 typ = types.Dispatcher(_temporary_dispatcher_map[gvar.name])
             else:
-                msg = _termcolor.errmsg("Untyped global name '%s':") + " %s"
-                e.patch_message(msg % (gvar.name, e))
+                nm = gvar.name
+                msg = _termcolor.errmsg("Untyped global name '%s':" % nm)
+                msg += " %s" # interps the actual error
+
+                # if the untyped global is a numba internal function then add
+                # to the error message asking if it's been imported.
+                from numba import special
+                if nm in special.__all__:
+                    tmp = ("\n'%s' looks like a Numba internal function, has "
+                           "it been imported (i.e. 'from numba import %s')?\n" %
+                           (nm, nm))
+                    msg += _termcolor.errmsg(tmp)
+                e.patch_message(msg % e)
                 raise
 
         if isinstance(typ, types.Dispatcher) and typ.dispatcher.is_compiling:


Test patch:
diff --git a/numba/tests/test_errorhandling.py b/numba/tests/test_errorhandling.py
--- a/numba/tests/test_errorhandling.py
+++ b/numba/tests/test_errorhandling.py
@@ -8,6 +8,8 @@
 from numba import errors, utils
 import numpy as np
 
+from .support import skip_parfors_unsupported
+
 # used in TestMiscErrorHandling::test_handling_of_write_to_*_global
 _global_list = [1, 2, 3, 4]
 _global_dict = typed.Dict.empty(int64, int64)
@@ -152,6 +154,20 @@ def foo():
 
         self.check_write_to_globals(foo)
 
+    @skip_parfors_unsupported
+    def test_handling_forgotten_numba_internal_import(self):
+        @njit(parallel=True)
+        def foo():
+            for i in prange(10): # prange is not imported
+                pass
+
+        with self.assertRaises(errors.TypingError) as raises:
+            foo()
+
+        expected = ("'prange' looks like a Numba internal function, "
+                    "has it been imported")
+        self.assertIn(expected, str(raises.exception))
+
 
 class TestConstantInferenceErrorHandling(unittest.TestCase):