This commit is contained in:
Florian Bruhin 2014-09-14 23:56:19 +02:00
parent 063be350e4
commit 4d3b3616a6
6 changed files with 93 additions and 69 deletions

View File

@ -257,7 +257,7 @@ class CommandDispatcher:
@cmdutils.register(instance='mainwindow.tabs.cmd')
def hint(self, group=webelem.Group.all, target=hints.Target.normal,
*args : {'nargs': '*'}):
*args: {'nargs': '*'}):
"""Start hinting.
Args:
@ -603,7 +603,7 @@ class CommandDispatcher:
self.openurl(config.get('general', 'startpage')[0])
@cmdutils.register(instance='mainwindow.tabs.cmd')
def run_userscript(self, cmd, *args : {'nargs': '*'}):
def run_userscript(self, cmd, *args: {'nargs': '*'}):
"""Run an userscript given as argument.
Args:

View File

@ -164,7 +164,7 @@ class register: # pylint: disable=invalid-name
Return:
The original function (unmodified).
"""
global aliases, cmd_dict
global aliases
self.func = func
names = self._get_names()
log.commands.vdebug("Registering command {}".format(names[0]))
@ -178,6 +178,7 @@ class register: # pylint: disable=invalid-name
self.parser.add_argument('-h', '--help', action=argparser.HelpAction,
default=argparser.SUPPRESS, nargs=0,
help=argparser.SUPPRESS)
self._check_func()
has_count, desc, type_conv = self._inspect_func()
cmd = command.Command(
name=names[0], split=self.split, hide=self.hide, count=has_count,
@ -210,6 +211,35 @@ class register: # pylint: disable=invalid-name
else:
return self.name
def _check_func(self):
"""Make sure the function parameters don't violate any rules."""
signature = inspect.signature(self.func)
if 'self' in signature.parameters and self.instance is None:
raise TypeError("{} is a class method, but instance was not "
"given!".format(self.name[0]))
elif 'self' not in signature.parameters and self.instance is not None:
raise TypeError("{} is not a class method, but instance was "
"given!".format(self.name[0]))
elif inspect.getfullargspec(self.func).varkw is not None:
raise TypeError("{}: functions with varkw arguments are not "
"supported!".format(self.name[0]))
def _get_typeconv(self, param, typ):
"""Get a dict with a type conversion for the parameter.
Args:
param: The inspect.Parameter to handle.
typ: The type of the parameter.
"""
type_conv = {}
if utils.is_enum(typ):
type_conv[param.name] = argparser.enum_getter(typ)
elif isinstance(typ, tuple):
if param.default is not inspect.Parameter.empty:
typ = typ + (type(param.default),)
type_conv[param.name] = argparser.multitype_conv(typ)
return type_conv
def _inspect_func(self):
"""Inspect the function to get useful informations from it.
@ -221,15 +251,6 @@ class register: # pylint: disable=invalid-name
"""
type_conv = {}
signature = inspect.signature(self.func)
if 'self' in signature.parameters and self.instance is None:
raise TypeError("{} is a class method, but instance was not "
"given!".format(self.name[0]))
elif 'self' not in signature.parameters and self.instance is not None:
raise TypeError("{} is not a class method, but instance was "
"given!".format(self.name[0]))
elif inspect.getfullargspec(self.func).varkw is not None:
raise TypeError("{}: functions with varkw arguments are not "
"supported!".format(self.name[0]))
has_count = 'count' in signature.parameters
doc = inspect.getdoc(self.func)
if doc is not None:
@ -240,27 +261,17 @@ class register: # pylint: disable=invalid-name
for param in signature.parameters.values():
if param.name in ('self', 'count'):
continue
argparse_args = []
argparse_kwargs = {}
annotation_info = self._parse_annotation(param)
typ = self._get_type(param, annotation_info)
args, kwargs = self._param_to_argparse_args(
param, annotation_info)
argparse_args += args
argparse_kwargs.update(kwargs)
argparse_kwargs.update(annotation_info.kwargs)
typ = self._get_type(param, annotation_info)
if utils.is_enum(typ):
type_conv[param.name] = argparser.enum_getter(typ)
elif isinstance(typ, tuple):
if param.default is not inspect.Parameter.empty:
typ = typ + (type(param.default),)
type_conv[param.name] = argparser.multitype_conv(typ)
type_conv.update(self._get_typeconv(param, typ))
callsig = debugutils.format_call(
self.parser.add_argument, argparse_args, argparse_kwargs,
self.parser.add_argument, args, kwargs,
full=False)
log.commands.vdebug('Adding arg {} of type {} -> {}'.format(
param.name, typ, callsig))
self.parser.add_argument(*argparse_args, **argparse_kwargs)
self.parser.add_argument(*args, **kwargs)
return has_count, desc, type_conv
def _param_to_argparse_args(self, param, annotation_info):
@ -317,7 +328,7 @@ class register: # pylint: disable=invalid-name
else:
args.append(name)
self.pos_args.append(name)
kwargs.update(annotation_info.kwargs)
return args, kwargs
def _parse_annotation(self, param):

View File

@ -98,59 +98,45 @@ class Command:
raise cmdexc.PrerequisitesError(
"{}: This command needs javascript enabled.".format(self.name))
def run(self, args=None, count=None):
"""Run the command.
Note we don't catch CommandError here as it might happen async.
def _get_args(self, func, count, # noqa, pylint: disable=too-many-branches
namespace):
"""Get arguments for a function call.
Args:
args: Arguments to the command.
count: Command repetition count.
func: The function to be called.
count: The count to be added to the call.
namespace: The argparse namespace.
Return:
An (args, kwargs) tuple.
"""
dbgout = ["command called:", self.name]
if args:
dbgout.append(str(args))
if count is not None:
dbgout.append("(count={})".format(count))
log.commands.debug(' '.join(dbgout))
posargs = []
args = []
kwargs = {}
app = QCoreApplication.instance()
try:
namespace = self.parser.parse_args(args)
except argparser.ArgumentParserError as e:
message.error('{}: {}'.format(self.name, e))
return
except argparser.ArgumentParserExit as e:
log.commands.debug("argparser exited with status {}: {}".format(
e.status, e))
return
signature = inspect.signature(self.handler)
signature = inspect.signature(func)
for i, param in enumerate(signature.parameters.values()):
if i == 0 and self.instance is not None:
# Special case for 'self'.
assert param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
app = QCoreApplication.instance()
if self.instance == '':
obj = app
else:
obj = utils.dotted_getattr(app, self.instance)
posargs.append(obj)
args.append(obj)
continue
elif param.name == 'count':
# Special case for 'count'.
if not self.count:
raise TypeError("{}: count argument given with a command "
"which does not support count!".format(
self.name))
self.name))
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
if count is not None:
posargs.append(count)
args.append(count)
else:
posargs.append(param.default)
args.append(param.default)
elif param.kind == inspect.Parameter.KEYWORD_ONLY:
if count is not None:
kwargs['count'] = count
@ -167,16 +153,43 @@ class Command:
# want.
value = self.type_conv[param.name](value)
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
posargs.append(value)
args.append(value)
elif param.kind == inspect.Parameter.VAR_POSITIONAL:
if value is not None:
posargs += value
args += value
elif param.kind == inspect.Parameter.KEYWORD_ONLY:
kwargs[param.name] = value
else:
raise TypeError("{}: Invalid parameter type {} for argument "
"'{}'!".format(
self.name, param.kind, param.name))
return args, kwargs
def run(self, args=None, count=None):
"""Run the command.
Note we don't catch CommandError here as it might happen async.
Args:
args: Arguments to the command.
count: Command repetition count.
"""
dbgout = ["command called:", self.name]
if args:
dbgout.append(str(args))
if count is not None:
dbgout.append("(count={})".format(count))
log.commands.debug(' '.join(dbgout))
try:
namespace = self.parser.parse_args(args)
except argparser.ArgumentParserError as e:
message.error('{}: {}'.format(self.name, e))
return
except argparser.ArgumentParserExit as e:
log.commands.debug("argparser exited with status {}: {}".format(
e.status, e))
return
posargs, kwargs = self._get_args(self.handler, count, namespace)
self._check_prerequisites()
log.commands.debug('Calling {}'.format(
debug.format_call(self.handler, posargs, kwargs)))

View File

@ -283,7 +283,8 @@ class ConfigManager(QObject):
@cmdutils.register(name='get', instance='config',
completion=[Completion.section, Completion.option])
def get_command(self, section, option):
def get_command(self, sectname: {'name': 'section'},
optname: {'name': 'option'}):
"""Get the value from a section/option.
//
@ -291,16 +292,16 @@ class ConfigManager(QObject):
Wrapper for the get-command to output the value in the status bar.
Args:
section: The section where the option is in.
option: The name of the option.
sectname: The section where the option is in.
optname: The name of the option.
"""
try:
val = self.get(section, option, transformed=False)
val = self.get(sectname, optname, transformed=False)
except (NoOptionError, NoSectionError) as e:
raise cmdexc.CommandError("get: {} - {}".format(
e.__class__.__name__, e))
else:
message.info("{} {} = {}".format(section, option, val),
message.info("{} {} = {}".format(sectname, optname, val),
immediately=True)
@functools.lru_cache()
@ -336,7 +337,8 @@ class ConfigManager(QObject):
@cmdutils.register(name='set', instance='config',
completion=[Completion.section, Completion.option,
Completion.value])
def set_command(self, section, option, value, temp=False):
def set_command(self, section, # pylint: disable=redefined-outer-name
option, value, temp=False):
"""Set an option.
//

View File

@ -161,12 +161,12 @@ class KeyConfigParser(QObject):
raise cmdexc.CommandError("Invalid mode {}!".format(m))
try:
sect = self.keybindings[mode]
except KeyError as e:
except KeyError:
raise cmdexc.CommandError("Can't find mode section '{}'!".format(
sect))
try:
del sect[key]
except KeyError as e:
except KeyError:
raise cmdexc.CommandError("Can't find binding '{}' in section "
"'{}'!".format(key, mode))
else:

View File

@ -136,5 +136,3 @@ HANDLERS = {
'gpl': qute_gpl,
'help': qute_help,
}