Source code for testplan.common.utils.interface

"""Validates methods signature."""

from inspect import signature
from itertools import zip_longest
from typing import List, Optional


[docs] class MethodSignatureMismatch(Exception): """ MethodSignatureMismatch Exception """ pass
def _unused_variant(arg_name: Optional[str]) -> List[str]: """ returns all linter acceptable variants of the given arg_name """ if isinstance(arg_name, str): if arg_name.startswith("_"): return [arg_name] return [arg_name, f"_{arg_name}", "_"] return []
[docs] def check_signature(func: callable, args_list: List[str]) -> bool: """ Checks if the given function's signature matches the given list of args :param func: function whose signature to check :param args_list: list of arg names to match as signature :return: ``True`` if the signature is matching :raises MethodSignatureMismatch: if the given function's signature differs from the provided """ funcparams = [ n for n, p in signature(func).parameters.items() if p.kind in (p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY) ] if not all( map( lambda x: x[0] in _unused_variant(x[1]), zip_longest(funcparams, args_list), ) ): raise MethodSignatureMismatch( f"Expected arguments for {func.__name__} are {args_list} or their " f"underscore-prefixed variants, not {funcparams}" ) return True
[docs] def check_signature_leading(func: callable, exp_params: List[str]) -> bool: """ check if the leading (positional) parameters of the function signature matches the expected parameters this is for checking if parametrized testcases have been well defined """ # return value is not very useful in this case, just to keep it consistent # with ``check_signature`` funcparams = [ n for n, p in signature(func).parameters.items() if p.kind in (p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY) ] msg = ( f"First several expected arguments for {func.__name__} are " f"{exp_params} or their underscore-prefixed variants, not " f"{funcparams[:len(exp_params)]}" ) for exp in exp_params: if funcparams and funcparams[0] in _unused_variant(exp): funcparams.pop(0) continue break else: return True raise MethodSignatureMismatch(msg)