41 Such methods must implement a coroutine as follows: |
41 Such methods must implement a coroutine as follows: |
42 |
42 |
43 @batchable |
43 @batchable |
44 def sample(self, one, two=None): |
44 def sample(self, one, two=None): |
45 # Build list of encoded arguments suitable for your wire protocol: |
45 # Build list of encoded arguments suitable for your wire protocol: |
46 encargs = [('one', encode(one),), ('two', encode(two),)] |
46 encoded_args = [('one', encode(one),), ('two', encode(two),)] |
47 # Create future for injection of encoded result: |
47 # Create future for injection of encoded result: |
48 encresref = future() |
48 encoded_res_future = future() |
49 # Return encoded arguments and future: |
49 # Return encoded arguments and future: |
50 yield encargs, encresref |
50 yield encoded_args, encoded_res_future |
51 # Assuming the future to be filled with the result from the batched |
51 # Assuming the future to be filled with the result from the batched |
52 # request now. Decode it: |
52 # request now. Decode it: |
53 yield decode(encresref.value) |
53 yield decode(encoded_res_future.value) |
54 |
54 |
55 The decorator returns a function which wraps this coroutine as a plain |
55 The decorator returns a function which wraps this coroutine as a plain |
56 method, but adds the original method as an attribute called "batchable", |
56 method, but adds the original method as an attribute called "batchable", |
57 which is used by remotebatch to split the call into separate encoding and |
57 which is used by remotebatch to split the call into separate encoding and |
58 decoding phases. |
58 decoding phases. |
59 """ |
59 """ |
60 |
60 |
61 def plain(*args, **opts): |
61 def plain(*args, **opts): |
62 batchable = f(*args, **opts) |
62 batchable = f(*args, **opts) |
63 encargsorres, encresref = next(batchable) |
63 encoded_args_or_res, encoded_res_future = next(batchable) |
64 if not encresref: |
64 if not encoded_res_future: |
65 return encargsorres # a local result in this case |
65 return encoded_args_or_res # a local result in this case |
66 self = args[0] |
66 self = args[0] |
67 cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr |
67 cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr |
68 encresref.set(self._submitone(cmd, encargsorres)) |
68 encoded_res_future.set(self._submitone(cmd, encoded_args_or_res)) |
69 return next(batchable) |
69 return next(batchable) |
70 |
70 |
71 setattr(plain, 'batchable', f) |
71 setattr(plain, 'batchable', f) |
72 setattr(plain, '__name__', f.__name__) |
72 setattr(plain, '__name__', f.__name__) |
73 return plain |
73 return plain |
255 pycompat.future_set_exception_info(f, sys.exc_info()[1:]) |
255 pycompat.future_set_exception_info(f, sys.exc_info()[1:]) |
256 return |
256 return |
257 |
257 |
258 # Encoded arguments and future holding remote result. |
258 # Encoded arguments and future holding remote result. |
259 try: |
259 try: |
260 encargsorres, fremote = next(batchable) |
260 encoded_args_or_res, fremote = next(batchable) |
261 except Exception: |
261 except Exception: |
262 pycompat.future_set_exception_info(f, sys.exc_info()[1:]) |
262 pycompat.future_set_exception_info(f, sys.exc_info()[1:]) |
263 return |
263 return |
264 |
264 |
265 if not fremote: |
265 if not fremote: |
266 f.set_result(encargsorres) |
266 f.set_result(encoded_args_or_res) |
267 else: |
267 else: |
268 requests.append((command, encargsorres)) |
268 requests.append((command, encoded_args_or_res)) |
269 states.append((command, f, batchable, fremote)) |
269 states.append((command, f, batchable, fremote)) |
270 |
270 |
271 if not requests: |
271 if not requests: |
272 return |
272 return |
273 |
273 |