Fix choices validation with unannotated args

Something like:

    @cmdutils.argument('foo', choices=['one', 'two'])
    def func(foo):
        # ...

didn't actually validate the foo argument, since the inferred type of
the argument is None, and that skipped all conversion (and thus
validation).

Fixes #1871
See #1885

This is a reworked version of 12061b8bb1
which lets special parameters (count/win_id/flags) through correctly.
This commit is contained in:
Florian Bruhin 2016-08-23 22:01:21 +02:00
parent ce4dcf9e80
commit 943dc564b2
2 changed files with 37 additions and 4 deletions

View File

@ -340,12 +340,17 @@ class Command:
Args:
param: The inspect.Parameter to look at.
"""
arginfo = self.get_arg_info(param)
if param.annotation is not inspect.Parameter.empty:
return param.annotation
elif param.default is None or param.default is inspect.Parameter.empty:
elif param.default not in [None, inspect.Parameter.empty]:
return type(param.default)
elif arginfo.count or arginfo.win_id or param.kind in [
inspect.Parameter.VAR_POSITIONAL,
inspect.Parameter.VAR_KEYWORD]:
return None
else:
return type(param.default)
return str
def _get_self_arg(self, win_id, param, args):
"""Get the self argument for a function call.
@ -425,10 +430,10 @@ class Command:
elif typ is str:
choices = self.get_arg_info(param).choices
value = argparser.type_conv(param, typ, value, str_choices=choices)
elif typ is None:
pass
elif typ is bool: # no type conversion for flags
assert isinstance(value, bool)
elif typ is None:
pass
else:
value = argparser.type_conv(param, typ, value)

View File

@ -295,6 +295,34 @@ class TestRegister:
else:
assert cmd._get_call_args(win_id=0) == ([expected], {})
def test_choices_no_annotation(self):
# https://github.com/The-Compiler/qutebrowser/issues/1871
@cmdutils.register()
@cmdutils.argument('arg', choices=['foo', 'bar'])
def fun(arg):
"""Blah."""
pass
cmd = cmdutils.cmd_dict['fun']
cmd.namespace = cmd.parser.parse_args(['fish'])
with pytest.raises(cmdexc.ArgumentTypeError):
cmd._get_call_args(win_id=0)
def test_choices_no_annotation_kwonly(self):
# https://github.com/The-Compiler/qutebrowser/issues/1871
@cmdutils.register()
@cmdutils.argument('arg', choices=['foo', 'bar'])
def fun(*, arg):
"""Blah."""
pass
cmd = cmdutils.cmd_dict['fun']
cmd.namespace = cmd.parser.parse_args(['--arg=fish'])
with pytest.raises(cmdexc.ArgumentTypeError):
cmd._get_call_args(win_id=0)
def test_pos_arg_info(self):
@cmdutils.register()
@cmdutils.argument('foo', choices=('a', 'b'))