summaryrefslogtreecommitdiff
path: root/qutebrowser
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2020-10-07 15:54:47 +0200
committerFlorian Bruhin <me@the-compiler.org>2021-01-26 20:32:37 +0100
commit273734c9aa4ac80c7fa29b47255c741841ac9864 (patch)
treeb9b6b36a22e5783626835e98c29a8812391274cd /qutebrowser
parent41dc2913097a6e028237289c6ac8607668156c7d (diff)
downloadqutebrowser-273734c9aa4ac80c7fa29b47255c741841ac9864.tar.gz
qutebrowser-273734c9aa4ac80c7fa29b47255c741841ac9864.zip
command: Only do function inspection once
Diffstat (limited to 'qutebrowser')
-rw-r--r--qutebrowser/commands/command.py42
1 files changed, 19 insertions, 23 deletions
diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py
index 0410a7b23..5ec14b557 100644
--- a/qutebrowser/commands/command.py
+++ b/qutebrowser/commands/command.py
@@ -125,6 +125,9 @@ class Command:
self.flags_with_args: MutableSequence[str] = []
self._has_vararg = False
+ self._signature = inspect.signature(handler)
+ self._type_hints = typing.get_type_hints(handler)
+
# This is checked by future @cmdutils.argument calls so they fail
# (as they'd be silently ignored otherwise)
self._qute_args = getattr(self.handler, 'qute_args', {})
@@ -154,20 +157,19 @@ class Command:
def _check_func(self):
"""Make sure the function parameters don't violate any rules."""
- signature = inspect.signature(self.handler)
- if 'self' in signature.parameters:
+ if 'self' in self._signature.parameters:
if self._instance is None:
raise TypeError("{} is a class method, but instance was not "
"given!".format(self.name))
- arg_info = self.get_arg_info(signature.parameters['self'])
+ arg_info = self.get_arg_info(self._signature.parameters['self'])
if arg_info.value is not None:
raise TypeError("{}: Can't fill 'self' with value!"
.format(self.name))
- elif 'self' not in signature.parameters and self._instance is not None:
+ elif 'self' not in self._signature.parameters and self._instance is not None:
raise TypeError("{} is not a class method, but instance was "
"given!".format(self.name))
elif any(param.kind == inspect.Parameter.VAR_KEYWORD
- for param in signature.parameters.values()):
+ for param in self._signature.parameters.values()):
raise TypeError("{}: functions with varkw arguments are not "
"supported!".format(self.name))
@@ -215,16 +217,13 @@ class Command:
Return:
How many user-visible arguments the command has.
"""
- signature = inspect.signature(self.handler)
- type_hints = typing.get_type_hints(self.handler)
-
doc = inspect.getdoc(self.handler)
if doc is not None:
self.desc = doc.splitlines()[0].strip()
else:
self.desc = ""
- for param in signature.parameters.values():
+ for param in self._signature.parameters.values():
# https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind
# "Python has no explicit syntax for defining positional-only
# parameters, but many built-in and extension module functions
@@ -240,7 +239,7 @@ class Command:
raise TypeError("{}: handler has keyword only argument {!r} "
"without default!".format(
self.name, param.name))
- typ = self._get_type(param, type_hints)
+ typ = self._get_type(param)
is_bool = typ is bool
kwargs = self._param_to_argparse_kwargs(param, is_bool)
args = self._param_to_argparse_args(param, is_bool)
@@ -252,7 +251,7 @@ class Command:
self.parser.add_argument(*args, **kwargs)
if param.kind == inspect.Parameter.VAR_POSITIONAL:
self._has_vararg = True
- return signature.parameters.values()
+ return self._signature.parameters.values()
def _param_to_argparse_kwargs(self, param, is_bool):
"""Get argparse keyword arguments for a parameter.
@@ -330,12 +329,11 @@ class Command:
self.pos_args.append((param.name, name))
return args
- def _get_type(self, param, type_hints):
+ 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.
- type_hints: The dict returned by typing.get_type_hints
"""
arg_info = self.get_arg_info(param)
if arg_info.value:
@@ -344,12 +342,12 @@ class Command:
elif param.kind in [inspect.Parameter.VAR_POSITIONAL,
inspect.Parameter.VAR_KEYWORD]:
# For *args/**kwargs we only support strings
- if param.name in type_hints and type_hints[param.name] != str:
+ if param.name in self._type_hints and self._type_hints[param.name] != str:
raise TypeError("Expected str annotation for {}, got {}".format(
- param, type_hints[param.name]))
+ param, self._type_hints[param.name]))
return None
- elif param.name in type_hints:
- return type_hints[param.name]
+ elif param.name in self._type_hints:
+ return self._type_hints[param.name]
elif param.default not in [None, inspect.Parameter.empty]:
return type(param.default)
else:
@@ -402,10 +400,10 @@ class Command:
self._add_special_arg(value=tab, param=param, args=args,
kwargs=kwargs)
- def _get_param_value(self, param, type_hints):
+ def _get_param_value(self, param):
"""Get the converted value for an inspect.Parameter."""
value = getattr(self.namespace, param.name)
- typ = self._get_type(param, type_hints)
+ typ = self._get_type(param)
if isinstance(typ, tuple):
raise TypeError("{}: Legacy tuple type annotation!".format(
@@ -501,16 +499,14 @@ class Command:
"""
args: Any = []
kwargs: MutableMapping[str, Any] = {}
- signature = inspect.signature(self.handler)
- type_hints = typing.get_type_hints(self.handler)
- for i, param in enumerate(signature.parameters.values()):
+ for i, param in enumerate(self._signature.parameters.values()):
if self._handle_special_call_arg(pos=i, param=param,
win_id=win_id, args=args,
kwargs=kwargs):
continue
- value = self._get_param_value(param, type_hints)
+ value = self._get_param_value(param)
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
args.append(value)
elif param.kind == inspect.Parameter.VAR_POSITIONAL: