diff --git a/girder_worker_utils/decorators.py b/girder_worker_utils/decorators.py index c6d8466..4175586 100644 --- a/girder_worker_utils/decorators.py +++ b/girder_worker_utils/decorators.py @@ -30,12 +30,23 @@ def __init__(self, name, **kwargs): for k, v in six.iteritems(kwargs): setattr(self, k, v) + # No default value for this argument -class Arg(Argument): pass +class Arg(Argument): + pass + + # Has a default argument for the value -class KWArg(Argument): pass -class Varargs(Argument): pass -class Kwargs(Argument): pass +class KWArg(Argument): + pass + + +class Varargs(Argument): + pass + + +class Kwargs(Argument): + pass # class Return(Argument): pass @@ -43,8 +54,6 @@ def _clean_function_doc(f): doc = getdoc(f) or '' if isinstance(doc, bytes): doc = doc.decode('utf-8') - else: - doc = cleandoc(doc) return doc @@ -81,7 +90,7 @@ def __getitem__(self, key): return self._construct_argument( self._get_class(self._signature.parameters[key]), key) - def _construct_argument(self, cls, name, **kwargs): + def _construct_argument(self, parameter_cls, name): p = self._signature.parameters[name] metadata = {} @@ -93,7 +102,7 @@ def _construct_argument(self, cls, name, **kwargs): metadata.update(self._metadata.get(name, {})) - return cls(name, **metadata) + return parameter_cls(name, **metadata) def _is_varargs(self, p): return p.kind == Parameter.VAR_POSITIONAL @@ -121,22 +130,20 @@ def _get_class(self, p): else: raise RuntimeError("Could not determine parameter type!") + def init_metadata(self, name): + if name not in self._metadata: + self._metadata[name] = {} def set_metadata(self, name, key, value): if name not in self._signature.parameters: raise RuntimeError("{} is not a valid argument to this function!") - if name not in self._metadata: - self._metadata[name] = {} + self.init_metadata(name) self._metadata[name][key] = value @property def arguments(self): - # Only return arguments if we've declared them as paramaters - # This prevents us from returning things like 'self' of bound - # methods (e.g. celery tasks) etc. This is a dubious design - # decision. return [ self._construct_argument( self._get_class(self._signature.parameters[name]), name) @@ -170,7 +177,7 @@ def parameter(name, **kwargs): raise TypeError('Expected argument name to be a string') data_type = kwargs.get("data_type", None) - if data_type is not None and callable(data_type): + if callable(data_type): kwargs['data_type'] = data_type(name, **kwargs) def argument_wrapper(func): @@ -184,7 +191,7 @@ def argument_wrapper(func): # the full list of parameters that have been identified by the # user (even if there is no actual metadata associated with # the argument). - desc._metadata[name] = {} + desc.init_metadata(name) for key, value in six.iteritems(kwargs): desc.set_metadata(name, key, value) diff --git a/girder_worker_utils/tests/decorators_test.py b/girder_worker_utils/tests/decorators_test.py index cd15cb8..eaae61e 100644 --- a/girder_worker_utils/tests/decorators_test.py +++ b/girder_worker_utils/tests/decorators_test.py @@ -2,7 +2,14 @@ from girder_worker_utils import decorators from girder_worker_utils import types -from girder_worker_utils.decorators import argument +from girder_worker_utils.decorators import ( + argument, + parameter, + GWFuncDesc, + Varargs, + Kwargs, + Arg, + KWArg) @argument('n', types.Integer, help='The element to return') @@ -173,22 +180,8 @@ def test_unhandled_input_binding(): with pytest.raises(ValueError): decorators.get_input_data(arg, {}) - - ########################### - -import six - -from girder_worker_utils.decorators import parameter -from girder_worker_utils.decorators import ( - GWFuncDesc, - Varargs, - Kwargs, - Arg, - KWArg) - - def arg(a): pass # noqa def varargs(*args): pass # noqa def kwarg(a='test'): pass # noqa @@ -205,7 +198,6 @@ def arg_kwarg_kwargs(a, b='test', **kwargs): pass # noqa def arg_kwarg_varargs_kwargs(a, b='test', *args, **kwargs): pass # noqa - @pytest.mark.parametrize('func,classes', [ (arg, [Arg]), (varargs, [Varargs]), @@ -233,6 +225,7 @@ def test_GWFuncDesc_arguments_returns_expected_classes(func, classes): arg_kwargs, kwarg_kwarg, kwarg_kwargs, arg_kwarg_kwargs] + @pytest.mark.parametrize('func', no_varargs) def test_GWFuncDesc_varargs_returns_None(func): spec = GWFuncDesc(func) @@ -242,6 +235,7 @@ def test_GWFuncDesc_varargs_returns_None(func): with_varargs = [varargs, arg_varargs, kwarg_varargs, arg_kwarg_varargs, arg_kwarg_varargs_kwargs] + @pytest.mark.parametrize('func', with_varargs) def test_GWFuncDesc_varargs_returns_Vararg(func): spec = GWFuncDesc(func) @@ -284,6 +278,7 @@ def test_GWFuncDesc_keyword_args_correct_names(func, names): assert isinstance(p, KWArg) assert p.name == n + # TODO keyword_args returns None test @pytest.mark.parametrize('func,defaults', [ (kwarg, ['test']), @@ -302,7 +297,9 @@ def test_GWFuncDesc_keyword_args_have_defaults(func, defaults): assert hasattr(p, 'default') assert p.default == d -@pytest.mark.skip("Fix this to use API for accessing argument spec rather than using 'private' attribute") + +@pytest.mark.skip("Fix this to use API for accessing argument " + "spec rather than using 'private' attribute") def test_parameter_decorator_adds_metadata(): @parameter('a', test='TEST') def arg(a): diff --git a/girder_worker_utils/tests/py3_decorators_test.py b/girder_worker_utils/tests/py3_decorators_test.py index fc614f4..306632c 100644 --- a/girder_worker_utils/tests/py3_decorators_test.py +++ b/girder_worker_utils/tests/py3_decorators_test.py @@ -1,17 +1,18 @@ import pytest -import six from girder_worker_utils.decorators import ( GWFuncDesc, Varargs, - Kwargs, + # Kwargs, Arg, KWArg) -def arg_varargs_kwarg(a, *args, b='test'): pass -def arg_varargs_kwarg_no_default(a, *args, b): pass -def arg_emptyvarargs_kwarg(a, *, b='test'): pass -def arg_emptyvarargs_kwarg_no_default(a, *, b): pass -def arg_with_annotation(a: int): pass +# TODO write Kwargs test + +def arg_varargs_kwarg(a, *args, b='test'): pass # noqa +def arg_varargs_kwarg_no_default(a, *args, b): pass # noqa +def arg_emptyvarargs_kwarg(a, *, b='test'): pass # noqa +def arg_emptyvarargs_kwarg_no_default(a, *, b): pass # noqa +def arg_with_annotation(a: int): pass # noqa @pytest.mark.parametrize('func,classes', [ @@ -79,6 +80,7 @@ def test_GWFuncDesc_keyword_args_correct_names(func, names): # TODO keyword_args returns None test + @pytest.mark.parametrize('func,defaults', [ (arg_varargs_kwarg, ['test']), (arg_emptyvarargs_kwarg, ['test']) @@ -90,6 +92,7 @@ def test_GWFuncDesc_keyword_args_have_defaults(func, defaults): assert hasattr(p, 'default') assert p.default == d + @pytest.mark.parametrize('func', [ arg_varargs_kwarg_no_default, arg_emptyvarargs_kwarg_no_default