diff --git a/src/decorators.py b/src/decorators.py index 245bc6d..14aa6e0 100644 --- a/src/decorators.py +++ b/src/decorators.py @@ -157,7 +157,7 @@ def _update_adapter(wrapper, target): WRAPPER_ARGLIST = ('wrapped', 'instance', 'args', 'kwargs') -def decorator(wrapper=None, target=None): +def decorator(wrapper=None, target=None, validate=True): # The decorator takes some optional keyword parameters to change its # behaviour. The decorator works out whether parameters have been # passed based on whether the first positional argument, which is @@ -165,7 +165,12 @@ def decorator(wrapper=None, target=None): # supplied. The 'target' argument is used to optionally denote a # function which is wrapped by an adapter decorator. In that case # the name attributes are copied from the target function rather - # than those of the adapter function. + # than those of the adapter function. The 'validate' argument, which + # defaults to True, indicates whether validation of decorator + # parameters should be validated at the time the decorator is + # applied, or whether a failure is allow to occur only when the + # wrapped function is later called and the user wrapper function + # thus called. if wrapper is not None: # We now need to work out whether the users decorator is @@ -196,8 +201,9 @@ def decorator(wrapper=None, target=None): # decorator is used and not only when the # function is later called. - _validate_parameters(wrapper, wrapper_argspec, - *decorator_args, **decorator_kwargs) + if validate: + _validate_parameters(wrapper, wrapper_argspec, + *decorator_args, **decorator_kwargs) # Now create and return the final wrapper which # combines the parameters with the wrapped function. @@ -235,7 +241,7 @@ def decorator(wrapper=None, target=None): # a partial using the collected default parameters and the # adapter function if one is being used. - return partial(decorator, target=target) + return partial(decorator, target=target, validate=validate) def adapter(target): @decorator(target=target) diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 4bebc51..9b89f11 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -279,5 +279,22 @@ class TestDecorator(unittest.TestCase): self.assertEqual(result, (_args, _kwargs)) + def test_parameter_missing_no_validation(self): + _args = (1, 2) + _kwargs = { 'one': 1, 'two': 2 } + + @wrapt.decorator(validate=False) + def _decorator(wrapped, instance, args, kwargs, p1, p2=2): + return wrapped(*args, **kwargs) + + @_decorator() + def _function(*args, **kwargs): + return args, kwargs + + def run(): + result = _function(*_args, **_kwargs) + + self.assertRaises(TypeError, run, ()) + if __name__ == '__main__': unittest.main()