@@ -63,9 +63,6 @@ def remove(t):
6363
6464# async 
6565def  gather (* aws , return_exceptions = False ):
66-     if  not  aws :
67-         return  []
68- 
6966    def  done (t , er ):
7067        # Sub-task "t" has finished, with exception "er". 
7168        nonlocal  state 
@@ -86,26 +83,39 @@ def done(t, er):
8683        # Gather waiting is done, schedule the main gather task. 
8784        core ._task_queue .push (gather_task )
8885
86+     # Prepare the sub-tasks for the gather. 
87+     # The `state` variable counts the number of tasks to wait for, and can be negative 
88+     # if the gather should not run at all (because a task already had an exception). 
8989    ts  =  [core ._promote_to_task (aw ) for  aw  in  aws ]
90+     state  =  0 
9091    for  i  in  range (len (ts )):
91-         if  ts [i ].state  is  not   True :
92-             # Task is not running, gather not currently supported for this case. 
92+         if  ts [i ].state  is  True :
93+             # Task is running, register the callback to call when the task is done. 
94+             ts [i ].state  =  done 
95+             state  +=  1 
96+         elif  not  ts [i ].state :
97+             # Task finished already. 
98+             if  not  isinstance (ts [i ].data , StopIteration ):
99+                 # Task finished by raising an exception. 
100+                 if  not  return_exceptions :
101+                     # Do not run this gather at all. 
102+                     state  =  - len (ts )
103+         else :
104+             # Task being waited on, gather not currently supported for this case. 
93105            raise  RuntimeError ("can't gather" )
94-         # Register the callback to call when the task is done. 
95-         ts [i ].state  =  done 
96106
97107    # Set the state for execution of the gather. 
98108    gather_task  =  core .cur_task 
99-     state  =  len (ts )
100109    cancel_all  =  False 
101110
102-     # Wait for the a sub-task to need attention. 
103-     gather_task .data  =  _Remove 
104-     try :
105-         yield 
106-     except  core .CancelledError  as  er :
107-         cancel_all  =  True 
108-         state  =  er 
111+     # Wait for a sub-task to need attention (if there are any to wait for). 
112+     if  state  >  0 :
113+         gather_task .data  =  _Remove 
114+         try :
115+             yield 
116+         except  core .CancelledError  as  er :
117+             cancel_all  =  True 
118+             state  =  er 
109119
110120    # Clean up tasks. 
111121    for  i  in  range (len (ts )):
@@ -118,8 +128,13 @@ def done(t, er):
118128            # Sub-task ran to completion, get its return value. 
119129            ts [i ] =  ts [i ].data .value 
120130        else :
121-             # Sub-task had an exception with return_exceptions==True, so get its exception. 
122-             ts [i ] =  ts [i ].data 
131+             # Sub-task had an exception. 
132+             if  return_exceptions :
133+                 # Get the sub-task exception to return in the list of return values. 
134+                 ts [i ] =  ts [i ].data 
135+             elif  isinstance (state , int ):
136+                 # Raise the sub-task exception, if there is not already an exception to raise. 
137+                 state  =  ts [i ].data 
123138
124139    # Either this gather was cancelled, or one of the sub-tasks raised an exception with 
125140    # return_exceptions==False, so reraise the exception here. 
0 commit comments