diff --git a/func_annotations.py b/func_annotations.py new file mode 100755 index 0000000..1555c41 --- /dev/null +++ b/func_annotations.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# Play around with function annotations to implement a crude type checker. + +import inspect + + +def typechecked(func): + wrapped_func = func + + def typecheck(*args, **kvargs): + parameters = inspect.signature(wrapped_func).parameters + wants = [(par, parameters[par].annotation) for par in parameters] + for want, arg in zip(wants, args): + name, class_ = want + if not isinstance(arg, class_): + raise TypeError("arg {} is not " + "an instance of {}".format(name, class_)) + + return_ = wrapped_func(*args, **kvargs) + class_ = wrapped_func.__annotations__["return"] + if not isinstance(return_, class_): + raise TypeError("return value is not " + "an instance of {}".format(class_)) + return return_ + + typecheck.__doc__ = wrapped_func.__doc__ + return typecheck + + +@typechecked +def greet(name: str, age: int, fnord: str=None) -> str: + """Greet someone. + + >>> greet("Mike", 12) + 'Hello Mike, you are 12 years old' + >>> greet("Florian", "eins") + Traceback (most recent call last): + File "func_annotations.py", line 14, in typecheck + "is not an instance of {}".format(name, class_)) + TypeError: arg age is not an instance of + """ + return 'Hello {0}, you are {1} years old'.format(name, age) + + +@typechecked +def test(foo: int) -> str: + """ Just a test. + + >>> test(1) + Traceback (most recent call last): + File "func_annotations.py", line 21, in typecheck + "is not an instance of {}".format(class_)) + TypeError: return value is not an instance of + """ + return 1 + +import doctest +doctest.testmod()