Ticket #13879: ticket13879-r16259.diff

File ticket13879-r16259.diff, 3.9 KB (added by adurdin, 4 years ago)

Patch with fix and tests against trunk revision 16259

  • tests/regressiontests/decorators/tests.py

     
    33from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
    44from django.contrib.admin.views.decorators import staff_member_required
    55from django.http import HttpResponse, HttpRequest, HttpResponseNotAllowed
    6 from django.utils.decorators import method_decorator
     6from django.utils.decorators import method_decorator, method_decorator_with_args
    77from django.utils.functional import allow_lazy, lazy, memoize
    88from django.utils.unittest import TestCase
    99from django.views.decorators.http import require_http_methods, require_GET, require_POST, require_safe
     
    201201
    202202        self.assertEqual(Test.method.__doc__, 'A method')
    203203        self.assertEqual(Test.method.im_func.__name__, 'method')
     204
     205
     206# For testing method_decorator_with_args, a decorator factory, that returns
     207# a decorator that assumes a single argument. We will get type arguments if
     208# there is a mismatch in the number of arguments.
     209def prefix_arg(prefix):
     210    def dec(func):
     211        def wrapper(arg):
     212            return func(prefix + arg)
     213        return wraps(func)(wrapper)
     214    return dec
     215
     216prefix_arg_m = method_decorator_with_args(prefix_arg)
     217
     218# For testing method_decorator_with_args, a decorator factory that returns
     219# a decorator that adds an attribute to the function.
     220def add_attr(attname):
     221    def dec(func):
     222        def wrapper(*args, **kwargs):
     223            return func(*args, **kwargs)
     224        setattr(wrapper, attname, True)
     225        return wraps(func)(wrapper)
     226    return dec
     227
     228add_attr_m = method_decorator_with_args(add_attr)
     229
     230class MethodDecoratorWithArgsTests(TestCase):
     231    """
     232    Tests for method_decorator_with_args
     233    """
     234    def test_preserve_signature(self):
     235        class Test(object):
     236            @prefix_arg_m("test:")
     237            def say(self, arg):
     238                return arg
     239
     240        self.assertEqual("test:hello", Test().say("hello"))
     241
     242    def test_preserve_attributes(self):
     243        # Sanity check add_attr
     244        @add_attr('myattr')
     245        @add_attr('myattr2')
     246        def func():
     247            pass
     248
     249        self.assertEqual(getattr(func, 'myattr', False), True)
     250        self.assertEqual(getattr(func, 'myattr2', False), True)
     251
     252        # Now check method_decorator
     253        class Test(object):
     254            @add_attr_m('myattr')
     255            @add_attr_m('myattr2')
     256            def method(self):
     257                "A method"
     258                pass
     259
     260        self.assertEqual(getattr(Test().method, 'myattr', False), True)
     261        self.assertEqual(getattr(Test().method, 'myattr2', False), True)
     262
     263        self.assertEqual(getattr(Test.method, 'myattr', False), True)
     264        self.assertEqual(getattr(Test.method, 'myattr2', False), True)
     265
     266        self.assertEqual(Test.method.__doc__, 'A method')
     267        self.assertEqual(Test.method.im_func.__name__, 'method')
  • django/utils/decorators.py

     
    4040    return _dec
    4141
    4242
     43def method_decorator_with_args(decorator_factory):
     44    """
     45    Converts a function decorator factory (e.g. `permission_required`) into a
     46    method decorator factory.
     47    """
     48    def _method_dec_factory(*args, **kwargs):
     49        return method_decorator(decorator_factory(*args, **kwargs))
     50    update_wrapper(_method_dec_factory, decorator_factory)
     51    # Change the name to aid debugging.
     52    _method_dec_factory.__name__ = 'method_decorator_with_args(%s)' % decorator_factory.__name__
     53    return _method_dec_factory
     54
     55
    4356def decorator_from_middleware_with_args(middleware_class):
    4457    """
    4558    Like decorator_from_middleware, but returns a function
Back to Top