diff --git a/django/utils/decorators.py b/django/utils/decorators.py index 4ccf1d69dff..fbcf4edf139 100644 --- a/django/utils/decorators.py +++ b/django/utils/decorators.py @@ -22,7 +22,7 @@ def method_decorator(decorator): def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): - return func(self, *args2, **kwargs2) + return func.__get__(self, type(self))(*args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. diff --git a/tests/decorators/tests.py b/tests/decorators/tests.py index e72e6cfee33..4a49dcc71da 100644 --- a/tests/decorators/tests.py +++ b/tests/decorators/tests.py @@ -232,9 +232,45 @@ class MethodDecoratorTests(TestCase): def method(self): return True - # t = Test() self.assertEqual(Test().method(), False) + def test_descriptors(self): + + def original_dec(wrapped): + def _wrapped(arg): + return wrapped(arg) + + return _wrapped + + method_dec = method_decorator(original_dec) + + class bound_wrapper(object): + def __init__(self, wrapped): + self.wrapped = wrapped + self.__name__ = wrapped.__name__ + + def __call__(self, arg): + return self.wrapped(arg) + + def __get__(self, instance, owner): + return self + + class descriptor_wrapper(object): + def __init__(self, wrapped): + self.wrapped = wrapped + self.__name__ = wrapped.__name__ + + def __get__(self, instance, owner): + return bound_wrapper(self.wrapped.__get__(instance, owner)) + + class Test(object): + @method_dec + @descriptor_wrapper + def method(self, arg): + return arg + + self.assertEqual(Test().method(1), 1) + class XFrameOptionsDecoratorsTests(TestCase): """