Skip to content

Commit

Permalink
Fixed #33043 -- Made method_decorator() preserve wrapper assignments.
Browse files Browse the repository at this point in the history
Regression in f434f5b.
  • Loading branch information
vinayinvicible authored and felixxm committed Oct 20, 2021
1 parent 004b462 commit 8806e88
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
2 changes: 1 addition & 1 deletion django/utils/decorators.py
Expand Up @@ -37,7 +37,7 @@ def _wrapper(self, *args, **kwargs):
# 'self' argument, but it's a closure over self so it can call
# 'func'. Also, wrap method.__get__() in a function because new
# attributes can't be set on bound method objects, only on functions.
bound_method = partial(method.__get__(self, type(self)))
bound_method = wraps(method)(partial(method.__get__(self, type(self))))
for dec in decorators:
bound_method = dec(bound_method)
return bound_method(*args, **kwargs)
Expand Down
23 changes: 23 additions & 0 deletions tests/decorators/tests.py
Expand Up @@ -425,6 +425,29 @@ class Test:
def __module__(cls):
return "tests"

def test_wrapper_assignments(self):
"""@method_decorator preserves wrapper assignments."""
func_name = None
func_module = None

def decorator(func):
@wraps(func)
def inner(*args, **kwargs):
nonlocal func_name, func_module
func_name = getattr(func, '__name__', None)
func_module = getattr(func, '__module__', None)
return func(*args, **kwargs)
return inner

class Test:
@method_decorator(decorator)
def method(self):
return 'tests'

Test().method()
self.assertEqual(func_name, 'method')
self.assertIsNotNone(func_module)


class XFrameOptionsDecoratorsTests(TestCase):
"""
Expand Down

0 comments on commit 8806e88

Please sign in to comment.