@@ -275,6 +275,15 @@ def check_if_arguments_can_be_encoded(function_abi, args, kwargs):
275275
276276
277277def merge_args_and_kwargs (function_abi , args , kwargs ):
278+ """
279+ Takes a list of positional args (``args``) and a dict of keyword args
280+ (``kwargs``) defining values to be passed to a call to the contract function
281+ described by ``function_abi``. Checks to ensure that the correct number of
282+ args were given, no duplicate args were given, and no unknown args were
283+ given. Returns a list of argument values aligned to the order of inputs
284+ defined in ``function_abi``.
285+ """
286+ # Ensure the function is being applied to the correct number of args
278287 if len (args ) + len (kwargs ) != len (function_abi .get ('inputs' , [])):
279288 raise TypeError (
280289 "Incorrect argument count. Expected '{0}'. Got '{1}'" .format (
@@ -283,47 +292,50 @@ def merge_args_and_kwargs(function_abi, args, kwargs):
283292 )
284293 )
285294
295+ # If no keyword args were given, we don't need to align them
286296 if not kwargs :
287297 return args
288298
289- args_as_kwargs = {
290- arg_abi ['name' ]: arg
291- for arg_abi , arg in zip (function_abi ['inputs' ], args )
292- }
293- duplicate_keys = set (args_as_kwargs ).intersection (kwargs .keys ())
294- if duplicate_keys :
299+ kwarg_names = set (kwargs .keys ())
300+ sorted_arg_names = tuple (arg_abi ['name' ] for arg_abi in function_abi ['inputs' ])
301+ args_as_kwargs = dict (zip (sorted_arg_names , args ))
302+
303+ # Check for duplicate args
304+ duplicate_args = kwarg_names .intersection (args_as_kwargs .keys ())
305+ if duplicate_args :
295306 raise TypeError (
296307 "{fn_name}() got multiple values for argument(s) '{dups}'" .format (
297308 fn_name = function_abi ['name' ],
298- dups = ', ' .join (duplicate_keys ),
309+ dups = ', ' .join (duplicate_args ),
299310 )
300311 )
301312
302- sorted_arg_names = [arg_abi ['name' ] for arg_abi in function_abi ['inputs' ]]
303-
304- unknown_kwargs = {key for key in kwargs .keys () if key not in sorted_arg_names }
305- if unknown_kwargs :
313+ # Check for unknown args
314+ unknown_args = kwarg_names .difference (sorted_arg_names )
315+ if unknown_args :
306316 if function_abi .get ('name' ):
307317 raise TypeError (
308318 "{fn_name}() got unexpected keyword argument(s) '{dups}'" .format (
309319 fn_name = function_abi .get ('name' ),
310- dups = ', ' .join (unknown_kwargs ),
320+ dups = ', ' .join (unknown_args ),
311321 )
312322 )
313- # show type instead of name in the error message incase key 'name' is missing.
314323 raise TypeError (
315324 "Type: '{_type}' got unexpected keyword argument(s) '{dups}'" .format (
316325 _type = function_abi .get ('type' ),
317- dups = ', ' .join (unknown_kwargs ),
326+ dups = ', ' .join (unknown_args ),
318327 )
319328 )
320329
321- sorted_args = list (zip (
330+ # Sort args according to their position in the ABI and unzip them from their
331+ # names
332+ sorted_args = tuple (zip (
322333 * sorted (
323334 itertools .chain (kwargs .items (), args_as_kwargs .items ()),
324- key = lambda kv : sorted_arg_names .index (kv [0 ])
335+ key = lambda kv : sorted_arg_names .index (kv [0 ]),
325336 )
326337 ))
338+
327339 if sorted_args :
328340 return sorted_args [1 ]
329341 else :
0 commit comments