forked from LBRYCommunity/lbry-sdk
update arg parsing to use docopt
This commit is contained in:
parent
0eac1e6ed0
commit
57c3d2590c
5 changed files with 119 additions and 140 deletions
|
@ -1,23 +1,68 @@
|
|||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import colorama
|
||||
|
||||
from docopt import docopt
|
||||
from collections import OrderedDict
|
||||
from lbrynet import conf
|
||||
from lbrynet.core import utils
|
||||
from lbrynet.lbrynet_daemon.auth.client import JSONRPCException, LBRYAPIClient
|
||||
from lbrynet.lbrynet_daemon.Daemon import LOADING_WALLET_CODE
|
||||
from lbrynet.lbrynet_daemon.Daemon import LOADING_WALLET_CODE, Daemon
|
||||
from jsonrpc.common import RPCError
|
||||
from urllib2 import URLError, HTTPError
|
||||
from httplib import UNAUTHORIZED
|
||||
|
||||
|
||||
def main():
|
||||
colorama.init()
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
_, arguments = parser.parse_known_args()
|
||||
def remove_brackets(key):
|
||||
if key.startswith("<") and key.endswith(">"):
|
||||
return str(key[1:-1])
|
||||
return key
|
||||
|
||||
|
||||
def set_flag_vals(flag_names, parsed_args):
|
||||
kwargs = OrderedDict()
|
||||
for key, arg in parsed_args.iteritems():
|
||||
if arg is None:
|
||||
continue
|
||||
elif key.startswith("--"):
|
||||
if remove_brackets(key[2:]) not in kwargs:
|
||||
k = remove_brackets(key[2:])
|
||||
kwargs[k] = guess_type(arg)
|
||||
elif key in flag_names:
|
||||
if remove_brackets(flag_names[key]) not in kwargs:
|
||||
kwargs[remove_brackets(flag_names[key])] = guess_type(arg)
|
||||
elif remove_brackets(key) not in kwargs:
|
||||
kwargs[remove_brackets(key)] = guess_type(arg)
|
||||
return kwargs
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv[1:]):
|
||||
method, args = sys.argv[1], sys.argv[2:]
|
||||
else:
|
||||
print_help()
|
||||
return
|
||||
|
||||
if method in ['help', '--help', '-h']:
|
||||
if len(args) == 1:
|
||||
print_help_for_command(args[0])
|
||||
else:
|
||||
print_help()
|
||||
return
|
||||
|
||||
if method not in Daemon.callable_methods:
|
||||
print_error("\"%s\" is not a valid command." % method)
|
||||
return
|
||||
|
||||
fn = Daemon.callable_methods[method]
|
||||
if hasattr(fn, "_flags"):
|
||||
flag_names = fn._flags
|
||||
else:
|
||||
flag_names = {}
|
||||
|
||||
parsed = docopt(fn.__doc__, args)
|
||||
kwargs = set_flag_vals(flag_names, parsed)
|
||||
colorama.init()
|
||||
conf.initialize_settings()
|
||||
api = LBRYAPIClient.get_client()
|
||||
|
||||
|
@ -44,94 +89,43 @@ def main():
|
|||
print " Status: " + message
|
||||
return 1
|
||||
|
||||
if len(arguments) < 1:
|
||||
print_help(api)
|
||||
return 1
|
||||
|
||||
method = arguments[0]
|
||||
try:
|
||||
params = parse_params(arguments[1:])
|
||||
except InvalidParameters as e:
|
||||
print_error(e.message)
|
||||
return 1
|
||||
|
||||
# TODO: check if port is bound. Error if its not
|
||||
|
||||
if method in ['--help', '-h', 'help']:
|
||||
if len(params) == 0:
|
||||
print_help(api)
|
||||
elif 'command' not in params:
|
||||
print_error(
|
||||
'To get help on a specific command, use `{} help command=COMMAND_NAME`'.format(
|
||||
os.path.basename(sys.argv[0]))
|
||||
)
|
||||
try:
|
||||
result = api.call(method, **kwargs)
|
||||
if isinstance(result, basestring):
|
||||
# printing the undumped string is prettier
|
||||
print result
|
||||
else:
|
||||
print_help_for_command(api, params['command'])
|
||||
print utils.json_dumps_pretty(result)
|
||||
except (RPCError, KeyError, JSONRPCException, HTTPError) as err:
|
||||
error_data = None
|
||||
if isinstance(err, HTTPError):
|
||||
error_body = err.read()
|
||||
try:
|
||||
error_data = json.loads(error_body)
|
||||
except ValueError:
|
||||
print (
|
||||
"There was an error, and the response was not valid JSON.\n" +
|
||||
"Raw JSONRPC response:\n" + error_body
|
||||
)
|
||||
return 1
|
||||
|
||||
elif method not in api.commands():
|
||||
print_error("'" + method + "' is not a valid command.")
|
||||
print_error(error_data['error']['message'] + "\n", suggest_help=False)
|
||||
else:
|
||||
print_error("Something went wrong\n", suggest_help=False)
|
||||
|
||||
else:
|
||||
try:
|
||||
result = api.call(method, params)
|
||||
if isinstance(result, basestring):
|
||||
# printing the undumped string is prettier
|
||||
print result
|
||||
else:
|
||||
print utils.json_dumps_pretty(result)
|
||||
except (RPCError, KeyError, JSONRPCException, HTTPError) as err:
|
||||
error_data = None
|
||||
if isinstance(err, HTTPError):
|
||||
error_body = err.read()
|
||||
try:
|
||||
error_data = json.loads(error_body)
|
||||
except ValueError:
|
||||
print (
|
||||
"There was an error, and the response was not valid JSON.\n" +
|
||||
"Raw JSONRPC response:\n" + error_body
|
||||
)
|
||||
return 1
|
||||
print_help_for_command(method)
|
||||
|
||||
print_error(error_data['error']['message'] + "\n", suggest_help=False)
|
||||
else:
|
||||
print_error("Something went wrong\n", suggest_help=False)
|
||||
|
||||
print_help_for_command(api, method)
|
||||
if 'data' in error_data['error'] and 'traceback' in error_data['error']['data']:
|
||||
print "Here's the traceback for the error you encountered:"
|
||||
print "\n".join(error_data['error']['data']['traceback'])
|
||||
return 1
|
||||
|
||||
|
||||
def parse_params(params):
|
||||
if len(params) > 1:
|
||||
return get_params_from_kwargs(params)
|
||||
elif len(params) == 1:
|
||||
try:
|
||||
return json.loads(params[0])
|
||||
except ValueError:
|
||||
return get_params_from_kwargs(params)
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class InvalidParameters(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_params_from_kwargs(params):
|
||||
params_for_return = {}
|
||||
for i in params:
|
||||
try:
|
||||
eq_pos = i.index('=')
|
||||
except ValueError:
|
||||
raise InvalidParameters('{} is not in <key>=<value> format'.format(i))
|
||||
k, v = i[:eq_pos], i[eq_pos + 1:]
|
||||
params_for_return[k] = guess_type(v)
|
||||
return params_for_return
|
||||
if 'data' in error_data['error'] and 'traceback' in error_data['error']['data']:
|
||||
print "Here's the traceback for the error you encountered:"
|
||||
print "\n".join(error_data['error']['data']['traceback'])
|
||||
return 1
|
||||
|
||||
|
||||
def guess_type(x):
|
||||
if not isinstance(x, (unicode, str)):
|
||||
return x
|
||||
if x in ('true', 'True', 'TRUE'):
|
||||
return True
|
||||
if x in ('false', 'False', 'FALSE'):
|
||||
|
@ -159,7 +153,8 @@ def print_error(message, suggest_help=True):
|
|||
print_help_suggestion()
|
||||
|
||||
|
||||
def print_help(api):
|
||||
def print_help():
|
||||
commands = Daemon.callable_methods.keys()
|
||||
print "\n".join([
|
||||
"NAME",
|
||||
" lbrynet-cli - LBRY command line client.",
|
||||
|
@ -170,20 +165,18 @@ def print_help(api):
|
|||
"EXAMPLES",
|
||||
" lbrynet-cli commands # list available commands",
|
||||
" lbrynet-cli status # get daemon status",
|
||||
" lbrynet-cli resolve_name name=what # resolve a name",
|
||||
" lbrynet-cli help command=resolve_name # get help for a command",
|
||||
" lbrynet-cli resolve_name what # resolve a name",
|
||||
" lbrynet-cli help resolve_name # get help for a command",
|
||||
"",
|
||||
"COMMANDS",
|
||||
wrap_list_to_term_width(api.commands(), prefix=' ')
|
||||
wrap_list_to_term_width(commands, prefix=' ')
|
||||
])
|
||||
|
||||
|
||||
def print_help_for_command(api, command):
|
||||
help_response = api.call('help', {'command': command})
|
||||
print "Help for %s method:" % command
|
||||
message = help_response['help'] if 'help' in help_response else help_response
|
||||
message = "\n".join([' ' + line for line in message.split("\n")])
|
||||
print message
|
||||
def print_help_for_command(command):
|
||||
fn = Daemon.callable_methods.get(command)
|
||||
if fn:
|
||||
print "Help for %s method:\n%s" % (command, fn.__doc__)
|
||||
|
||||
|
||||
def wrap_list_to_term_width(l, width=None, separator=', ', prefix=''):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
import urlparse
|
||||
import inspect
|
||||
import json
|
||||
import inspect
|
||||
|
||||
from decimal import Decimal
|
||||
from zope.interface import implements
|
||||
|
@ -15,9 +15,9 @@ from traceback import format_exc
|
|||
from lbrynet import conf
|
||||
from lbrynet.core.Error import InvalidAuthenticationToken
|
||||
from lbrynet.core import utils
|
||||
from lbrynet.undecorated import undecorated
|
||||
from lbrynet.lbrynet_daemon.auth.util import APIKey, get_auth_message
|
||||
from lbrynet.lbrynet_daemon.auth.client import LBRY_SECRET
|
||||
from lbrynet.undecorated import undecorated
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -338,12 +338,16 @@ class AuthJSONRPCServer(AuthorizedBase):
|
|||
|
||||
if args == EMPTY_PARAMS or args == []:
|
||||
args_dict = {}
|
||||
_args, _kwargs = (), {}
|
||||
elif isinstance(args, dict):
|
||||
args_dict = 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 isinstance(args, list):
|
||||
_args, _kwargs = args, {}
|
||||
else:
|
||||
# d = defer.maybeDeferred(function, *args) # if we want to support positional args too
|
||||
raise ValueError('Args must be a dict')
|
||||
|
@ -400,28 +404,6 @@ class AuthJSONRPCServer(AuthorizedBase):
|
|||
(utils.now() - time_in).total_seconds()))
|
||||
return server.NOT_DONE_YET
|
||||
|
||||
@staticmethod
|
||||
def _check_params(function, args_dict):
|
||||
argspec = inspect.getargspec(undecorated(function))
|
||||
num_optional_params = 0 if argspec.defaults is None else len(argspec.defaults)
|
||||
missing_required_params = [
|
||||
required_param
|
||||
for required_param in argspec.args[1:-num_optional_params]
|
||||
if required_param not in args_dict
|
||||
]
|
||||
if len(missing_required_params):
|
||||
return 'Missing required parameters', missing_required_params
|
||||
|
||||
extraneous_params = [] if argspec.keywords is not None else [
|
||||
extra_param
|
||||
for extra_param in args_dict
|
||||
if extra_param not in argspec.args[1:]
|
||||
]
|
||||
if len(extraneous_params):
|
||||
return 'Extraneous parameters', extraneous_params
|
||||
|
||||
return None, None
|
||||
|
||||
def _register_user_session(self, session_id):
|
||||
"""
|
||||
Add or update a HMAC secret for a session
|
||||
|
@ -502,6 +484,28 @@ class AuthJSONRPCServer(AuthorizedBase):
|
|||
self._verify_method_is_callable(function_path)
|
||||
return self.callable_methods.get(function_path)
|
||||
|
||||
@staticmethod
|
||||
def _check_params(function, args_dict):
|
||||
argspec = inspect.getargspec(undecorated(function))
|
||||
num_optional_params = 0 if argspec.defaults is None else len(argspec.defaults)
|
||||
missing_required_params = [
|
||||
required_param
|
||||
for required_param in argspec.args[1:-num_optional_params]
|
||||
if required_param not in args_dict
|
||||
]
|
||||
if len(missing_required_params):
|
||||
return 'Missing required parameters', missing_required_params
|
||||
|
||||
extraneous_params = [] if argspec.keywords is not None else [
|
||||
extra_param
|
||||
for extra_param in args_dict
|
||||
if extra_param not in argspec.args[1:]
|
||||
]
|
||||
if len(extraneous_params):
|
||||
return 'Extraneous parameters', extraneous_params
|
||||
|
||||
return None, None
|
||||
|
||||
def _initialize_session(self, session_id):
|
||||
if not self.sessions.get(session_id, False):
|
||||
self._register_user_session(session_id)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Twisted==16.6.0
|
||||
appdirs==1.4.3
|
||||
argparse==1.2.1
|
||||
docopt==0.6.2
|
||||
base58==0.2.2
|
||||
git+https://github.com/lbryio/bumpversion.git#egg=bumpversion
|
||||
colorama==0.3.7
|
||||
|
|
1
setup.py
1
setup.py
|
@ -31,6 +31,7 @@ requires = [
|
|||
'seccure',
|
||||
'txJSON-RPC',
|
||||
'zope.interface',
|
||||
'docopt'
|
||||
]
|
||||
|
||||
console_scripts = [
|
||||
|
|
|
@ -16,23 +16,3 @@ class DaemonCLITests(unittest.TestCase):
|
|||
self.assertEqual(False, DaemonCLI.guess_type('false'))
|
||||
self.assertEqual(False, DaemonCLI.guess_type('False'))
|
||||
|
||||
def test_get_params(self):
|
||||
test_params = [
|
||||
'b64address=VdNmakxFORPSyfCprAD/eDDPk5TY9QYtSA==',
|
||||
'name=test',
|
||||
'amount=5.3',
|
||||
'n=5',
|
||||
'address=bY13xeAjLrsjP4KGETwStK2a9UgKgXVTXu',
|
||||
't=true',
|
||||
'f=False',
|
||||
]
|
||||
test_r = {
|
||||
'b64address': 'VdNmakxFORPSyfCprAD/eDDPk5TY9QYtSA==',
|
||||
'name': 'test',
|
||||
'amount': 5.3,
|
||||
'n': 5,
|
||||
'address': 'bY13xeAjLrsjP4KGETwStK2a9UgKgXVTXu',
|
||||
't': True,
|
||||
'f': False,
|
||||
}
|
||||
self.assertDictEqual(test_r, DaemonCLI.get_params_from_kwargs(test_params))
|
||||
|
|
Loading…
Add table
Reference in a new issue