Reputation: 131
i want to design a decorator to check any function annotation type and if it has similar type then run function. can python do such this thing?? if python can, please help me!!
def foo (a:int):
if foo.__annotations__.get('a') == type(a):
pass
def boo (b:str):
if boo.__annotations__.get('b') == type(b):
pass
and another thing is annotations is a dict type, i want such this :
from type import FunctionType
def check (f:FunctionType):
result = True
k = [k for k in f.__annotations__.keys()]
v = [v for v in f.__annotations__.values()]
for i in range(len(v)):
if v[i] != type(k[i]): #but we don't access to the type of k[i] out of th f function
result = False
return result
Upvotes: 2
Views: 964
Reputation: 21
import functools
def annotations_checker(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
TrueFalseChecker=True
keys=tuple(func.__annotations__.keys())
for key_num in range(len(keys)):
if func.__annotations__[keys[key_num]]!=type(args[key_num]):
break
else:
value=func(*args,*kwargs)
return value
return
return wrapper
and you can use @annotations_checker decorator for any python method / python function to check type annotations like:
@annotations_checker
def test(str_example:str,int_example:int,second_str_example:str):
print("if you can see this, the args and annonations type are same!")
test(1,"2",3) #the function will not work
test("1",1,"testtest") #function will work
Upvotes: 1
Reputation: 119
If I understand the idea correctly, perhaps this code will help you:
from types import FunctionType
def check(f: FunctionType):
def wrapper(*args, **kwargs):
result = True
# check args
keys = tuple(f.__annotations__.keys())
for ar in enumerate(args):
if not isinstance(ar[1], f.__annotations__.get(keys[ar[0]])):
result = False
break
if result:
# check kwargs
for k, v in kwargs.items():
if not isinstance(v, f.__annotations__.get(k)):
result = False
break
if result:
f(*args, **kwargs)
return wrapper
Example usage:
@check
def foo(a: str, b: int = None):
print(f"a = {a}")
print(f"b = {b}")
# Example 1: a=324, b=32:
foo(234, b=32)
# result: function not executed
# Example 2: a="abc", b="zzz":
foo("abc", b="zzz")
# result: function not executed
# Example 3: a="qwe", b= not set:
foo("qwe")
# result: function executed, output:
# a = qwe
# b = None
# Example 4: a="abc", b=99:
foo("abc", 99)
# result: function executed, output:
# a = abc
# b = 99
The decorator checks the argument types, and if everything is in order, it executes the function, otherwise it does nothing.
Upvotes: 2
Reputation: 69
something like this.
import inspect
import functools
def check(func):
msg = "Expected type {etype} for {para} got {got}"
para = inspect.signature(func).parameters
keys = tuple(para.keys())
@functools.wraps(func)
def wrapper(*args,**kwargs):
def do_check(anno,value,para):
if not isinstance(value, anno):
raise TypeError(msg.format(etype=anno,
para=para,
got=type(value)))
for i,value in enumerate(args):
anno = para[keys[i]].annotation
do_check(anno, value, keys[i])
for arg_name,value in kwargs.items():
anno = para[arg_name].annotation
do_check(anno, value, arg_name)
ret = func(*args,**kwargs)
if "return" in func.__annotations__:
anno = func.__annotations__["return"]
do_check(anno, ret, "return")
return ret
return wrapper
@check
def test(a:int,b:str) -> str:
return 'aaa'
@check
def test2(a:int,b:str) -> str:
return 123
Upvotes: 1