Browse Source

Allow class methods to define tasks

georgepsarakis 8 years ago
parent
commit
8c4e6dd8a3
2 changed files with 17 additions and 1 deletions
  1. 5 1
      celery/utils/functional.py
  2. 12 0
      t/unit/utils/test_functional.py

+ 5 - 1
celery/utils/functional.py

@@ -266,7 +266,11 @@ def head_from_fun(fun, bound=False, debug=False):
     # in pure-Python.  Instead we use exec to create a new function
     # in pure-Python.  Instead we use exec to create a new function
     # with an empty body, meaning it has the same performance as
     # with an empty body, meaning it has the same performance as
     # as just calling a function.
     # as just calling a function.
-    if not inspect.isfunction(fun) and hasattr(fun, '__call__'):
+    is_function = inspect.isfunction(fun)
+    is_callable = hasattr(fun, '__call__')
+    is_method = inspect.ismethod(fun)
+
+    if not is_function and is_callable and not is_method:
         name, fun = fun.__class__.__name__, fun.__call__
         name, fun = fun.__class__.__name__, fun.__call__
     else:
     else:
         name = fun.__name__
         name = fun.__name__

+ 12 - 0
t/unit/utils/test_functional.py

@@ -205,6 +205,18 @@ class test_head_from_fun:
         g(a=1, b=2)
         g(a=1, b=2)
         g(a=1, b=2, c=3)
         g(a=1, b=2, c=3)
 
 
+    def test_classmethod(self):
+        class A(object):
+            @classmethod
+            def f(cls, x):
+                return x
+
+        fun = head_from_fun(A.f, bound=False)
+        assert fun(A, 1) == 1
+
+        fun = head_from_fun(A.f, bound=True)
+        assert fun(1) == 1
+
 
 
 class test_fun_takes_argument:
 class test_fun_takes_argument: