Get rid of dict annotations

This commit is contained in:
Florian Bruhin 2016-05-10 22:03:10 +02:00
parent d990032a2e
commit 1611562271
5 changed files with 28 additions and 62 deletions

View File

@ -416,21 +416,17 @@ The types of the function arguments are inferred based on their default values,
e.g. an argument `foo=True` will be converted to a flag `-f`/`--foo` in
qutebrowser's commandline.
This behavior can be overridden using Python's
http://legacy.python.org/dev/peps/pep-3107/[function annotations]. The
annotation should always be a `dict`, like this:
The type can be overridden using Python's
http://legacy.python.org/dev/peps/pep-3107/[function annotations]:
[source,python]
----
@cmdutils.register(...)
def foo(bar: {'type': int}, baz=True):
def foo(bar: int, baz=True):
...
----
The following keys are supported in the dict:
* `type`: The type this value should have. The value entered by the user is
then automatically checked. Possible values:
Possible values:
- A callable (`int`, `float`, etc.): Gets called to validate/convert the
value.
- A string: The value must match exactly (mainly useful with tuples to get

View File

@ -455,8 +455,7 @@ class CommandDispatcher:
self._open(url, tab, background, window)
@cmdutils.register(instance='command-dispatcher', scope='window')
def navigate(self, where: {'type': ('prev', 'next', 'up', 'increment',
'decrement')},
def navigate(self, where: ('prev', 'next', 'up', 'increment', 'decrement'),
tab=False, bg=False, window=False):
"""Open typical prev/next links or navigate using the URL path.
@ -505,7 +504,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.argument('count', count=True)
def scroll_px(self, dx: {'type': int}, dy: {'type': int}, count=1):
def scroll_px(self, dx: int, dy: int, count=1):
"""Scroll the current tab by 'count * dx/dy' pixels.
Args:
@ -522,7 +521,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.argument('count', count=True)
def scroll(self, direction: {'type': (str, int)}, count=1):
def scroll(self, direction: (str, int), count=1):
"""Scroll the current tab in the given direction.
Args:
@ -583,8 +582,7 @@ class CommandDispatcher:
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('horizontal', flag='x')
def scroll_perc(self, perc: {'type': float}=None, horizontal=False,
count=None):
def scroll_perc(self, perc: 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.
@ -622,9 +620,9 @@ class CommandDispatcher:
@cmdutils.argument('count', count=True)
@cmdutils.argument('top_navigate', metavar='ACTION')
@cmdutils.argument('bottom_navigate', metavar='ACTION')
def scroll_page(self, x: {'type': float}, y: {'type': float}, *,
top_navigate: {'type': ('prev', 'decrement')}=None,
bottom_navigate: {'type': ('next', 'increment')}=None,
def scroll_page(self, x: float, y: float, *,
top_navigate: ('prev', 'decrement')=None,
bottom_navigate: ('next', 'increment')=None,
count=1):
"""Scroll the frame page-wise.
@ -738,7 +736,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def zoom(self, zoom: {'type': int}=None, count=None):
def zoom(self, zoom: int=None, count=None):
"""Set the zoom level for the current tab.
The zoom can be given as argument or as [count]. If neither of both is
@ -921,7 +919,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def tab_focus(self, index: {'type': (int, 'last')}=None, count=None):
def tab_focus(self, index: (int, 'last')=None, count=None):
"""Select the tab given as argument/[count].
If neither count nor index are given, it behaves like tab-next.
@ -954,7 +952,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def tab_move(self, direction: {'type': ('+', '-')}=None, count=None):
def tab_move(self, direction: ('+', '-')=None, count=None):
"""Move the current tab.
Args:

View File

@ -87,14 +87,8 @@ class Command:
_count: The count set for the command.
_instance: The object to bind 'self' to.
_scope: The scope to get _instance for in the object registry.
Class attributes:
AnnotationInfo: Named tuple for info from an annotation.
"""
AnnotationInfo = collections.namedtuple(
'AnnotationInfo', ['type'])
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,
@ -256,14 +250,13 @@ class Command:
if not self.ignore_args:
for param in signature.parameters.values():
annotation_info = self._parse_annotation(param)
if param.name == 'self':
continue
if self._inspect_special_param(param):
continue
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)
typ = self._get_type(param)
kwargs = self._param_to_argparse_kwargs(param, typ)
args = self._param_to_argparse_args(param, typ)
self._type_conv.update(self._get_typeconv(param, typ))
callsig = debug_utils.format_call(
self.parser.add_argument, args, kwargs,
@ -273,18 +266,17 @@ class Command:
self.parser.add_argument(*args, **kwargs)
return signature.parameters.keys()
def _param_to_argparse_kwargs(self, param, annotation_info):
def _param_to_argparse_kwargs(self, param, typ):
"""Get argparse keyword arguments for a parameter.
Args:
param: The inspect.Parameter object to get the args for.
annotation_info: An AnnotationInfo tuple for the parameter.
typ: The type of the parameter
Return:
A kwargs dict.
"""
kwargs = {}
typ = self._get_type(param, annotation_info)
try:
kwargs['help'] = self.docparser.arg_descs[param.name]
@ -314,12 +306,12 @@ class Command:
kwargs['nargs'] = '?'
return kwargs
def _param_to_argparse_args(self, param, annotation_info):
def _param_to_argparse_args(self, param, typ):
"""Get argparse positional arguments for a parameter.
Args:
param: The inspect.Parameter object to get the args for.
annotation_info: An AnnotationInfo tuple for the parameter.
typ: The type of the parameter
Return:
A list of args.
@ -337,7 +329,6 @@ class Command:
raise ValueError("Flag '{}' of parameter {} (command {}) must be "
"exactly 1 char!".format(shortname, name,
self.name))
typ = self._get_type(param, annotation_info)
if typ is bool or param.kind == inspect.Parameter.KEYWORD_ONLY:
long_flag = '--{}'.format(name)
short_flag = '-{}'.format(shortname)
@ -351,33 +342,14 @@ class Command:
self.pos_args.append((param.name, name))
return args
def _parse_annotation(self, param):
"""Get argparse arguments and type from a parameter annotation.
Args:
param: A inspect.Parameter instance.
Return:
An AnnotationInfo namedtuple.
typ: The type to use for this argument.
name: The long name if overridden.
"""
info = {'type': None}
if param.annotation is not inspect.Parameter.empty:
log.commands.vdebug("Parsing annotation {}".format(
param.annotation))
info['type'] = param.annotation['type']
return self.AnnotationInfo(**info)
def _get_type(self, param, annotation_info):
def _get_type(self, param):
"""Get the type of an argument from its default value or annotation.
Args:
param: The inspect.Parameter to look at.
annotation_info: An AnnotationInfo tuple which overrides the type.
"""
if annotation_info.type is not None:
return annotation_info.type
if param.annotation is not inspect.Parameter.empty:
return param.annotation
elif param.default is None or param.default is inspect.Parameter.empty:
return None
else:

View File

@ -388,7 +388,7 @@ class SessionManager(QObject):
completion=[usertypes.Completion.sessions],
instance='session-manager')
@cmdutils.argument('win_id', win_id=True)
def session_save(self, win_id, name: {'type': str}=default, current=False,
def session_save(self, win_id, name: str=default, current=False,
quiet=False, force=False):
"""Save a session.

View File

@ -41,7 +41,7 @@ from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
@cmdutils.register(maxsplit=1, no_cmd_split=True)
@cmdutils.argument('win_id', win_id=True)
def later(ms: {'type': int}, command, win_id):
def later(ms: int, command, win_id):
"""Execute a command after some time.
Args:
@ -71,7 +71,7 @@ def later(ms: {'type': int}, command, win_id):
@cmdutils.register(maxsplit=1, no_cmd_split=True)
@cmdutils.argument('win_id', win_id=True)
def repeat(times: {'type': int}, command, win_id):
def repeat(times: int, command, win_id):
"""Repeat a given command.
Args:
@ -119,7 +119,7 @@ def message_warning(win_id, text):
@cmdutils.register(debug=True)
def debug_crash(typ: {'type': ('exception', 'segfault')}='exception'):
def debug_crash(typ: ('exception', 'segfault')='exception'):
"""Crash for debugging purposes.
Args: