RussBaz / enforce

Python 3.5+ runtime type checking for integration testing and data validation
543 stars 21 forks source link

Enforce throws TypeError when calling instance method with forgotten `self` #49

Open justuswilhelm opened 6 years ago

justuswilhelm commented 6 years ago

I have had this obscure problem, which I would call a bug since one would expect to get a proper error message like Python 3 normally does.

I use

class A:
    def hello():
        print("Hello, World!")

a = A()
# Traceback (most recent call last):
#   File "example.py", line 13, in <module>
#     a.hello()
#   File "example.py", line 4, in hello
#     print("Hello, " + b.world())
# TypeError: world() takes 0 positional arguments but 1 was given
try:
    a.hello()
except TypeError:
    print("Error caught correctly")

# But now

import enforce

@enforce.runtime_validation
class BadA:
    def hello():
        print("Hello, ")

a = BadA()
a.hello()

will output

Error caught correctly   
Traceback (most recent call last):                
  File "example.py", line 30, in <module>         
    a.hello()            
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/decorators.py", line 104, in universal
    _args, _kwargs, _ = enforcer.validate_inputs(parameters)                                         
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/enforcers.py", line 71, in validate_inputs
    binded_arguments = self.signature.bind(*args, **kwargs)                                          
  File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/inspect.py", line 2933, in bind
    return args[0]._bind(args[1:], kwargs)        
  File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/inspect.py", line 2854, in _bind
    raise TypeError('too many positional arguments') from None                                       
TypeError: too many positional arguments    
RussBaz commented 6 years ago

As a rule of thumb, one should not expect to get the same exception message from the decorated function as if it was not.

It still gives the correct exception type, however, but totally unintuitive stacktrace.

I agree this seems like a very likely place to run into exceptions. I will have a look if anything can be done about the clarity of such exceptions at this moment.

Thanks.