@ensure_annotations
def f(x: int, y: float) -> float:
return x+y
f(1, 2.3)
>>> 3.3
f(1, 2)
>>> ensure.EnsureError: Argument y to <function f at 0x109b7c710> does not match annotation type <class 'float'>
I think it works better than other approaches mentioned here because it (1) doesn't repeat the contents of the function signature, (2) doesn't install any magic system-wide hooks (and the attendant performance issues), and (3) is completely optional.