diff options
| author | Vinay Karanam <vinayinvicible@gmail.com> | 2021-08-23 18:28:38 +0530 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-10-20 18:52:10 +0200 |
| commit | 354bbf1fd22cd0a826e8da75ba16bc28fc274868 (patch) | |
| tree | 93ffd034e8957a8229efb3120841f3a0dcd5c92d | |
| parent | 5d62beb61a7d5a6bb2755d2cdabc8e31f462391f (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.py | 2 | ||||
| -rw-r--r-- | tests/decorators/tests.py | 23 |
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): """ |
