summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinay Karanam <vinayinvicible@gmail.com>2021-08-23 18:28:38 +0530
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-10-20 18:52:10 +0200
commit354bbf1fd22cd0a826e8da75ba16bc28fc274868 (patch)
tree93ffd034e8957a8229efb3120841f3a0dcd5c92d
parent5d62beb61a7d5a6bb2755d2cdabc8e31f462391f (diff)
[4.0.x] Fixed #33043 -- Made method_decorator() preserve wrapper assignments.
Regression in f434f5b84f7fcea9a76a551621ecce70786e2899. Backport of 8806e8809e023017e6958b9fa0bbd960938e0a91 from main
-rw-r--r--django/utils/decorators.py2
-rw-r--r--tests/decorators/tests.py23
2 files changed, 24 insertions, 1 deletions
diff --git a/django/utils/decorators.py b/django/utils/decorators.py
index 5c9a5d01c7..69aca10a4d 100644
--- a/django/utils/decorators.py
+++ b/django/utils/decorators.py
@@ -37,7 +37,7 @@ def _multi_decorate(decorators, method):
# '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)
diff --git a/tests/decorators/tests.py b/tests/decorators/tests.py
index 46b01c1852..e496e2c790 100644
--- a/tests/decorators/tests.py
+++ b/tests/decorators/tests.py
@@ -425,6 +425,29 @@ class MethodDecoratorTests(SimpleTestCase):
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):
"""