RussBaz / enforce

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

Run on any function automatically #1

Open The-Compiler opened 8 years ago

The-Compiler commented 8 years ago

Hey, I just discovered this via pycoder's weekly :smile:

It'd be nice to have some way to run the type checks automatically on any function call. I'm sure this will be slow as hell, but it'd be nice to run the tests with it once in a while, to discover things a static checker might not discover.

I'm not sure what the best way to implement this would be - sys.settrace and bytecode rewriting come to mind, but I'm not sure how hard this is...

RussBaz commented 8 years ago

Hmmm. Yes, I like how this sounds. I think it might be especially useful in debugging already running systems. However, I am not yet sure how to implement it correctly right now. I need to focus on few other problems first.

PS. Thanks for noting! I hope this project can help you at least one day.

jakeschurch commented 7 years ago

Try this:

def CheckInputTypes(func):
    def wrapper(*args, **kwargs):

        for arg in args:
            ArgValue = next(iter(locals()['args']))
            ArgParamType = next(iter(func.__annotations__.keys()))

            if isinstance(ArgValue, func.__annotations__[ArgParamType]) is False:
                raise TypeError(
                    "Arg: {0} in function {1} is not of type {2}".format(
                        repr(ArgParamType), repr(func.__name__),
                        func.__annotations__[ArgParamType]))

        for kwarg in kwargs:
            KwargValue = locals()['kwargs'][kwarg]

            if isinstance(KwargValue, func.__annotations__[kwarg]) is False:
                raise TypeError(
                    "Kwarg: {0} in function {1} is not of type {2}".format(
                        repr(kwarg), repr(func.__name__),
                        func.__annotations__[kwarg]))

        RanFunc = func(*args, **kwargs)
        if isinstance(RanFunc, func.__annotations__['return']) is False:
            raise TypeError(
                "Return value {0} in function {1} is not of type {2}".format(
                    repr(RanFunc), repr(func.__name__),
                    func.__annotations__['return']))

        return RanFunc
    return wrapper