Closed RussBaz closed 8 years ago
I think a related bug is that function types are not handled correctly either. A minimum example is
import typing
import enforce
@enforce.runtime_validation
def foo(func: typing.Callable[[int], str], bar: int) -> str:
return func(bar)
foo(lambda x: str(x), 5)
According to the typing documentation, that should be the correct syntax, but enforce
thinks it's an error.
Edit: Here's the output error
Traceback (most recent call last):
File "minexample.py", line 8, in <module>
foo(lambda x: str(x), 5)
File "/home/william/.local/lib/python3.5/site-packages/enforce/decorators.py", line 44, in wrapper
raise RuntimeTypeError(exception_text)
enforce.exceptions.RuntimeTypeError: Argument 'func' ('<function <lambda> at 0x7f393cbca620>') was not of type typing.Callable[[int], str]. Actual type was <class 'function'>.
Edit2: Further inspection shows that the reason behind this error is actually built into python.
import typing
type(lambda x: x) == typing.Callable
This returns False
. Still digging away at this.
>>> import typing
>>> isinstance(lambda x: x, typing.Callable)
True
Anyway, you are doing a great job but I have totally forgotten to mention this in the README:
In the dev branch I implemented a recursive structure but there is no limit on a depth of recursion as it is using generators to avoid hitting this limit. A tree of type checking nodes (each node being a generator) is assigned for every parameter definition. The incoming argument is then passed to its own tree when a function is invoked. Whenever one of them fails, an exception is raised. In addition, it deals with a concept of Type variables by generating a single tree for every unique TypeVar (if any type T is used in more than one parameter, they will all point to the same tree) which has a special property of remembering the exact type passed to it last time. It will raise an exception if a different type is passed at the later stage.
In addition, I thought of evaluating contents of sequence structures lazily, i.e. the sequence is wrapped in a proxy object which will trigger type check on the content only when such content is accessed. In addition, it might be a good idea to check the first available element of every sequence before wrapping it in a proxy. Therefore, if the first one fails, there is no need for any extra overhead associated with the proxy object.
However, I have not yet implemented any special handling for the sequence, dictionary or callable type checks yet. I had enough time to work on this only during some of the major holidays because of my work. Please help me if you can.
I am especially concerned about checking the signature of callable objects. Honestly, I think the only realistic option would be to wrap it in a proxy object with an expected signature but it will prevent a detection of signature mismatch at the moment of passing such object into the function. As you can see, I do not have a working solution for this yet and hence I am very open to suggestions about how to make it better.
Thanks for all the work you did!
I've made a new issue for this specific problem of dealing with callable objects.
See #6.
I think, in its basic form, this bug was resolved. I am closing this issue till a more specific one is raised.
Sequences do not trigger an exception if their contents are of incorrect type, i.e. any sequence is always a sequence and content type checks are ignored. This is a limitations of a current type parser and validator. This should be resolved when a new parser ( #2 ) is implemented.