Is there a way to check if all the argument passes to a method matches the expected one? I tried the inspect.signature.bind to match them but it does now work properly when using a default parameter, even when the type of the default value is not same as passed. eg in the last call to the method faa, I send a list as the third argument, but the expected default argument is Bool. Is there a way to match that also?
import inspect
def foo(a, b, x=True):
pass
def faa(*args, **kwargs):
try:
inspect.signature(foo).bind(*args, **kwargs)
except TypeError:
print("Does not match")
else:
print("Matches")
faa(1) # Does not match , Ok
faa(10, None, 'something') # Matches, Ok.
faa(1, 2) # Matches, Ok.
faa(10, None, [1,2]) # Matches, NOK. Is there a way to add a check to not match ?
You could use the decorator validate_arguments
belonging to the module pydantic
. As an example:
from pydantic import validate_arguments
@validate_arguments
def faa(a, b, x: bool = True):
pass
faa(
a=10, b=None, x=[1, 2]
)
Output
pydantic.error_wrappers.ValidationError: 1 validation error for Faa
x
value could not be parsed to a boolean (type=type_error.bool)
You could define a simple decorator that can be used for every function you want to validate. This decorator builds up on the inpsect
module. The idea is to validate the function parameter (both positional and non-positional) against the default value of the corresponding argument in the function.
import inspect
from functools import wraps
def validate_func_args(func):
def check_type(value, fn_param: inspect.Parameter):
if not fn_param.default is fn_param.empty:
_default = fn_param.default
# We do not type check if the default value is None or if the argument is none
is_none = _default is None or value is None
if not is_none and type(value) != type(_default):
raise TypeError(f"Invalid type encountered for {fn_param.name}")
@wraps(func)
def wrapper(*args, **kwargs):
# First pass
inspect.signature(foo).bind(*args, **kwargs)
# Second pass (validate parameters with default values)
args_count = len(args)
fn_params = inspect.signature(foo).parameters
for arg, param in zip(args, list(fn_params)[:args_count]):
check_type(arg, fn_params[param])
for kwarg, value in kwargs.items():
check_type(value, fn_params[kwarg])
# All good. Now call the function and return the result
result = func(*args, **kwargs)
return result
return wrapper
Function definition
@validate_func_args
def foo(a, b=2, x=True):
pass
Function call
foo(10, None, "something")
Output
TypeError: Invalid type encountered for x
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.