Repository: numba/numba

Issue:
Fix needed for invalid signature specification error message
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->

## Feature request

<!--

Please include details of the feature you would like to see, why you would
like to see it/the use case

-->

```python
from numba import njit
@njit(['f8',])
def foo(a):
    return 1
```
the above is invalid as the signature makes no sense, however the error message says:
```
  File "gi53.py", line 20, in <module>
    @njit(['f8',])
  File "<path>/numba/numba/decorators.py", line 183, in wrapper
    disp.compile(sig)
  File "<path>/numba/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "<path>/numba/numba/dispatcher.py", line 641, in compile
    args, return_type = sigutils.normalize_signature(sig)
  File "<path>/numba/numba/sigutils.py", line 35, in normalize_signature
    % (sig.__class__.__name__,))
TypeError: invalid signature: 'str' instance not allowed
```
fix this so it reports something more useful!


Discussion:
Hi @stuartarchibald, can I try to fix this?
@PGryllos that would be great, thanks... I think that the error message needs to report the input that was invalid along with the output of parsing the input and feed this back to the user, thoughts?
If I have understood correctly the problem here is that we are feeding a str instead of a valid signature type where something like that

```python
@njit(["(f8,)"])
def foo(a):
    return 1
```
is valid

> I think that the error message needs to report the input that was invalid

@stuartarchibald the existing msg suffices for this part, right? It says str type cannot be interpreted as a signature; If I look into the compilation the `normalise_signature` outputs that when encountering something other than a tuple of a `Signature`. Or do you mean that it should instead say something like `"f8" is of type str that cannot be interpreter as a signature`?

>  the output of parsing the input 

As far as I can understand this should be the output of `normalise_signature` ?
The following has a signature supplied as a string, the signature is invalid.
```python
from numba import njit
@njit(['f8',])
def foo(a):
    return 1
```
which gives the error message:
```
TypeError: invalid signature: 'str' instance not allowed
```
but this doesn't make sense, because the problem isn't that the signature is specified as a string instance, it's that it is invalid as a signature.

Conversely:
```python
from numba import njit
@njit(['(f8,)',])
def foo(a):
    return 1
```
works fine, it's a signature specified as a string but this time is slightly more valid.

> Or do you mean that it should instead say something like "f8" is of type str that cannot be interpreter as a signature?

I think that something along these lines would be most appropriate, there is nothing wrong with passing in a string for a signature, it's just that the string has to evaluate to something valid.

@stuartarchibald okay, now I fully understood your point. 

would this msg be closer?

> TypeError: invalid signature: 'str' instance evaluates to 'Float' instead of tuple or Signature
I think something along those makes sense, including the invalid input and what it evaluates to along with fundamentally what the problem is in the error message is a good idea.

Resolving patch:
diff --git a/numba/sigutils.py b/numba/sigutils.py
--- a/numba/sigutils.py
+++ b/numba/sigutils.py
@@ -31,13 +31,16 @@ def normalize_signature(sig):
     elif isinstance(parsed, typing.Signature):
         args, return_type = parsed.args, parsed.return_type
     else:
-        raise TypeError("invalid signature: %r instance not allowed"
-                        % (sig.__class__.__name__,))
+        raise TypeError("invalid signature: %r (type: %r) evaluates to %r "
+                        "instead of tuple or Signature" % (
+                            sig, sig.__class__.__name__,
+                            parsed.__class__.__name__
+                        ))
 
     def check_type(ty):
         if not isinstance(ty, types.Type):
-            raise TypeError("invalid signature: expected a type instance, "
-                            "got %r" % (ty,))
+            raise TypeError("invalid type in signature: expected a type "
+                            "instance, got %r" % (ty,))
 
     if return_type is not None:
         check_type(return_type)


Test patch:
diff --git a/numba/tests/test_types.py b/numba/tests/test_types.py
--- a/numba/tests/test_types.py
+++ b/numba/tests/test_types.py
@@ -498,8 +498,9 @@ def check_error(sig, msg):
         check("(complex64, int16)", (c64, i16), None)
         check(typing.signature(i16, c64), (c64,), i16)
 
-        check_error((types.Integer,), "invalid signature")
-        check_error((None,), "invalid signature")
+        msg = "invalid type in signature: expected a type instance"
+        check_error((types.Integer,), msg)
+        check_error((None,), msg)
         check_error([], "invalid signature")