Repository: numba/numba

Issue:
typing error numpy.shape "not supported" 
```
using spyder 3.3.4, python 3.7.0 in anaconda environment 1.9.7 on OS X 10.14.4 (mojave)
get this:
TypingError: Use of unsupported NumPy function 'numpy.shape' or unsupported use of the function.
File "testcode.py", line 23:
def ggp_timestep(g, Pfr):
    <source elided>
    sg=np.shape(g)       #this is line 23 in testcode.py
    thearr = np.random.rand(sg[0], sg[1])
```



Come on guys, it says over and over in the reference manual that shape is a supported numpy function.



Discussion:
File "testcode.py", line 23:
def ggp_timestep(g, Pfr):
    <source elided>
    sg=np.shape(g)
    thearr = np.random.rand(sg[0], sg[1])
    ^

[1] During: typing of get attribute at /Users/dpg/jobs/ameresco/new heather project/testcode.py (23)

File "testcode.py", line 23:
def ggp_timestep(g, Pfr):
    <source elided>
    sg=np.shape(g)   #this is line 23 in testcode.py
    thearr = np.random.rand(sg[0], sg[1])
NOTE. Edited original markdown as it was pasted into the commented out instruction section.

RE formatting in GitHub issues, for future reference triple backticks are needed around a code block (with optional language syntax specified), for example: ` ```python <your code> ``` `. GitHub also has a basic guide to its markdown syntax available [here](https://help.github.com/articles/basic-writing-and-formatting-syntax).
Thanks for the report. I don't believe it says in the documentation that the NumPy module function `shape` (i.e. `np.shape`) is supported, if it does please could you point to where, this is probably an error. The `numpy.ndarray.shape` attribute is supported, this is functionally equivalent but not the same as the use of the module level function. i.e.:
```python
from numba import njit
import numpy as np

@njit
def foo(x):
    return x.shape

@njit
def bar(x):
    return np.shape(x)

print(foo(np.arange(12).reshape(3, 4))) # returns (3, 4)
print(bar(np.arange(12).reshape(3, 4))) # error, not supported
```

Resolving patch:
diff --git a/numba/numpy_support.py b/numba/numpy_support.py
--- a/numba/numpy_support.py
+++ b/numba/numpy_support.py
@@ -594,3 +594,11 @@ def is_fortran(dims, strides, itemsize):
             return False
         ax += 1
     return True
+
+
+def type_can_asarray(arr):
+    """ Returns True if the type of 'arr' is supported by the Numba `np.asarray`
+    implementation, False otherwise.
+    """
+    ok = (types.Array, types.Sequence, types.Tuple, types.Number, types.Boolean)
+    return isinstance(arr, ok)
diff --git a/numba/targets/arraymath.py b/numba/targets/arraymath.py
--- a/numba/targets/arraymath.py
+++ b/numba/targets/arraymath.py
@@ -17,7 +17,7 @@
 
 from numba import types, cgutils, typing, generated_jit
 from numba.extending import overload, overload_method, register_jitable
-from numba.numpy_support import as_dtype
+from numba.numpy_support import as_dtype, type_can_asarray
 from numba.numpy_support import version as numpy_version
 from numba.targets.imputils import (lower_builtin, impl_ret_borrowed,
                                     impl_ret_new_ref, impl_ret_untracked)
@@ -3422,6 +3422,12 @@ def _is_nonelike(ty):
 
 @overload(np.asarray)
 def np_asarray(a, dtype=None):
+
+    # developer note... keep this function (type_can_asarray) in sync with the
+    # accepted types implementations below!
+    if not type_can_asarray(a):
+        return None
+
     impl = None
     if isinstance(a, types.Array):
         if _is_nonelike(dtype) or a.dtype == dtype.dtype:
diff --git a/numba/targets/arrayobj.py b/numba/targets/arrayobj.py
--- a/numba/targets/arrayobj.py
+++ b/numba/targets/arrayobj.py
@@ -19,6 +19,7 @@
 from numba.numpy_support import (as_dtype, carray, farray, is_contiguous,
                                  is_fortran)
 from numba.numpy_support import version as numpy_version
+from numba.numpy_support import type_can_asarray
 from numba.targets.imputils import (lower_builtin, lower_getattr,
                                     lower_getattr_generic,
                                     lower_setattr_generic,
@@ -1832,6 +1833,18 @@ def imp(nd, dims, strides, old_itemsize, new_itemsize, layout):
     return res
 
 
+@overload(np.shape)
+def np_shape(a):
+    if not type_can_asarray(a):
+        raise errors.TypingError("The argument to np.shape must be array-like")
+
+    def impl(a):
+        return np.asarray(a).shape
+    return impl
+
+#-------------------------------------------------------------------------------
+
+
 @overload(np.unique)
 def np_unique(a):
     def np_unique_impl(a):
@@ -3694,6 +3707,7 @@ def arange(start, stop, step):
     res = context.compile_internal(builder, arange, sig, args)
     return impl_ret_new_ref(context, builder, sig.return_type, res)
 
+
 @lower_builtin(np.arange, types.Number, types.Number,
                types.Number, types.DTypeSpec)
 def numpy_arange_4(context, builder, sig, args):


Test patch:
diff --git a/numba/tests/test_array_manipulation.py b/numba/tests/test_array_manipulation.py
--- a/numba/tests/test_array_manipulation.py
+++ b/numba/tests/test_array_manipulation.py
@@ -132,6 +132,10 @@ def numpy_fill_diagonal(arr, val, wrap=False):
     return np.fill_diagonal(arr, val, wrap)
 
 
+def numpy_shape(arr):
+    return np.shape(arr)
+
+
 class TestArrayManipulation(MemoryLeakMixin, TestCase):
     """
     Check shape-changing operations on arrays.
@@ -708,5 +712,30 @@ def _assert_raises(arr, val):
         _assert_raises(arr, val)
 
 
+    def test_shape(self):
+        pyfunc = numpy_shape
+        cfunc = jit(nopython=True)(pyfunc)
+
+        def check(x):
+            expected = pyfunc(x)
+            got = cfunc(x)
+            self.assertPreciseEqual(got, expected)
+
+        # check arrays
+        for t in [(), (1,), (2, 3,), (4, 5, 6)]:
+            arr = np.empty(t)
+            check(arr)
+
+        # check some types that go via asarray
+        for t in [1, False, [1,], [[1, 2,],[3, 4]], (1,), (1, 2, 3)]:
+            check(arr)
+
+        with self.assertRaises(TypingError) as raises:
+            cfunc('a')
+
+        self.assertIn("The argument to np.shape must be array-like",
+                      str(raises.exception))
+
+
 if __name__ == '__main__':
     unittest.main()