From 4e7bdafdcfb80419234a5db0dcce12134f015a7b Mon Sep 17 00:00:00 2001 From: Jack Robison Date: Tue, 3 Apr 2018 12:26:32 -0400 Subject: [PATCH] fix positional and keyword args --- CHANGELOG.md | 1 + lbrynet/daemon/auth/client.py | 4 ++-- lbrynet/daemon/auth/server.py | 27 ++++++++++++++++++--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43701e481..6281c5236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ at anytime. * pass the sd hash to reflector ClientFactory instead of looking it up * if the `use_authentication` setting is configured, use authentication for all api methods instead of only those with the `auth_required` decorator * regenerate api keys on startup if the using authentication + * support both positional and keyword args for api calls ### Added * virtual kademlia network and mock udp transport for dht integration tests diff --git a/lbrynet/daemon/auth/client.py b/lbrynet/daemon/auth/client.py index 2e18ac748..6c81eb686 100644 --- a/lbrynet/daemon/auth/client.py +++ b/lbrynet/daemon/auth/client.py @@ -40,8 +40,8 @@ class AuthAPIClient(object): if name.startswith('__') and name.endswith('__'): raise AttributeError(name) - def f(*args): - return self.call(name, args[0] if args else {}) + def f(*args, **kwargs): + return self.call(name, [args, kwargs]) return f diff --git a/lbrynet/daemon/auth/server.py b/lbrynet/daemon/auth/server.py index 3b3581099..7169f8b87 100644 --- a/lbrynet/daemon/auth/server.py +++ b/lbrynet/daemon/auth/server.py @@ -314,20 +314,19 @@ class AuthJSONRPCServer(AuthorizedBase): return server.NOT_DONE_YET if args == EMPTY_PARAMS or args == []: - args_dict = {} _args, _kwargs = (), {} elif isinstance(args, dict): - args_dict = args + _args, _kwargs = (), args elif len(args) == 1 and isinstance(args[0], dict): # TODO: this is for backwards compatibility. Remove this once API and UI are updated # TODO: also delete EMPTY_PARAMS then - args_dict = args[0] _args, _kwargs = (), args + elif len(args) == 2 and isinstance(args[0], list) and isinstance(args[1], dict): + _args, _kwargs = args else: - # d = defer.maybeDeferred(function, *args) # if we want to support positional args too - raise ValueError('Args must be a dict') + raise ValueError('invalid args format') - params_error, erroneous_params = self._check_params(fn, args_dict) + params_error, erroneous_params = self._check_params(fn, _args, _kwargs) if params_error is not None: params_error_message = '{} for {} command: {}'.format( params_error, function_name, ', '.join(erroneous_params) @@ -339,7 +338,7 @@ class AuthJSONRPCServer(AuthorizedBase): ) return server.NOT_DONE_YET - d = defer.maybeDeferred(fn, self, **args_dict) + d = defer.maybeDeferred(fn, self, *_args, **_kwargs) # finished_deferred will callback when the request is finished # and errback if something went wrong. If the errback is @@ -431,12 +430,22 @@ class AuthJSONRPCServer(AuthorizedBase): return self.callable_methods.get(function_path) @staticmethod - def _check_params(function, args_dict): + def _check_params(function, args_tup, args_dict): argspec = inspect.getargspec(undecorated(function)) num_optional_params = 0 if argspec.defaults is None else len(argspec.defaults) + + duplicate_params = [ + duplicate_param + for duplicate_param in argspec.args[1:len(args_tup) + 2] + if duplicate_param in args_dict + ] + + if duplicate_params: + return 'Duplicate parameters', duplicate_params + missing_required_params = [ required_param - for required_param in argspec.args[1:-num_optional_params] + for required_param in argspec.args[len(args_tup)+1:-num_optional_params] if required_param not in args_dict ] if len(missing_required_params):