Commit 80cd64ee authored by Marc Tamlyn's avatar Marc Tamlyn
Browse files

Fixed #21247 -- Made method_decorator play nicely with descriptors

When a method decorator was used in conjunction with a decorator
implemented as a descriptor, method_decorator did not correctly respect
the method binding.

Thanks for Graham Dumpleton for the report and initial patch.
parent 97a8fd46
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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.
+37 −1
Original line number Diff line number Diff line
@@ -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):
    """