RussBaz / enforce

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

When passing a callable object to a Callable argument, validate on object.__call__ instead of object #27

Closed hwayne closed 7 years ago

hwayne commented 7 years ago

Ideally, an object that implements the __call__ method should be usable in any place a regular function can be used. Right now, though, runtime_validation will not accept callable objects for a Callable argument. This fixes and adds tests. Since the change happens in CallableNode other type validations (for example, that you're passing in an object) are unaffected.

Example:

>>> from enforce import runtime_validation
>>> from typing import Callable
>>>
>>> class Foo:
...     def __call__(self, a: int) -> str:
...       return str(2*a)
...
>>> @runtime_validation
... def class_name(a: Foo) -> str:
...     return str(a.__class__)
...
>>> @runtime_validation
... def run_function(f: typing.Callable[[int], str], b: int) -> str:
...     return f(b)
...
>>> print(class_name(Foo())) # Foo() can be read as an object of class 'Foo'
<class '__main__.Foo'>
>>> print(run_function(Foo(), 5)) # Foo() can now also be read as a callable
10
coveralls commented 7 years ago

Coverage Status

Coverage remained the same at 95.757% when pulling 9b55bbd5c6974aca224309b9f6fef75985e6d8a2 on hwayne:callable-objects into 67b14610d4e7fa1867f2e1719ae1c80817a8010f on RussBaz:dev.