Browse Source

[backward incompatible] Signature.__call__ should call task directly to be consistent with the "Calling API". Closes #1426

Ask Solem 11 years ago
parent
commit
5b61b802d8
2 changed files with 35 additions and 10 deletions
  1. 6 2
      celery/canvas.py
  2. 29 8
      docs/userguide/canvas.rst

+ 6 - 2
celery/canvas.py

@@ -139,8 +139,11 @@ class Signature(dict):
              immutable=immutable)
 
     def __call__(self, *partial_args, **partial_kwargs):
+        args, kwargs, _ = self._merge(partial_args, partial_kwargs, None)
+        return self.type(*args, **kwargs)
+
+    def delay(self, *partial_args, **partial_kwargs):
         return self.apply_async(partial_args, partial_kwargs)
-    delay = __call__
 
     def apply(self, args=(), kwargs={}, **options):
         """Apply this task locally."""
@@ -150,7 +153,8 @@ class Signature(dict):
 
     def _merge(self, args=(), kwargs={}, options={}):
         if self.immutable:
-            return self.args, self.kwargs, dict(self.options, **options)
+            return (self.args, self.kwargs,
+                    dict(self.options, **options) if options else self.options)
         return (tuple(args) + tuple(self.args) if args else self.args,
                 dict(self.kwargs, **kwargs) if kwargs else self.kwargs,
                 dict(self.options, **options) if options else self.options)

+ 29 - 8
docs/userguide/canvas.rst

@@ -59,14 +59,30 @@ or even serialized and sent across the wire.
         >>> s.options
         {'countdown': 10}
 
-- It supports the "Calling API" which means it takes the same arguments
-  as the :meth:`~@Task.apply_async` method::
+- It supports the "Calling API" which means it supports ``delay`` and
+  ``apply_async`` or being called directly.
 
-    >>> add.apply_async(args, kwargs, **options)
-    >>> add.subtask(args, kwargs, **options).apply_async()
+    Calling the subtask will execute the task inline in the current process::
 
-    >>> add.apply_async((2, 2), countdown=1)
-    >>> add.subtask((2, 2), countdown=1).apply_async()
+        >>> add(2, 2)
+        4
+        >>> add.s(2, 2)()
+        4
+
+  ``delay`` is our beloved shortcut to ``apply_async`` taking star-arguments::
+
+        >>> result = add.delay(2, 2)
+        >>> result.get()
+        4
+
+    ``apply_async`` takes the same arguments
+    as the :meth:`Task.apply_async <@Task.apply_async>` method::
+
+        >>> add.apply_async(args, kwargs, **options)
+        >>> add.subtask(args, kwargs, **options).apply_async()
+
+        >>> add.apply_async((2, 2), countdown=1)
+        >>> add.subtask((2, 2), countdown=1).apply_async()
 
 - You can't define options with :meth:`~@Task.s`, but a chaining
   ``set`` call takes care of that::
@@ -77,11 +93,16 @@ or even serialized and sent across the wire.
 Partials
 --------
 
-A subtask can be applied too::
+You can execute the subtask in a worker::
 
     >>> add.s(2, 2).delay()
     >>> add.s(2, 2).apply_async(countdown=1)
 
+Or you can call it directly in the current process::
+
+    >>> add.s(2, 2)()
+    4
+
 Specifying additional args, kwargs or options to ``apply_async``/``delay``
 creates partials:
 
@@ -104,7 +125,7 @@ creates partials:
     >>> s = add.subtask((2, 2), countdown=10)
     >>> s.apply_async(countdown=1)  # countdown is now 1
 
-You can also clone subtasks to augment these::
+You can also clone subtasks to create derivates:
 
     >>> s = add.s(2)
     proj.tasks.add(2)