@@ -27,10 +27,10 @@ def get(self):
27
27
do_something_with_response(response)
28
28
self.render("template.html")
29
29
30
- `Task` works with any function that takes a ``callback`` keyword argument
31
- (and runs that callback with zero or one arguments). You can also yield
32
- a list of ``Tasks``, which will be started at the same time and run in parallel;
33
- a list of results will be returned when they are all finished::
30
+ `Task` works with any function that takes a ``callback`` keyword
31
+ argument. You can also yield a list of ``Tasks``, which will be
32
+ started at the same time and run in parallel; a list of results will
33
+ be returned when they are all finished::
34
34
35
35
def get(self):
36
36
http_client = AsyncHTTPClient()
@@ -55,9 +55,16 @@ def get(self):
55
55
asynchronous operations to be started at different times and proceed
56
56
in parallel: yield several callbacks with different keys, then wait
57
57
for them once all the async operations have started.
58
+
59
+ The result of a `Wait` or `Task` yield expression depends on how the callback
60
+ was run. If it was called with no arguments, the result is ``None``. If
61
+ it was called with one argument, the result is that argument. If it was
62
+ called with more than one argument or any keyword arguments, the result
63
+ is an `Arguments` object, which is a named tuple ``(args, kwargs)``.
58
64
"""
59
65
60
66
import functools
67
+ import operator
61
68
import sys
62
69
import types
63
70
@@ -134,10 +141,7 @@ def is_ready(self):
134
141
return True
135
142
136
143
def get_result (self ):
137
- return self .callback
138
-
139
- def callback (self , arg = None ):
140
- self .runner .set_result (self .key , arg )
144
+ return self .runner .result_callback (self .key )
141
145
142
146
class Wait (YieldPoint ):
143
147
"""Returns the argument passed to the result of a previous `Callback`."""
@@ -191,24 +195,23 @@ class Task(YieldPoint):
191
195
"""
192
196
def __init__ (self , func , * args , ** kwargs ):
193
197
assert "callback" not in kwargs
194
- kwargs ["callback" ] = self .callback
195
- self .func = functools .partial (func , * args , ** kwargs )
198
+ self .args = args
199
+ self .kwargs = kwargs
200
+ self .func = func
196
201
197
202
def start (self , runner ):
198
203
self .runner = runner
199
204
self .key = object ()
200
205
runner .register_callback (self .key )
201
- self .func ()
206
+ self .kwargs ["callback" ] = runner .result_callback (self .key )
207
+ self .func (* self .args , ** self .kwargs )
202
208
203
209
def is_ready (self ):
204
210
return self .runner .is_ready (self .key )
205
211
206
212
def get_result (self ):
207
213
return self .runner .pop_result (self .key )
208
214
209
- def callback (self , arg = None ):
210
- self .runner .set_result (self .key , arg )
211
-
212
215
class Multi (YieldPoint ):
213
216
"""Runs multiple asynchronous operations in parallel.
214
217
@@ -318,3 +321,29 @@ def run(self):
318
321
finally :
319
322
self .running = False
320
323
324
+ def result_callback (self , key ):
325
+ def inner (* args , ** kwargs ):
326
+ if kwargs or len (args ) > 1 :
327
+ result = Arguments (args , kwargs )
328
+ elif args :
329
+ result = args [0 ]
330
+ else :
331
+ result = None
332
+ self .set_result (key , result )
333
+ return inner
334
+
335
+ # in python 2.6+ this could be a collections.namedtuple
336
+ class Arguments (tuple ):
337
+ """The result of a yield expression whose callback had more than one
338
+ argument (or keyword arguments).
339
+
340
+ The `Arguments` object can be used as a tuple ``(args, kwargs)``
341
+ or an object with attributes ``args`` and ``kwargs``.
342
+ """
343
+ __slots__ = ()
344
+
345
+ def __new__ (cls , args , kwargs ):
346
+ return tuple .__new__ (cls , (args , kwargs ))
347
+
348
+ args = property (operator .itemgetter (0 ))
349
+ kwargs = property (operator .itemgetter (1 ))
0 commit comments