RussBaz / enforce

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

How to use Generics? #51

Open justuswilhelm opened 6 years ago

justuswilhelm commented 6 years ago

In mypy you can use this

import typing

def returns_dict() -> typing.Mapping:
    return dict()

returns_dict()

And it validates just fine.

But with enforce I get a strange result

import enforce
import typing

@enforce.runtime_validation
def returns_dict() -> typing.Mapping:
    return dict

returns_dict()

Seemingly, the generic type handling is different in enforce.

Traceback (most recent call last):                
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/nodes.py", line 539, in preprocess_data
    enforcer = data.__enforcer__                  
AttributeError: type object 'dict' has no attribute '__enforcer__'                                   

During handling of the above exception, another exception occurred:                                  

Traceback (most recent call last):                
  File "test.py", line 10, in <module>            
    returns_dict()       
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/decorators.py", line 118, in universal
    return enforcer.validate_outputs(result)      
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/enforcers.py", line 96, in validate_outputs
    if not self.validator.validate(output_data, 'return'):                                           
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/validator.py", line 26, in validate
    validation_result = visit(validation_tree)    
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/utils.py", line 17, in visit
    stack.append(last.send(last_result))          
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/nodes.py", line 64, in validate
    clean_data = self.preprocess_data(validator, data)                                               
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/nodes.py", line 541, in preprocess_data
    return GenericProxy(data)                     
  File "/Users/XXX/enforce-test/env/lib/python3.6/site-packages/enforce/enforcers.py", line 130, in __init__
    raise TypeError('Only generics can be wrapped in GenericProxy')                                  
TypeError: Only generics can be wrapped in GenericProxy    

What's the best way to get a similar behavior to mypy?

RussBaz commented 6 years ago

Well, you are not returning a dictionary in your second example. The return value is a function which returns a dictionary. Is it a typo or is it what you intended?

justuswilhelm commented 6 years ago

Sorry, that was a typo in my post above. The method should return dict(). I tried return a dict type just now, and that does not change the error message. Which makes sense, since the decorator phase fails, not the execution phase.