Get rid of dict annotations
This commit is contained in:
parent
d990032a2e
commit
1611562271
@ -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
|
e.g. an argument `foo=True` will be converted to a flag `-f`/`--foo` in
|
||||||
qutebrowser's commandline.
|
qutebrowser's commandline.
|
||||||
|
|
||||||
This behavior can be overridden using Python's
|
The type can be overridden using Python's
|
||||||
http://legacy.python.org/dev/peps/pep-3107/[function annotations]. The
|
http://legacy.python.org/dev/peps/pep-3107/[function annotations]:
|
||||||
annotation should always be a `dict`, like this:
|
|
||||||
|
|
||||||
[source,python]
|
[source,python]
|
||||||
----
|
----
|
||||||
@cmdutils.register(...)
|
@cmdutils.register(...)
|
||||||
def foo(bar: {'type': int}, baz=True):
|
def foo(bar: int, baz=True):
|
||||||
...
|
...
|
||||||
----
|
----
|
||||||
|
|
||||||
The following keys are supported in the dict:
|
Possible values:
|
||||||
|
|
||||||
* `type`: The type this value should have. The value entered by the user is
|
|
||||||
then automatically checked. Possible values:
|
|
||||||
- A callable (`int`, `float`, etc.): Gets called to validate/convert the
|
- A callable (`int`, `float`, etc.): Gets called to validate/convert the
|
||||||
value.
|
value.
|
||||||
- A string: The value must match exactly (mainly useful with tuples to get
|
- A string: The value must match exactly (mainly useful with tuples to get
|
||||||
|
@ -455,8 +455,7 @@ class CommandDispatcher:
|
|||||||
self._open(url, tab, background, window)
|
self._open(url, tab, background, window)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
def navigate(self, where: {'type': ('prev', 'next', 'up', 'increment',
|
def navigate(self, where: ('prev', 'next', 'up', 'increment', 'decrement'),
|
||||||
'decrement')},
|
|
||||||
tab=False, bg=False, window=False):
|
tab=False, bg=False, window=False):
|
||||||
"""Open typical prev/next links or navigate using the URL path.
|
"""Open typical prev/next links or navigate using the URL path.
|
||||||
|
|
||||||
@ -505,7 +504,7 @@ class CommandDispatcher:
|
|||||||
@cmdutils.register(instance='command-dispatcher', hide=True,
|
@cmdutils.register(instance='command-dispatcher', hide=True,
|
||||||
scope='window')
|
scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@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.
|
"""Scroll the current tab by 'count * dx/dy' pixels.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -522,7 +521,7 @@ class CommandDispatcher:
|
|||||||
@cmdutils.register(instance='command-dispatcher', hide=True,
|
@cmdutils.register(instance='command-dispatcher', hide=True,
|
||||||
scope='window')
|
scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@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.
|
"""Scroll the current tab in the given direction.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -583,8 +582,7 @@ class CommandDispatcher:
|
|||||||
scope='window')
|
scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
@cmdutils.argument('horizontal', flag='x')
|
@cmdutils.argument('horizontal', flag='x')
|
||||||
def scroll_perc(self, perc: {'type': float}=None, horizontal=False,
|
def scroll_perc(self, perc: float=None, horizontal=False, count=None):
|
||||||
count=None):
|
|
||||||
"""Scroll to a specific percentage of the page.
|
"""Scroll to a specific percentage of the page.
|
||||||
|
|
||||||
The percentage can be given either as argument or as count.
|
The percentage can be given either as argument or as count.
|
||||||
@ -622,9 +620,9 @@ class CommandDispatcher:
|
|||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
@cmdutils.argument('top_navigate', metavar='ACTION')
|
@cmdutils.argument('top_navigate', metavar='ACTION')
|
||||||
@cmdutils.argument('bottom_navigate', metavar='ACTION')
|
@cmdutils.argument('bottom_navigate', metavar='ACTION')
|
||||||
def scroll_page(self, x: {'type': float}, y: {'type': float}, *,
|
def scroll_page(self, x: float, y: float, *,
|
||||||
top_navigate: {'type': ('prev', 'decrement')}=None,
|
top_navigate: ('prev', 'decrement')=None,
|
||||||
bottom_navigate: {'type': ('next', 'increment')}=None,
|
bottom_navigate: ('next', 'increment')=None,
|
||||||
count=1):
|
count=1):
|
||||||
"""Scroll the frame page-wise.
|
"""Scroll the frame page-wise.
|
||||||
|
|
||||||
@ -738,7 +736,7 @@ class CommandDispatcher:
|
|||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@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.
|
"""Set the zoom level for the current tab.
|
||||||
|
|
||||||
The zoom can be given as argument or as [count]. If neither of both is
|
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.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@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].
|
"""Select the tab given as argument/[count].
|
||||||
|
|
||||||
If neither count nor index are given, it behaves like tab-next.
|
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.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@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.
|
"""Move the current tab.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -87,14 +87,8 @@ class Command:
|
|||||||
_count: The count set for the command.
|
_count: The count set for the command.
|
||||||
_instance: The object to bind 'self' to.
|
_instance: The object to bind 'self' to.
|
||||||
_scope: The scope to get _instance for in the object registry.
|
_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,
|
def __init__(self, *, handler, name, instance=None, maxsplit=None,
|
||||||
hide=False, completion=None, modes=None, not_modes=None,
|
hide=False, completion=None, modes=None, not_modes=None,
|
||||||
needs_js=False, debug=False, ignore_args=False,
|
needs_js=False, debug=False, ignore_args=False,
|
||||||
@ -256,14 +250,13 @@ class Command:
|
|||||||
|
|
||||||
if not self.ignore_args:
|
if not self.ignore_args:
|
||||||
for param in signature.parameters.values():
|
for param in signature.parameters.values():
|
||||||
annotation_info = self._parse_annotation(param)
|
|
||||||
if param.name == 'self':
|
if param.name == 'self':
|
||||||
continue
|
continue
|
||||||
if self._inspect_special_param(param):
|
if self._inspect_special_param(param):
|
||||||
continue
|
continue
|
||||||
typ = self._get_type(param, annotation_info)
|
typ = self._get_type(param)
|
||||||
kwargs = self._param_to_argparse_kwargs(param, annotation_info)
|
kwargs = self._param_to_argparse_kwargs(param, typ)
|
||||||
args = self._param_to_argparse_args(param, annotation_info)
|
args = self._param_to_argparse_args(param, typ)
|
||||||
self._type_conv.update(self._get_typeconv(param, typ))
|
self._type_conv.update(self._get_typeconv(param, typ))
|
||||||
callsig = debug_utils.format_call(
|
callsig = debug_utils.format_call(
|
||||||
self.parser.add_argument, args, kwargs,
|
self.parser.add_argument, args, kwargs,
|
||||||
@ -273,18 +266,17 @@ class Command:
|
|||||||
self.parser.add_argument(*args, **kwargs)
|
self.parser.add_argument(*args, **kwargs)
|
||||||
return signature.parameters.keys()
|
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.
|
"""Get argparse keyword arguments for a parameter.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
param: The inspect.Parameter object to get the args for.
|
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:
|
Return:
|
||||||
A kwargs dict.
|
A kwargs dict.
|
||||||
"""
|
"""
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
typ = self._get_type(param, annotation_info)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kwargs['help'] = self.docparser.arg_descs[param.name]
|
kwargs['help'] = self.docparser.arg_descs[param.name]
|
||||||
@ -314,12 +306,12 @@ class Command:
|
|||||||
kwargs['nargs'] = '?'
|
kwargs['nargs'] = '?'
|
||||||
return kwargs
|
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.
|
"""Get argparse positional arguments for a parameter.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
param: The inspect.Parameter object to get the args for.
|
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:
|
Return:
|
||||||
A list of args.
|
A list of args.
|
||||||
@ -337,7 +329,6 @@ class Command:
|
|||||||
raise ValueError("Flag '{}' of parameter {} (command {}) must be "
|
raise ValueError("Flag '{}' of parameter {} (command {}) must be "
|
||||||
"exactly 1 char!".format(shortname, name,
|
"exactly 1 char!".format(shortname, name,
|
||||||
self.name))
|
self.name))
|
||||||
typ = self._get_type(param, annotation_info)
|
|
||||||
if typ is bool or param.kind == inspect.Parameter.KEYWORD_ONLY:
|
if typ is bool or param.kind == inspect.Parameter.KEYWORD_ONLY:
|
||||||
long_flag = '--{}'.format(name)
|
long_flag = '--{}'.format(name)
|
||||||
short_flag = '-{}'.format(shortname)
|
short_flag = '-{}'.format(shortname)
|
||||||
@ -351,33 +342,14 @@ class Command:
|
|||||||
self.pos_args.append((param.name, name))
|
self.pos_args.append((param.name, name))
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def _parse_annotation(self, param):
|
def _get_type(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):
|
|
||||||
"""Get the type of an argument from its default value or annotation.
|
"""Get the type of an argument from its default value or annotation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
param: The inspect.Parameter to look at.
|
param: The inspect.Parameter to look at.
|
||||||
annotation_info: An AnnotationInfo tuple which overrides the type.
|
|
||||||
"""
|
"""
|
||||||
if annotation_info.type is not None:
|
if param.annotation is not inspect.Parameter.empty:
|
||||||
return annotation_info.type
|
return param.annotation
|
||||||
elif param.default is None or param.default is inspect.Parameter.empty:
|
elif param.default is None or param.default is inspect.Parameter.empty:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
|
@ -388,7 +388,7 @@ class SessionManager(QObject):
|
|||||||
completion=[usertypes.Completion.sessions],
|
completion=[usertypes.Completion.sessions],
|
||||||
instance='session-manager')
|
instance='session-manager')
|
||||||
@cmdutils.argument('win_id', win_id=True)
|
@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):
|
quiet=False, force=False):
|
||||||
"""Save a session.
|
"""Save a session.
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
|
|||||||
|
|
||||||
@cmdutils.register(maxsplit=1, no_cmd_split=True)
|
@cmdutils.register(maxsplit=1, no_cmd_split=True)
|
||||||
@cmdutils.argument('win_id', win_id=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.
|
"""Execute a command after some time.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -71,7 +71,7 @@ def later(ms: {'type': int}, command, win_id):
|
|||||||
|
|
||||||
@cmdutils.register(maxsplit=1, no_cmd_split=True)
|
@cmdutils.register(maxsplit=1, no_cmd_split=True)
|
||||||
@cmdutils.argument('win_id', win_id=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.
|
"""Repeat a given command.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -119,7 +119,7 @@ def message_warning(win_id, text):
|
|||||||
|
|
||||||
|
|
||||||
@cmdutils.register(debug=True)
|
@cmdutils.register(debug=True)
|
||||||
def debug_crash(typ: {'type': ('exception', 'segfault')}='exception'):
|
def debug_crash(typ: ('exception', 'segfault')='exception'):
|
||||||
"""Crash for debugging purposes.
|
"""Crash for debugging purposes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
Loading…
Reference in New Issue
Block a user