From 0c1d6159b891f11010803d6a8d7d9a83590c9c78 Mon Sep 17 00:00:00 2001 From: Matt Patrick Date: Tue, 26 Feb 2019 16:16:22 -0500 Subject: [PATCH] Relaxes type restriction on parameters decorator argument --- brewtils/decorators.py | 11 ++++++----- test/decorators_test.py | 42 +++++++++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/brewtils/decorators.py b/brewtils/decorators.py index bf927086..c45ed535 100644 --- a/brewtils/decorators.py +++ b/brewtils/decorators.py @@ -298,7 +298,7 @@ def cmd1(self, **kwargs): pass Args: - *args (list): Positional arguments + *args (iterable): Positional arguments The first (and only) positional argument must be a list containing dictionaries that describe parameters. @@ -306,8 +306,6 @@ def cmd1(self, **kwargs): func: The decorated function """ if len(args) == 1: - if not isinstance(args[0], list): - raise PluginParamError("@parameters argument must be a list") return functools.partial(parameters, args[0]) elif len(args) != 2: raise PluginParamError("@parameters takes a single argument") @@ -315,8 +313,11 @@ def cmd1(self, **kwargs): if not isinstance(args[1], types.FunctionType): raise PluginParamError("@parameters must be applied to a function") - for param in args[0]: - parameter(args[1], **param) + try: + for param in args[0]: + parameter(args[1], **param) + except TypeError: + raise PluginParamError("@parameters argument must be iterable of dictionaries") @wrapt.decorator(enabled=_wrap_functions) def wrapper(_double_wrapped, _, _args, _kwargs): diff --git a/test/decorators_test.py b/test/decorators_test.py index 2860a1b1..2c6a6926 100644 --- a/test/decorators_test.py +++ b/test/decorators_test.py @@ -368,14 +368,44 @@ def func2(_, foo): func1._command.parameters[0], func2._command.parameters[0] ) - @pytest.mark.parametrize("args", [[], [1], [1, 2], [1, 2, 3], lazy_fixture("cmd")]) - def test_bad_arguments(self, args): - # Can't put lazy fixture in a list inside of parametrize... - if not isinstance(args, list): - args = [args] + @pytest.mark.parametrize("args", [[], [1, 2, 3]]) + def test_bad_arity(self, args): + # Must be called with either just one arg, or one arg + the function + with pytest.raises(PluginParamError) as ex: + parameters(*args) + assert "single argument" in str(ex) + @pytest.mark.parametrize( + "arg1,arg2", + [ + (1, cmd), # arg1 needs to be iterable + ([1], cmd), # arg1 item needs to be **able + ([], 1), # arg2 must be a FunctionType + ], + ) + def test_bad_args(self, arg1, arg2): with pytest.raises(PluginParamError): - parameters(*args) + parameters(arg1, arg2) + + def test_dict_values(self, cmd, param_definition, wrap_functions): + test_mock = Mock() + wrapped = parameters({"foo": param_definition}.values(), cmd) + + assert len(cmd._command.parameters) == 1 + assert cmd._command.parameters[0].key == "foo" + assert wrapped(self, test_mock) == test_mock + + def test_dict_values_decorator(self, param_definition, wrap_functions): + test_mock = Mock() + param_spec = {"foo": param_definition} + + @parameters(param_spec.values()) + def func(_, foo): + return foo + + assert len(func._command.parameters) == 1 + assert func._command.parameters[0].key == "foo" + assert func(self, test_mock) == test_mock class TestCommand(object):