Skip to content

Commit

Permalink
Refs #29253 -- Fixed method_decorator() crash if decorator sets a new…
Browse files Browse the repository at this point in the history
… attribute.

Regression in fdc936c.
  • Loading branch information
cjerdonek authored and timgraham committed Jun 27, 2018
1 parent f52b026 commit f434f5b
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 3 deletions.
8 changes: 5 additions & 3 deletions django/utils/decorators.py
Expand Up @@ -2,7 +2,7 @@

# For backwards compatibility in Django 2.0.
from contextlib import ContextDecorator # noqa
from functools import WRAPPER_ASSIGNMENTS, update_wrapper, wraps
from functools import WRAPPER_ASSIGNMENTS, partial, update_wrapper, wraps


class classonlymethod(classmethod):
Expand Down Expand Up @@ -36,8 +36,10 @@ def _multi_decorate(decorators, method):

def _wrapper(self, *args, **kwargs):
# bound_method has the signature that 'decorator' expects i.e. no
# 'self' argument.
bound_method = method.__get__(self, type(self))
# '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)))
for dec in decorators:
bound_method = dec(bound_method)
return bound_method(*args, **kwargs)
Expand Down
15 changes: 15 additions & 0 deletions tests/decorators/tests.py
Expand Up @@ -271,6 +271,21 @@ def method(self):
self.assertEqual(Test.method.__doc__, 'A method')
self.assertEqual(Test.method.__name__, 'method')

def test_new_attribute(self):
"""A decorator that sets a new attribute on the method."""
def decorate(func):
func.x = 1
return func

class MyClass:
@method_decorator(decorate)
def method(self):
return True

obj = MyClass()
self.assertEqual(obj.method.x, 1)
self.assertIs(obj.method(), True)

def test_bad_iterable(self):
decorators = {myattr_dec_m, myattr2_dec_m}
msg = "'set' object is not subscriptable"
Expand Down

0 comments on commit f434f5b

Please sign in to comment.