@ -232,9 +232,27 @@ class permittedKwargs:
def typed_pos_args ( name : str , * types : T . Union [ T . Type , T . Tuple [ T . Type , . . . ] ] ,
varargs : T . Optional [ T . Union [ T . Type , T . Tuple [ T . Type ] ] ] = None ,
optargs : T . Optional [ T . List [ T . Union [ T . Type , T . Tuple [ T . Type ] ] ] ] = None ,
min_varargs : int = 0 , max_varargs : int = 0 ) - > T . Callable [ . . . , T . Any ] :
""" Decorator that types type checking of positional arguments.
This supports two different models of optional aguments , the first is the
variadic argument model . Variadic arguments are a possibly bounded ,
possibly unbounded number of arguments of the same type ( unions are
supported ) . The second is the standard default value model , in this case
a number of optional arguments may be provided , but they are still
ordered , and they may have different types .
This function does not support mixing variadic and default arguments .
: name : The name of the decorated function ( as displayed in error messages )
: varargs : They type ( s ) of any variadic arguments the function takes . If
None the function takes no variadic args
: min_varargs : the minimum number of variadic arguments taken
: max_varargs : the maximum number of variadic arguments taken . 0 means unlimited
: optargs : The types of any optional arguments parameters taken . If None
then no optional paramters are taken .
allows replacing this :
` ` ` python
def func ( self , node , args , kwargs ) :
@ -268,9 +286,12 @@ def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
assert isinstance ( args , list ) , args
assert max_varargs > = 0 , ' max_varrags cannot be negative '
assert min_varargs > = 0 , ' min_varrags cannot be negative '
assert optargs is None or varargs is None , \
' varargs and optargs not supported together as this would be ambiguous '
num_args = len ( args )
num_types = len ( types )
a_types = types
if varargs :
num_types + = min_varargs
@ -278,10 +299,19 @@ def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
raise InvalidArguments ( f ' { name } takes at least { num_types } arguments, but got { num_args } . ' )
elif max_varargs != 0 and ( num_args < num_types or num_args > num_types + max_varargs - min_varargs ) :
raise InvalidArguments ( f ' { name } takes between { num_types } and { num_types + max_varargs - min_varargs } arguments, but got { len ( args ) } . ' )
elif optargs :
if num_args < num_types :
raise InvalidArguments ( f ' { name } takes at least { num_types } arguments, but got { num_args } . ' )
elif num_args > num_types + len ( optargs ) :
raise InvalidArguments ( f ' { name } takes at most { num_types + len ( optargs ) } arguments, but got { num_args } . ' )
# Add the number of positional arguments required
if num_args > num_types :
diff = num_args - num_types
a_types = tuple ( list ( types ) + list ( optargs [ : diff ] ) )
elif num_args != num_types :
raise InvalidArguments ( f ' { name } takes exactly { num_types } arguments, but got { num_args } . ' )
for i , ( arg , type_ ) in enumerate ( itertools . zip_longest ( args , types , fillvalue = varargs ) , start = 1 ) :
for i , ( arg , type_ ) in enumerate ( itertools . zip_longest ( args , a_ types, fillvalue = varargs ) , start = 1 ) :
if not isinstance ( arg , type_ ) :
if isinstance ( type_ , tuple ) :
shouldbe = ' one of: {} ' . format ( " , " . join ( f ' " { t . __name__ } " ' for t in type_ ) )
@ -298,11 +328,17 @@ def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
# if we have varargs we need to split them into a separate
# tuple, as python's typing doesn't understand tuples with
# fixed elements and variadic elements, only one or the other.
# so in that cas we need T.Tuple[int, str, float, T.Tuple[str, ...]]
# so in that case we need T.Tuple[int, str, float, T.Tuple[str, ...]]
pos = args [ : len ( types ) ]
var = list ( args [ len ( types ) : ] )
pos . append ( var )
nargs [ i ] = tuple ( pos )
elif optargs :
if num_args < num_types + len ( optargs ) :
diff = num_types + len ( optargs ) - num_args
nargs [ i ] = tuple ( list ( args ) + [ None ] * diff )
else :
nargs [ i ] = args
else :
nargs [ i ] = tuple ( args )
return f ( * nargs , * * wrapped_kwargs )