@@ -73,6 +73,7 @@ def __init__(
73
73
fname = 'unknown' ,
74
74
targets = None ,
75
75
owner = False ,
76
+ return_exceptions = False ,
76
77
):
77
78
super (AsyncResult , self ).__init__ ()
78
79
if not isinstance (children , list ):
@@ -81,6 +82,8 @@ def __init__(
81
82
else :
82
83
self ._single_result = False
83
84
85
+ self ._return_exceptions = return_exceptions
86
+
84
87
if isinstance (children [0 ], string_types ):
85
88
self .msg_ids = children
86
89
self ._children = []
@@ -204,22 +207,35 @@ def _reconstruct_result(self, res):
204
207
else :
205
208
return res
206
209
207
- def get (self , timeout = - 1 ):
210
+ def get (self , timeout = None , return_exceptions = None ):
208
211
"""Return the result when it arrives.
209
212
210
- If `timeout` is not ``None`` and the result does not arrive within
211
- `timeout` seconds then ``TimeoutError`` is raised. If the
212
- remote call raised an exception then that exception will be reraised
213
- by get() inside a `RemoteError`.
213
+ Arguments:
214
+
215
+ timeout : int [default None]
216
+ If `timeout` is not ``None`` and the result does not arrive within
217
+ `timeout` seconds then ``TimeoutError`` is raised. If the
218
+ remote call raised an exception then that exception will be reraised
219
+ by get() inside a `RemoteError`.
220
+ return_exceptions : bool [default False]
221
+ If True, return Exceptions instead of raising them.
214
222
"""
215
223
if not self .ready ():
216
224
self .wait (timeout )
217
225
226
+ if return_exceptions is None :
227
+ # default to attribute, if AsyncResult was created with return_exceptions=True
228
+ return_exceptions = self ._return_exceptions
229
+
218
230
if self ._ready :
219
231
if self ._success :
220
232
return self .result ()
221
233
else :
222
- raise self .exception ()
234
+ e = self .exception ()
235
+ if return_exceptions :
236
+ return self ._reconstruct_result (self ._raw_results )
237
+ else :
238
+ raise e
223
239
else :
224
240
raise error .TimeoutError ("Result not ready." )
225
241
@@ -270,22 +286,37 @@ def wait(self, timeout=-1):
270
286
def _resolve_result (self , f = None ):
271
287
if self .done ():
272
288
return
289
+ if f :
290
+ results = f .result ()
291
+ else :
292
+ results = list (map (self ._client .results .get , self .msg_ids ))
293
+
294
+ # store raw results
295
+ self ._raw_results = results
296
+
273
297
try :
274
- if f :
275
- results = f .result ()
276
- else :
277
- results = list (map (self ._client .results .get , self .msg_ids ))
278
298
if self ._single_result :
279
299
r = results [0 ]
280
300
if isinstance (r , Exception ):
281
301
raise r
282
302
else :
283
- results = error .collect_exceptions (results , self ._fname )
284
- self ._success = True
285
- self .set_result (self ._reconstruct_result (results ))
303
+ results = self ._collect_exceptions (results )
286
304
except Exception as e :
287
305
self ._success = False
288
306
self .set_exception (e )
307
+ else :
308
+ self ._success = True
309
+ self .set_result (self ._reconstruct_result (results ))
310
+
311
+ def _collect_exceptions (self , results ):
312
+ """Wrap Exceptions in a CompositeError
313
+
314
+ if self._return_exceptions is True, this is a no-op
315
+ """
316
+ if self ._return_exceptions :
317
+ return results
318
+ else :
319
+ return error .collect_exceptions (results , self ._fname )
289
320
290
321
def _finalize_result (self , f ):
291
322
if self .owner :
@@ -424,10 +455,10 @@ def __getitem__(self, key):
424
455
"""getitem returns result value(s) if keyed by int/slice, or metadata if key is str."""
425
456
if isinstance (key , int ):
426
457
self ._check_ready ()
427
- return error . collect_exceptions ([self .result ()[key ]], self . _fname )[0 ]
458
+ return self . _collect_exceptions ([self .result ()[key ]])[0 ]
428
459
elif isinstance (key , slice ):
429
460
self ._check_ready ()
430
- return error . collect_exceptions (self .result ()[key ], self . _fname )
461
+ return self . _collect_exceptions (self .result ()[key ])
431
462
elif isinstance (key , string_types ):
432
463
# metadata proxy *does not* require that results are done
433
464
self .wait (0 )
@@ -473,7 +504,7 @@ def __iter__(self):
473
504
for child in self ._children :
474
505
self ._wait_for_child (child , evt = evt )
475
506
result = child .result ()
476
- error . collect_exceptions ([result ], self . _fname )
507
+ self . _collect_exceptions ([result ])
477
508
yield result
478
509
else :
479
510
# already done
@@ -583,15 +614,15 @@ def wait_interactive(self, interval=0.1, timeout=-1, widget=None):
583
614
Override default context-detection behavior for whether a widget-based progress bar
584
615
should be used.
585
616
"""
586
- if timeout is None :
587
- timeout = - 1
617
+ if timeout and timeout < 0 :
618
+ timeout = None
588
619
N = len (self )
589
620
tic = time .perf_counter ()
590
621
progress_bar = progress (widget = widget , total = N , unit = 'tasks' , desc = self ._fname )
591
622
592
623
n_prev = 0
593
624
while not self .ready () and (
594
- timeout < 0 or time .perf_counter () - tic <= timeout
625
+ timeout is None or time .perf_counter () - tic <= timeout
595
626
):
596
627
self .wait (interval )
597
628
progress_bar .update (self .progress - n_prev )
@@ -751,25 +782,50 @@ def display_outputs(self, groupby="type", result_only=False):
751
782
752
783
753
784
class AsyncMapResult (AsyncResult ):
754
- """Class for representing results of non-blocking gathers .
785
+ """Class for representing results of non-blocking maps .
755
786
756
- This will properly reconstruct the gather .
787
+ AsyncMapResult.get() will properly reconstruct gathers into single object .
757
788
758
- This class is iterable at any time, and will wait on results as they come.
789
+ AsyncMapResult is iterable at any time, and will wait on results as they come.
759
790
760
791
If ordered=False, then the first results to arrive will come first, otherwise
761
792
results will be yielded in the order they were submitted.
762
-
763
793
"""
764
794
765
- def __init__ (self , client , children , mapObject , fname = '' , ordered = True ):
795
+ def __init__ (
796
+ self ,
797
+ client ,
798
+ children ,
799
+ mapObject ,
800
+ fname = '' ,
801
+ ordered = True ,
802
+ return_exceptions = False ,
803
+ ):
766
804
self ._mapObject = mapObject
767
805
self .ordered = ordered
768
- AsyncResult .__init__ (self , client , children , fname = fname )
806
+ AsyncResult .__init__ (
807
+ self ,
808
+ client ,
809
+ children ,
810
+ fname = fname ,
811
+ return_exceptions = return_exceptions ,
812
+ )
769
813
self ._single_result = False
770
814
771
815
def _reconstruct_result (self , res ):
772
816
"""Perform the gather on the actual results."""
817
+ if self ._return_exceptions :
818
+ if any (isinstance (r , Exception ) for r in res ):
819
+ # running with _return_exceptions,
820
+ # cannot reconstruct original
821
+ # use simple chain iterable
822
+ flattened = []
823
+ for r in res :
824
+ if isinstance (r , Exception ):
825
+ flattened .append (r )
826
+ else :
827
+ flattened .extend (r )
828
+ return flattened
773
829
return self ._mapObject .joinPartitions (res )
774
830
775
831
# asynchronous iterator:
@@ -786,7 +842,7 @@ def _yield_child_results(self, child):
786
842
rlist = child .result ()
787
843
if not isinstance (rlist , list ):
788
844
rlist = [rlist ]
789
- error . collect_exceptions (rlist , self . _fname )
845
+ self . _collect_exceptions (rlist )
790
846
for r in rlist :
791
847
yield r
792
848
@@ -841,6 +897,8 @@ def _init_futures(self):
841
897
def wait (self , timeout = - 1 ):
842
898
"""wait for result to complete."""
843
899
start = time .time ()
900
+ if timeout and timeout < 0 :
901
+ timeout = None
844
902
if self ._ready :
845
903
return
846
904
local_ids = [m for m in self .msg_ids if m in self ._client .outstanding ]
@@ -852,7 +910,7 @@ def wait(self, timeout=-1):
852
910
else :
853
911
rdict = self ._client .result_status (remote_ids , status_only = False )
854
912
pending = rdict ['pending' ]
855
- while pending and (timeout < 0 or time .time () < start + timeout ):
913
+ while pending and (timeout is None or time .time () < start + timeout ):
856
914
rdict = self ._client .result_status (remote_ids , status_only = False )
857
915
pending = rdict ['pending' ]
858
916
if pending :
@@ -865,11 +923,10 @@ def wait(self, timeout=-1):
865
923
results = list (map (self ._client .results .get , self .msg_ids ))
866
924
if self ._single_result :
867
925
r = results [0 ]
868
- if isinstance (r , Exception ):
926
+ if isinstance (r , Exception ) and not self . _return_exceptions :
869
927
raise r
870
- self .set_result (r )
871
928
else :
872
- results = error . collect_exceptions (results , self . _fname )
929
+ results = self . _collect_exceptions (results )
873
930
self ._success = True
874
931
self .set_result (self ._reconstruct_result (results ))
875
932
except Exception as e :
0 commit comments