From c4dd5c5d8586dc7d099f9bf06047cce83c13b602 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Wed, 30 Jan 2019 16:54:59 -0700 Subject: [PATCH 1/4] Add docstring for `merge_args_and_kwargs` --- web3/_utils/abi.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web3/_utils/abi.py b/web3/_utils/abi.py index 9ccefeac8c..43ee3f042d 100644 --- a/web3/_utils/abi.py +++ b/web3/_utils/abi.py @@ -275,6 +275,14 @@ def check_if_arguments_can_be_encoded(function_abi, args, kwargs): def merge_args_and_kwargs(function_abi, args, kwargs): + """ + Takes a list of positional args (``args``) and a dict of keyword args + (``kwargs``) defining values to be passed to a call to the contract function + described by ``function_abi``. Checks to ensure that the correct number of + args were given, no duplicate args were given, and no unknown args were + given. Returns a list of argument values aligned to the order of inputs + defined in ``function_abi``. + """ if len(args) + len(kwargs) != len(function_abi.get('inputs', [])): raise TypeError( "Incorrect argument count. Expected '{0}'. Got '{1}'".format( From 961b520b6e0afd52459ea603697d2f6f2033d1bd Mon Sep 17 00:00:00 2001 From: David Sanders Date: Wed, 30 Jan 2019 16:58:22 -0700 Subject: [PATCH 2/4] Add/update comments in `merge_args_and_kwargs` --- web3/_utils/abi.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web3/_utils/abi.py b/web3/_utils/abi.py index 43ee3f042d..32bba91935 100644 --- a/web3/_utils/abi.py +++ b/web3/_utils/abi.py @@ -283,6 +283,7 @@ def merge_args_and_kwargs(function_abi, args, kwargs): given. Returns a list of argument values aligned to the order of inputs defined in ``function_abi``. """ + # Ensure the function is being applied to the correct number of args if len(args) + len(kwargs) != len(function_abi.get('inputs', [])): raise TypeError( "Incorrect argument count. Expected '{0}'. Got '{1}'".format( @@ -291,9 +292,11 @@ def merge_args_and_kwargs(function_abi, args, kwargs): ) ) + # If no keyword args were given, we don't need to align them if not kwargs: return args + # Check for duplicate args args_as_kwargs = { arg_abi['name']: arg for arg_abi, arg in zip(function_abi['inputs'], args) @@ -307,6 +310,7 @@ def merge_args_and_kwargs(function_abi, args, kwargs): ) ) + # Check for unknown args sorted_arg_names = [arg_abi['name'] for arg_abi in function_abi['inputs']] unknown_kwargs = {key for key in kwargs.keys() if key not in sorted_arg_names} @@ -318,7 +322,6 @@ def merge_args_and_kwargs(function_abi, args, kwargs): dups=', '.join(unknown_kwargs), ) ) - # show type instead of name in the error message incase key 'name' is missing. raise TypeError( "Type: '{_type}' got unexpected keyword argument(s) '{dups}'".format( _type=function_abi.get('type'), @@ -326,6 +329,8 @@ def merge_args_and_kwargs(function_abi, args, kwargs): ) ) + # Sort args according to their position in the ABI and unzip them from their + # names sorted_args = list(zip( *sorted( itertools.chain(kwargs.items(), args_as_kwargs.items()), From dbc71ca79fee1890a102135e097cb926e3ab61ec Mon Sep 17 00:00:00 2001 From: David Sanders Date: Wed, 30 Jan 2019 16:59:41 -0700 Subject: [PATCH 3/4] Minor lint/whitespace --- web3/_utils/abi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web3/_utils/abi.py b/web3/_utils/abi.py index 32bba91935..1e232ddfba 100644 --- a/web3/_utils/abi.py +++ b/web3/_utils/abi.py @@ -334,9 +334,10 @@ def merge_args_and_kwargs(function_abi, args, kwargs): sorted_args = list(zip( *sorted( itertools.chain(kwargs.items(), args_as_kwargs.items()), - key=lambda kv: sorted_arg_names.index(kv[0]) + key=lambda kv: sorted_arg_names.index(kv[0]), ) )) + if sorted_args: return sorted_args[1] else: From 575cb66717f8340a7f12754ae3c0a8fb9b4e516c Mon Sep 17 00:00:00 2001 From: David Sanders Date: Wed, 30 Jan 2019 17:00:12 -0700 Subject: [PATCH 4/4] Cleanup/refactoring in `merge_args_and_kwargs` --- web3/_utils/abi.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/web3/_utils/abi.py b/web3/_utils/abi.py index 1e232ddfba..9467f1af99 100644 --- a/web3/_utils/abi.py +++ b/web3/_utils/abi.py @@ -296,42 +296,40 @@ def merge_args_and_kwargs(function_abi, args, kwargs): if not kwargs: return args + kwarg_names = set(kwargs.keys()) + sorted_arg_names = tuple(arg_abi['name'] for arg_abi in function_abi['inputs']) + args_as_kwargs = dict(zip(sorted_arg_names, args)) + # Check for duplicate args - args_as_kwargs = { - arg_abi['name']: arg - for arg_abi, arg in zip(function_abi['inputs'], args) - } - duplicate_keys = set(args_as_kwargs).intersection(kwargs.keys()) - if duplicate_keys: + duplicate_args = kwarg_names.intersection(args_as_kwargs.keys()) + if duplicate_args: raise TypeError( "{fn_name}() got multiple values for argument(s) '{dups}'".format( fn_name=function_abi['name'], - dups=', '.join(duplicate_keys), + dups=', '.join(duplicate_args), ) ) # Check for unknown args - sorted_arg_names = [arg_abi['name'] for arg_abi in function_abi['inputs']] - - unknown_kwargs = {key for key in kwargs.keys() if key not in sorted_arg_names} - if unknown_kwargs: + unknown_args = kwarg_names.difference(sorted_arg_names) + if unknown_args: if function_abi.get('name'): raise TypeError( "{fn_name}() got unexpected keyword argument(s) '{dups}'".format( fn_name=function_abi.get('name'), - dups=', '.join(unknown_kwargs), + dups=', '.join(unknown_args), ) ) raise TypeError( "Type: '{_type}' got unexpected keyword argument(s) '{dups}'".format( _type=function_abi.get('type'), - dups=', '.join(unknown_kwargs), + dups=', '.join(unknown_args), ) ) # Sort args according to their position in the ABI and unzip them from their # names - sorted_args = list(zip( + sorted_args = tuple(zip( *sorted( itertools.chain(kwargs.items(), args_as_kwargs.items()), key=lambda kv: sorted_arg_names.index(kv[0]),