cmdutils.register: annotation -> arg for flags
Instead of using a 'flag' key in the annotation dict, we now use a flags argument to @cmdutils.register which is a {argument: flag} dict. See #637.
This commit is contained in:
parent
49fb981e7f
commit
5eff35ba30
@ -439,8 +439,6 @@ then automatically checked. Possible values:
|
||||
- A python enum type: All members of the enum are possible values.
|
||||
- A tuple of multiple types above: Any of these types are valid values,
|
||||
e.g. `('foo', 'bar')` or `(int, 'foo')`.
|
||||
* `flag`: The flag to be used, as 1-char string (default: First char of the
|
||||
long name).
|
||||
|
||||
The name of an argument will always be the parameter name, with any trailing
|
||||
underscores stripped.
|
||||
|
@ -575,9 +575,10 @@ class CommandDispatcher:
|
||||
widget.keyReleaseEvent(release_evt)
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', hide=True,
|
||||
scope='window', count='count')
|
||||
def scroll_perc(self, perc: {'type': float}=None,
|
||||
horizontal: {'flag': 'x'}=False, count=None):
|
||||
scope='window', count='count',
|
||||
flags={'horizontal': 'x'})
|
||||
def scroll_perc(self, perc: {'type': float}=None, horizontal=False,
|
||||
count=None):
|
||||
"""Scroll to a specific percentage of the page.
|
||||
|
||||
The percentage can be given either as argument or as count.
|
||||
|
@ -53,6 +53,7 @@ class Command:
|
||||
win_id_arg: The name of the win_id parameter, or None.
|
||||
flags_with_args: A list of flags which take an argument.
|
||||
no_cmd_split: If true, ';;' to split sub-commands is ignored.
|
||||
_flags: A mapping of argument names to alternative flags
|
||||
_type_conv: A mapping of conversion functions for arguments.
|
||||
_needs_js: Whether the command needs javascript enabled
|
||||
_modes: The modes the command can be executed in.
|
||||
@ -66,12 +67,12 @@ class Command:
|
||||
"""
|
||||
|
||||
AnnotationInfo = collections.namedtuple(
|
||||
'AnnotationInfo', ['type', 'flag', 'hide', 'metavar'])
|
||||
'AnnotationInfo', ['type', 'hide', 'metavar'])
|
||||
|
||||
def __init__(self, *, handler, name, instance=None, maxsplit=None,
|
||||
hide=False, completion=None, modes=None, not_modes=None,
|
||||
needs_js=False, debug=False, ignore_args=False,
|
||||
deprecated=False, no_cmd_split=False,
|
||||
deprecated=False, no_cmd_split=False, flags=None,
|
||||
star_args_optional=False, scope='global', count=None,
|
||||
win_id=None):
|
||||
# I really don't know how to solve this in a better way, I tried.
|
||||
@ -100,6 +101,7 @@ class Command:
|
||||
self._scope = scope
|
||||
self._needs_js = needs_js
|
||||
self._star_args_optional = star_args_optional
|
||||
self._flags = flags or {}
|
||||
self.debug = debug
|
||||
self.ignore_args = ignore_args
|
||||
self.handler = handler
|
||||
@ -121,10 +123,18 @@ class Command:
|
||||
self.desc = None
|
||||
self.flags_with_args = []
|
||||
self._type_conv = {}
|
||||
count = self._inspect_func()
|
||||
if self.completion is not None and len(self.completion) > count:
|
||||
|
||||
args = self._inspect_func()
|
||||
|
||||
if self.completion is not None and len(self.completion) > len(args):
|
||||
raise ValueError("Got {} completions, but only {} "
|
||||
"arguments!".format(len(self.completion), count))
|
||||
"arguments!".format(len(self.completion),
|
||||
len(args)))
|
||||
for argname in self._flags:
|
||||
if argname not in args:
|
||||
raise ValueError("Got argument {} in flags param, but no such "
|
||||
"argument exists for {}".format(
|
||||
argname, self.name))
|
||||
|
||||
def _check_prerequisites(self, win_id):
|
||||
"""Check if the command is permitted to run currently.
|
||||
@ -211,7 +221,6 @@ class Command:
|
||||
"""
|
||||
signature = inspect.signature(self.handler)
|
||||
doc = inspect.getdoc(self.handler)
|
||||
arg_count = 0
|
||||
if doc is not None:
|
||||
self.desc = doc.splitlines()[0].strip()
|
||||
else:
|
||||
@ -233,7 +242,6 @@ class Command:
|
||||
continue
|
||||
if self._inspect_special_param(param):
|
||||
continue
|
||||
arg_count += 1
|
||||
typ = self._get_type(param, annotation_info)
|
||||
kwargs = self._param_to_argparse_kwargs(param, annotation_info)
|
||||
args = self._param_to_argparse_args(param, annotation_info)
|
||||
@ -244,7 +252,7 @@ class Command:
|
||||
log.commands.vdebug('Adding arg {} of type {} -> {}'.format(
|
||||
param.name, typ, callsig))
|
||||
self.parser.add_argument(*args, **kwargs)
|
||||
return arg_count
|
||||
return signature.parameters.keys()
|
||||
|
||||
def _param_to_argparse_kwargs(self, param, annotation_info):
|
||||
"""Get argparse keyword arguments for a parameter.
|
||||
@ -297,7 +305,7 @@ class Command:
|
||||
"""
|
||||
args = []
|
||||
name = arg_name(param.name)
|
||||
shortname = annotation_info.flag or name[0]
|
||||
shortname = self._flags.get(param.name, name[0])
|
||||
if len(shortname) != 1:
|
||||
raise ValueError("Flag '{}' of parameter {} (command {}) must be "
|
||||
"exactly 1 char!".format(shortname, name,
|
||||
@ -325,14 +333,13 @@ class Command:
|
||||
Return:
|
||||
An AnnotationInfo namedtuple.
|
||||
typ: The type to use for this argument.
|
||||
flag: The short name/flag if overridden.
|
||||
name: The long name if overridden.
|
||||
"""
|
||||
info = {'type': None, 'flag': None, 'hide': False, 'metavar': None}
|
||||
info = {'type': None, 'hide': False, 'metavar': None}
|
||||
if param.annotation is not inspect.Parameter.empty:
|
||||
log.commands.vdebug("Parsing annotation {}".format(
|
||||
param.annotation))
|
||||
for field in ('type', 'flag', 'name', 'hide', 'metavar'):
|
||||
for field in ('type', 'name', 'hide', 'metavar'):
|
||||
if field in param.annotation:
|
||||
info[field] = param.annotation[field]
|
||||
return self.AnnotationInfo(**info)
|
||||
|
@ -207,9 +207,9 @@ class TestRegister:
|
||||
assert parser.parse_args(['-a']).arg
|
||||
assert not parser.parse_args([]).arg
|
||||
|
||||
def test_flag_annotation(self):
|
||||
@cmdutils.register()
|
||||
def fun(arg: {'flag': 'b'}=False):
|
||||
def test_flag_argument(self):
|
||||
@cmdutils.register(flags={'arg': 'b'})
|
||||
def fun(arg=False):
|
||||
"""Blah."""
|
||||
pass
|
||||
parser = cmdutils.cmd_dict['fun'].parser
|
||||
@ -217,3 +217,10 @@ class TestRegister:
|
||||
assert parser.parse_args(['-b']).arg
|
||||
with pytest.raises(argparser.ArgumentParserError):
|
||||
parser.parse_args(['-a'])
|
||||
|
||||
def test_unknown_argument_in_flags(self):
|
||||
with pytest.raises(ValueError):
|
||||
@cmdutils.register(flags={'foobar': 'f'})
|
||||
def fun():
|
||||
"""Blah."""
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user