summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorRigel Di Scala <rigel.discala@propylon.com>2015-07-21 21:54:37 +0100
committerTim Graham <timograham@gmail.com>2015-08-01 08:38:03 -0400
commit3bdaaf6777804d33ee46cdb5a889b8cc544a91f1 (patch)
tree86399ce870c06f59584c98bc3988d9ed8c739c87 /django
parent1a76257b1b385ac8afd67bd36d061f508613e4d2 (diff)
Fixed #25146 -- Allowed method_decorator() to decorate classes.
Diffstat (limited to 'django')
-rw-r--r--django/utils/decorators.py33
1 files changed, 29 insertions, 4 deletions
diff --git a/django/utils/decorators.py b/django/utils/decorators.py
index 1ea12b32d2..294761672c 100644
--- a/django/utils/decorators.py
+++ b/django/utils/decorators.py
@@ -17,13 +17,34 @@ class classonlymethod(classmethod):
return super(classonlymethod, self).__get__(instance, owner)
-def method_decorator(decorator):
+def method_decorator(decorator, name=''):
"""
Converts a function decorator into a method decorator
"""
- # 'func' is a function at the time it is passed to _dec, but will eventually
- # be a method of the class it is defined on.
- def _dec(func):
+ # 'obj' can be a class or a function. If 'obj' is a function at the time it
+ # is passed to _dec, it will eventually be a method of the class it is
+ # defined on. If 'obj' is a class, the 'name' is required to be the name
+ # of the method that will be decorated.
+ def _dec(obj):
+ is_class = isinstance(obj, type)
+ if is_class:
+ if name and hasattr(obj, name):
+ func = getattr(obj, name)
+ if not callable(func):
+ raise TypeError(
+ "Cannot decorate '{0}' as it isn't a callable "
+ "attribute of {1} ({2})".format(name, obj, func)
+ )
+ else:
+ raise ValueError(
+ "The keyword argument `name` must be the name of a method "
+ "of the decorated class: {0}. Got '{1}' instead".format(
+ obj, name,
+ )
+ )
+ else:
+ func = obj
+
def _wrapper(self, *args, **kwargs):
@decorator
def bound_func(*args2, **kwargs2):
@@ -43,6 +64,10 @@ def method_decorator(decorator):
# Need to preserve any existing attributes of 'func', including the name.
update_wrapper(_wrapper, func)
+ if is_class:
+ setattr(obj, name, _wrapper)
+ return obj
+
return _wrapper
update_wrapper(_dec, decorator, assigned=available_attrs(decorator))