command: Iterate over function signature when calling instead over namespace.

This commit is contained in:
Florian Bruhin 2014-09-14 22:48:25 +02:00
parent 4b759c5513
commit d4f584684b

View File

@ -19,6 +19,8 @@
"""Contains the Command class, a skeleton for a command.""" """Contains the Command class, a skeleton for a command."""
import inspect
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
@ -126,36 +128,51 @@ class Command:
e.status, e)) e.status, e))
return return
for name, arg in vars(namespace).items(): signature = inspect.signature(self.handler)
if isinstance(arg, list):
# If we got a list, we assume that's our *args, so we don't add for i, param in enumerate(signature.parameters.values()):
# it to kwargs. if i == 0 and self.instance is not None:
# FIXME: This approach is rather naive, but for now it works. # Special case for 'self'.
posargs += arg assert param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
if self.instance == '':
obj = app
else:
obj = utils.dotted_getattr(app, self.instance)
posargs.append(obj)
continue
elif param.name == 'count':
# Special case for 'count'.
if not self.count:
raise TypeError("{}: count argument given with a command "
"which does not support count!".format(
self.name))
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
posargs.append(count)
elif param.kind == inspect.Parameter.KEYWORD_ONLY:
kwargs['count'] = count
else:
raise TypeError("{}: invalid parameter type {} for "
"argument 'count'!".format(
self.name, param.kind))
continue
value = getattr(namespace, param.name)
if param.name in self.type_conv:
# We convert enum types after getting the values from
# argparse, because argparse's choices argument is
# processed after type conversation, which is not what we
# want.
value = self.type_conv[param.name](value)
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
posargs.append(value)
elif param.kind == inspect.Parameter.VAR_POSITIONAL:
posargs += value
elif param.kind == inspect.Parameter.KEYWORD_ONLY:
kwargs[param.name] = value
else: else:
if name in self.type_conv: raise TypeError("{}: Invalid parameter type {} for argument "
# We convert enum types after getting the values from "'{}'!".format(
# argparse, because argparse's choices argument is self.name, param.kind, param.name))
# processed after type conversation, which is not what we
# want.
arg = self.type_conv[name](arg)
kwargs[name] = arg
if self.instance is not None:
# Add the 'self' parameter.
if self.instance == '':
obj = app
else:
obj = utils.dotted_getattr(app, self.instance)
posargs.insert(0, obj)
if count is not None and self.count:
kwargs = {'count': count}
self._check_prerequisites() self._check_prerequisites()
log.commands.debug('Calling {}'.format( log.commands.debug('Calling {}'.format(
debug.format_call(self.handler, posargs, kwargs))) debug.format_call(self.handler, posargs, kwargs)))
# FIXME this won't work properly if some arguments are required to be
# positional, e.g.:
# def fun(one=True, two=False, *args)
self.handler(*posargs, **kwargs) self.handler(*posargs, **kwargs)