RussBaz / enforce

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

enforce is not transparent for Callable types - EnforceProxy #58

Open smarie opened 6 years ago

smarie commented 6 years ago

Hey there, I found this nice bug while developing valid8

With enforce 0.3.4,

@runtime_validation
class Foo:
    def __init__(self, fun: Callable):
        self.fun = fun

a = Foo(next)
assert a.fun.__name__ == 'next'  # => raises an AssertionError

Indeed a.fun does not hold your callable, but a proxy to it. This could be ok, but that proxy does not act as a transparent decorator. I would recommend using the very nice decorator library, which I use in valid8 and autoclass

RussBaz commented 6 years ago

Well, I am using wrapt at the moment. I pushed some tests to check this issue,

https://github.com/GrahamDumpleton/wrapt

The snippet you provided works at the moment ('dev' branch) if the object is a callable, excluding objects written in C, such ass built-in functions. next is a built-in function, so I am afraid it will not work with it. I am not sure what would be the best approach to such scenarios as it pretty much impossible to extract a signature from a C-defined function. If you have any suggestion what should or could be done, please feel free to share.

smarie commented 6 years ago

Thanks for the explanation. I'm afraid I do not know enough about C-defined function integration in python to be of any help here, but it seems that at least setting the __name__ attribute right on your decorated function is feasible - as it is present also in built-in functions. This should probably be done automatically by wrapt, but if it is not you can easily set this attribute manually before returning the wrapper.