Coverage for Lib/asyncio/tasks.py: 95%

553 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-25 03:29 +0000

1"""Support for tasks, coroutines and the scheduler.""" 

2 

3__all__ = ( 

4 'Task', 'create_task', 

5 'FIRST_COMPLETED', 'FIRST_EXCEPTION', 'ALL_COMPLETED', 

6 'wait', 'wait_for', 'as_completed', 'sleep', 

7 'gather', 'shield', 'ensure_future', 'run_coroutine_threadsafe', 

8 'current_task', 'all_tasks', 

9 'create_eager_task_factory', 'eager_task_factory', 

10 '_register_task', '_unregister_task', '_enter_task', '_leave_task', 

11) 

12 

13import concurrent.futures 

14import contextvars 

15import functools 

16import inspect 

17import itertools 

18import math 

19import types 

20import weakref 

21from types import GenericAlias 

22 

23from . import base_tasks 

24from . import coroutines 

25from . import events 

26from . import exceptions 

27from . import futures 

28from . import queues 

29from . import timeouts 

30 

31# Helper to generate new task names 

32# This uses itertools.count() instead of a "+= 1" operation because the latter 

33# is not thread safe. See bpo-11866 for a longer explanation. 

34_task_name_counter = itertools.count(1).__next__ 

35 

36 

37def current_task(loop=None): 

38 """Return a currently executed task.""" 

39 if loop is None: 

40 loop = events.get_running_loop() 

41 return _current_tasks.get(loop) 

42 

43 

44def all_tasks(loop=None): 

45 """Return a set of all tasks for the loop.""" 

46 if loop is None: 

47 loop = events.get_running_loop() 

48 # capturing the set of eager tasks first, so if an eager task "graduates" 

49 # to a regular task in another thread, we don't risk missing it. 

50 eager_tasks = list(_eager_tasks) 

51 

52 return {t for t in itertools.chain(_scheduled_tasks, eager_tasks) 

53 if futures._get_loop(t) is loop and not t.done()} 

54 

55 

56class Task(futures._PyFuture): # Inherit Python Task implementation 

57 # from a Python Future implementation. 

58 

59 """A coroutine wrapped in a Future.""" 

60 

61 # An important invariant maintained while a Task not done: 

62 # _fut_waiter is either None or a Future. The Future 

63 # can be either done() or not done(). 

64 # The task can be in any of 3 states: 

65 # 

66 # - 1: _fut_waiter is not None and not _fut_waiter.done(): 

67 # __step() is *not* scheduled and the Task is waiting for _fut_waiter. 

68 # - 2: (_fut_waiter is None or _fut_waiter.done()) and __step() is scheduled: 

69 # the Task is waiting for __step() to be executed. 

70 # - 3: _fut_waiter is None and __step() is *not* scheduled: 

71 # the Task is currently executing (in __step()). 

72 # 

73 # * In state 1, one of the callbacks of __fut_waiter must be __wakeup(). 

74 # * The transition from 1 to 2 happens when _fut_waiter becomes done(), 

75 # as it schedules __wakeup() to be called (which calls __step() so 

76 # we way that __step() is scheduled). 

77 # * It transitions from 2 to 3 when __step() is executed, and it clears 

78 # _fut_waiter to None. 

79 

80 # If False, don't log a message if the task is destroyed while its 

81 # status is still pending 

82 _log_destroy_pending = True 

83 

84 def __init__(self, coro, *, loop=None, name=None, context=None, 

85 eager_start=False): 

86 super().__init__(loop=loop) 

87 if self._source_traceback: 

88 del self._source_traceback[-1] 

89 if not coroutines.iscoroutine(coro): 

90 # raise after Future.__init__(), attrs are required for __del__ 

91 # prevent logging for pending task in __del__ 

92 self._log_destroy_pending = False 

93 raise TypeError(f"a coroutine was expected, got {coro!r}") 

94 

95 if name is None: 

96 self._name = f'Task-{_task_name_counter()}' 

97 else: 

98 self._name = str(name) 

99 

100 self._num_cancels_requested = 0 

101 self._must_cancel = False 

102 self._fut_waiter = None 

103 self._coro = coro 

104 if context is None: 

105 self._context = contextvars.copy_context() 

106 elif not isinstance(context, contextvars.Context): 

107 # gh-157301: the passed value must be a contextvars.Context 

108 self._log_destroy_pending = False 

109 raise TypeError('a contextvars.Context was expected, ' 

110 f'got {type(context).__name__}') 

111 else: 

112 self._context = context 

113 

114 if eager_start and self._loop.is_running(): 

115 try: 

116 self.__eager_start() 

117 except: 

118 self._log_destroy_pending = False 

119 raise 

120 else: 

121 self._loop.call_soon(self.__step, context=self._context) 

122 _py_register_task(self) 

123 

124 def __del__(self): 

125 if self._state == futures._PENDING and self._log_destroy_pending: 

126 context = { 

127 'task': self, 

128 'message': 'Task was destroyed but it is pending!', 

129 } 

130 if self._source_traceback: 

131 context['source_traceback'] = self._source_traceback 

132 self._loop.call_exception_handler(context) 

133 super().__del__() 

134 

135 __class_getitem__ = classmethod(GenericAlias) 

136 

137 def __repr__(self): 

138 return base_tasks._task_repr(self) 

139 

140 def get_coro(self): 

141 return self._coro 

142 

143 def get_context(self): 

144 return self._context 

145 

146 def get_name(self): 

147 return self._name 

148 

149 def set_name(self, value): 

150 self._name = str(value) 

151 

152 def set_result(self, result): 

153 raise RuntimeError('Task does not support set_result operation') 

154 

155 def set_exception(self, exception): 

156 raise RuntimeError('Task does not support set_exception operation') 

157 

158 def get_stack(self, *, limit=None): 

159 """Return the list of stack frames for this task's coroutine. 

160 

161 If the coroutine is not done, this returns the stack where it is 

162 suspended. If the coroutine has completed successfully or was 

163 cancelled, this returns an empty list. If the coroutine was 

164 terminated by an exception, this returns the list of traceback 

165 frames. 

166 

167 The frames are always ordered from oldest to newest. 

168 

169 The optional limit gives the maximum number of frames to 

170 return; by default all available frames are returned. Its 

171 meaning differs depending on whether a stack or a traceback is 

172 returned: the newest frames of a stack are returned, but the 

173 oldest frames of a traceback are returned. (This matches the 

174 behavior of the traceback module.) 

175 

176 For reasons beyond our control, only one stack frame is 

177 returned for a suspended coroutine. 

178 """ 

179 return base_tasks._task_get_stack(self, limit) 

180 

181 def print_stack(self, *, limit=None, file=None): 

182 """Print the stack or traceback for this task's coroutine. 

183 

184 This produces output similar to that of the traceback module, 

185 for the frames retrieved by get_stack(). The limit argument 

186 is passed to get_stack(). The file argument is an I/O stream 

187 to which the output is written; by default output is written 

188 to sys.stderr. 

189 """ 

190 return base_tasks._task_print_stack(self, limit, file) 

191 

192 def cancel(self, msg=None): 

193 """Request that this task cancel itself. 

194 

195 This arranges for a CancelledError to be thrown into the 

196 wrapped coroutine on the next cycle through the event loop. 

197 The coroutine then has a chance to clean up or even deny 

198 the request using try/except/finally. 

199 

200 Unlike Future.cancel, this does not guarantee that the 

201 task will be cancelled: the exception might be caught and 

202 acted upon, delaying cancellation of the task or preventing 

203 cancellation completely. The task may also return a value or 

204 raise a different exception. 

205 

206 Immediately after this method is called, Task.cancelled() will 

207 not return True (unless the task was already cancelled). A 

208 task will be marked as cancelled when the wrapped coroutine 

209 terminates with a CancelledError exception (even if cancel() 

210 was not called). 

211 

212 This also increases the task's count of cancellation requests. 

213 """ 

214 self._log_traceback = False 

215 if self.done(): 

216 return False 

217 self._num_cancels_requested += 1 

218 # These two lines are controversial. See discussion starting at 

219 # https://github.com/python/cpython/pull/31394#issuecomment-1053545331 

220 # Also remember that this is duplicated in _asynciomodule.c. 

221 # if self._num_cancels_requested > 1: 

222 # return False 

223 if self._fut_waiter is not None: 

224 if self._fut_waiter.cancel(msg=msg): 

225 # Leave self._fut_waiter; it may be a Task that 

226 # catches and ignores the cancellation so we may have 

227 # to cancel it again later. 

228 return True 

229 # It must be the case that self.__step is already scheduled. 

230 self._must_cancel = True 

231 self._cancel_message = msg 

232 return True 

233 

234 def cancelling(self): 

235 """Return the count of the task's cancellation requests. 

236 

237 This count is incremented when .cancel() is called 

238 and may be decremented using .uncancel(). 

239 """ 

240 return self._num_cancels_requested 

241 

242 def uncancel(self): 

243 """Decrement the task's count of cancellation requests. 

244 

245 This should be called by the party that called `cancel()` on the task 

246 beforehand. 

247 

248 Returns the remaining number of cancellation requests. 

249 """ 

250 if self._num_cancels_requested > 0: 250 ↛ 254line 250 didn't jump to line 254 because the condition on line 250 was always true

251 self._num_cancels_requested -= 1 

252 if self._num_cancels_requested == 0: 252 ↛ 254line 252 didn't jump to line 254 because the condition on line 252 was always true

253 self._must_cancel = False 

254 return self._num_cancels_requested 

255 

256 def __eager_start(self): 

257 prev_task = _py_swap_current_task(self._loop, self) 

258 try: 

259 _py_register_eager_task(self) 

260 try: 

261 self._context.run(self.__step_run_and_handle_result, None) 

262 finally: 

263 _py_unregister_eager_task(self) 

264 finally: 

265 try: 

266 curtask = _py_swap_current_task(self._loop, prev_task) 

267 assert curtask is self 

268 finally: 

269 if self.done(): 

270 self._coro = None 

271 self = None # Needed to break cycles when an exception occurs. 

272 else: 

273 _py_register_task(self) 

274 

275 def __step(self, exc=None): 

276 if self.done(): 

277 raise exceptions.InvalidStateError( 

278 f'__step(): already done: {self!r}, {exc!r}') 

279 if self._must_cancel: 

280 # gh-108549: do not swallow SystemExit and KeyboardInterrupt. 

281 if not isinstance(exc, (exceptions.CancelledError, 

282 SystemExit, KeyboardInterrupt)): 

283 exc = self._make_cancelled_error() 

284 self._must_cancel = False 

285 self._fut_waiter = None 

286 

287 _py_enter_task(self._loop, self) 

288 try: 

289 self.__step_run_and_handle_result(exc) 

290 finally: 

291 _py_leave_task(self._loop, self) 

292 self = None # Needed to break cycles when an exception occurs. 

293 

294 def __step_run_and_handle_result(self, exc): 

295 coro = self._coro 

296 try: 

297 if exc is None: 

298 # We use the `send` method directly, because coroutines 

299 # don't have `__iter__` and `__next__` methods. 

300 result = coro.send(None) 

301 else: 

302 result = coro.throw(exc) 

303 except StopIteration as exc: 

304 if self._must_cancel: 

305 # Task is cancelled right before coro stops. 

306 self._must_cancel = False 

307 super().cancel(msg=self._cancel_message) 

308 else: 

309 super().set_result(exc.value) 

310 except exceptions.CancelledError as exc: 

311 # Save the original exception so we can chain it later. 

312 self._cancelled_exc = exc 

313 super().cancel() # I.e., Future.cancel(self). 

314 except (KeyboardInterrupt, SystemExit) as exc: 

315 super().set_exception(exc) 

316 raise 

317 except BaseException as exc: 

318 super().set_exception(exc) 

319 else: 

320 blocking = getattr(result, '_asyncio_future_blocking', None) 

321 if blocking is not None: 

322 # Yielded Future must come from Future.__iter__(). 

323 if futures._get_loop(result) is not self._loop: 

324 new_exc = RuntimeError( 

325 f'Task {self!r} got Future ' 

326 f'{result!r} attached to a different loop') 

327 self._loop.call_soon( 

328 self.__step, new_exc, context=self._context) 

329 elif blocking: 329 ↛ 346line 329 didn't jump to line 346 because the condition on line 329 was always true

330 if result is self: 

331 new_exc = RuntimeError( 

332 f'Task cannot await on itself: {self!r}') 

333 self._loop.call_soon( 

334 self.__step, new_exc, context=self._context) 

335 else: 

336 futures.future_add_to_awaited_by(result, self) 

337 result._asyncio_future_blocking = False 

338 result.add_done_callback( 

339 self.__wakeup, context=self._context) 

340 self._fut_waiter = result 

341 if self._must_cancel: 

342 if self._fut_waiter.cancel( 342 ↛ 368line 342 didn't jump to line 368 because the condition on line 342 was always true

343 msg=self._cancel_message): 

344 self._must_cancel = False 

345 else: 

346 new_exc = RuntimeError( 

347 f'yield was used instead of yield from ' 

348 f'in task {self!r} with {result!r}') 

349 self._loop.call_soon( 

350 self.__step, new_exc, context=self._context) 

351 

352 elif result is None: 352 ↛ 355line 352 didn't jump to line 355 because the condition on line 352 was always true

353 # Bare yield relinquishes control for one event loop iteration. 

354 self._loop.call_soon(self.__step, context=self._context) 

355 elif inspect.isgenerator(result): 

356 # Yielding a generator is just wrong. 

357 new_exc = RuntimeError( 

358 f'yield was used instead of yield from for ' 

359 f'generator in task {self!r} with {result!r}') 

360 self._loop.call_soon( 

361 self.__step, new_exc, context=self._context) 

362 else: 

363 # Yielding something else is an error. 

364 new_exc = RuntimeError(f'Task got bad yield: {result!r}') 

365 self._loop.call_soon( 

366 self.__step, new_exc, context=self._context) 

367 finally: 

368 self = None # Needed to break cycles when an exception occurs. 

369 

370 def __wakeup(self, future): 

371 futures.future_discard_from_awaited_by(future, self) 

372 try: 

373 future.result() 

374 except BaseException as exc: 

375 # This may also be a cancellation. 

376 self.__step(exc) 

377 else: 

378 # Don't pass the value of `future.result()` explicitly, 

379 # as `Future.__iter__` and `Future.__await__` don't need it. 

380 # If we call `__step(value, None)` instead of `__step()`, 

381 # Python eval loop would use `.send(value)` method call, 

382 # instead of `__next__()`, which is slower for futures 

383 # that return non-generator iterators from their `__iter__`. 

384 self.__step() 

385 self = None # Needed to break cycles when an exception occurs. 

386 

387 

388_PyTask = Task 

389 

390 

391try: 

392 import _asyncio 

393except ImportError: 

394 pass 

395else: 

396 # _CTask is needed for tests. 

397 Task = _CTask = _asyncio.Task 

398 

399 

400def create_task(coro, **kwargs): 

401 """Schedule the execution of a coroutine object in a spawn task. 

402 

403 Return a Task object. 

404 """ 

405 loop = events.get_running_loop() 

406 return loop.create_task(coro, **kwargs) 

407 

408 

409# wait() and as_completed() similar to those in PEP 3148. 

410 

411FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED 

412FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION 

413ALL_COMPLETED = concurrent.futures.ALL_COMPLETED 

414 

415 

416async def wait(fs, *, timeout=None, return_when=ALL_COMPLETED): 

417 """Wait for the Futures or Tasks given by fs to complete. 

418 

419 The fs iterable must not be empty. 

420 

421 Returns two sets of Future: (done, pending). 

422 

423 Usage: 

424 

425 done, pending = await asyncio.wait(fs) 

426 

427 Note: This does not raise TimeoutError! Futures that aren't done 

428 when the timeout occurs are returned in the second set. 

429 """ 

430 if futures.isfuture(fs) or coroutines.iscoroutine(fs): 

431 raise TypeError(f"expect a list of futures, not {type(fs).__name__}") 

432 if not fs: 

433 raise ValueError('Set of Tasks/Futures is empty.') 

434 if return_when not in (FIRST_COMPLETED, FIRST_EXCEPTION, ALL_COMPLETED): 

435 raise ValueError(f'Invalid return_when value: {return_when}') 

436 

437 fs = set(fs) 

438 

439 if any(coroutines.iscoroutine(f) for f in fs): 439 ↛ 440line 439 didn't jump to line 440 because the condition on line 439 was never true

440 raise TypeError("Passing coroutines is forbidden, use tasks explicitly.") 

441 

442 loop = events.get_running_loop() 

443 return await _wait(fs, timeout, return_when, loop) 

444 

445 

446def _release_waiter(waiter, *args): 

447 if not waiter.done(): 447 ↛ exitline 447 didn't return from function '_release_waiter' because the condition on line 447 was always true

448 waiter.set_result(None) 

449 

450 

451async def wait_for(fut, timeout): 

452 """Wait for the single Future or coroutine to complete, with timeout. 

453 

454 Returns result of the Future or coroutine. When a timeout occurs, 

455 it cancels fut and raises TimeoutError. To prevent fut from being 

456 cancelled, wrap it in shield(). 

457 

458 If the wait is cancelled, fut is also cancelled. 

459 

460 If fut suppresses the cancellation and returns a value instead, 

461 that value is returned. 

462 

463 This function is a coroutine. 

464 """ 

465 # The special case for timeout <= 0 is for the following case: 

466 # 

467 # async def test_waitfor(): 

468 # func_started = False 

469 # 

470 # async def func(): 

471 # nonlocal func_started 

472 # func_started = True 

473 # 

474 # try: 

475 # await asyncio.wait_for(func(), 0) 

476 # except asyncio.TimeoutError: 

477 # assert not func_started 

478 # else: 

479 # assert False 

480 # 

481 # asyncio.run(test_waitfor()) 

482 

483 

484 if timeout is not None and timeout <= 0: 

485 fut = ensure_future(fut) 

486 

487 if fut.done(): 

488 return fut.result() 

489 

490 await _cancel_and_wait(fut) 

491 try: 

492 return fut.result() 

493 except exceptions.CancelledError as exc: 

494 raise TimeoutError from exc 

495 

496 async with timeouts.timeout(timeout): 

497 return await fut 

498 

499async def _wait(fs, timeout, return_when, loop): 

500 """Internal helper for wait(). 

501 

502 The fs argument must be a collection of Futures. 

503 """ 

504 assert fs, 'Set of Futures is empty.' 

505 waiter = loop.create_future() 

506 timeout_handle = None 

507 if timeout is not None: 

508 timeout_handle = loop.call_later(timeout, _release_waiter, waiter) 

509 counter = len(fs) 

510 cur_task = current_task() 

511 

512 def _on_completion(f): 

513 nonlocal counter 

514 counter -= 1 

515 if (counter <= 0 or 

516 return_when == FIRST_COMPLETED or 

517 return_when == FIRST_EXCEPTION and (not f.cancelled() and 

518 f.exception() is not None)): 

519 if timeout_handle is not None: 519 ↛ 520line 519 didn't jump to line 520 because the condition on line 519 was never true

520 timeout_handle.cancel() 

521 if not waiter.done(): 

522 waiter.set_result(None) 

523 futures.future_discard_from_awaited_by(f, cur_task) 

524 

525 for f in fs: 

526 f.add_done_callback(_on_completion) 

527 futures.future_add_to_awaited_by(f, cur_task) 

528 

529 try: 

530 await waiter 

531 finally: 

532 if timeout_handle is not None: 

533 timeout_handle.cancel() 

534 for f in fs: 

535 f.remove_done_callback(_on_completion) 

536 futures.future_discard_from_awaited_by(f, cur_task) 

537 

538 done, pending = set(), set() 

539 for f in fs: 

540 if f.done(): 

541 done.add(f) 

542 else: 

543 pending.add(f) 

544 return done, pending 

545 

546 

547async def _cancel_and_wait(fut): 

548 """Cancel the *fut* future or task and wait until it completes.""" 

549 

550 loop = events.get_running_loop() 

551 waiter = loop.create_future() 

552 cb = functools.partial(_release_waiter, waiter) 

553 fut.add_done_callback(cb) 

554 

555 # gh-157058: awaiting the waiter leaves no edge on fut, add it here 

556 cur_task = current_task() 

557 futures.future_add_to_awaited_by(fut, cur_task) 

558 

559 try: 

560 fut.cancel() 

561 # We cannot wait on *fut* directly to make 

562 # sure _cancel_and_wait itself is reliably cancellable. 

563 await waiter 

564 finally: 

565 fut.remove_done_callback(cb) 

566 futures.future_discard_from_awaited_by(fut, cur_task) 

567 

568 

569class _AsCompletedIterator: 

570 """Iterator of awaitables representing tasks of asyncio.as_completed. 

571 

572 As an asynchronous iterator, iteration yields futures as they finish. As a 

573 plain iterator, new coroutines are yielded that will return or raise the 

574 result of the next underlying future to complete. 

575 """ 

576 def __init__(self, aws, timeout): 

577 self._done = queues.Queue() 

578 self._timeout_handle = None 

579 

580 loop = events.get_event_loop() 

581 self._cur_task = current_task() 

582 todo = {ensure_future(aw, loop=loop) for aw in set(aws)} 

583 for f in todo: 

584 f.add_done_callback(self._handle_completion) 

585 futures.future_add_to_awaited_by(f, self._cur_task) 

586 if todo and timeout is not None: 

587 self._timeout_handle = ( 

588 loop.call_later(timeout, self._handle_timeout) 

589 ) 

590 self._todo = todo 

591 self._todo_left = len(todo) 

592 

593 def __aiter__(self): 

594 return self 

595 

596 def __iter__(self): 

597 return self 

598 

599 async def __anext__(self): 

600 if not self._todo_left: 

601 raise StopAsyncIteration 

602 assert self._todo_left > 0 

603 self._todo_left -= 1 

604 return await self._wait_for_one() 

605 

606 def __next__(self): 

607 if not self._todo_left: 

608 raise StopIteration 

609 assert self._todo_left > 0 

610 self._todo_left -= 1 

611 return self._wait_for_one(resolve=True) 

612 

613 def _handle_timeout(self): 

614 for f in self._todo: 

615 f.remove_done_callback(self._handle_completion) 

616 futures.future_discard_from_awaited_by(f, self._cur_task) 

617 self._done.put_nowait(None) # Sentinel for _wait_for_one(). 

618 self._todo.clear() # Can't do todo.remove(f) in the loop. 

619 

620 def _handle_completion(self, f): 

621 if not self._todo: 621 ↛ 622line 621 didn't jump to line 622 because the condition on line 621 was never true

622 return # _handle_timeout() was here first. 

623 self._todo.remove(f) 

624 futures.future_discard_from_awaited_by(f, self._cur_task) 

625 self._done.put_nowait(f) 

626 if not self._todo and self._timeout_handle is not None: 

627 self._timeout_handle.cancel() 

628 

629 async def _wait_for_one(self, resolve=False): 

630 # Wait for the next future to be done and return it unless resolve is 

631 # set, in which case return either the result of the future or raise 

632 # an exception. 

633 f = await self._done.get() 

634 if f is None: 

635 # Dummy value from _handle_timeout(). 

636 raise exceptions.TimeoutError 

637 return f.result() if resolve else f 

638 

639 

640def as_completed(fs, *, timeout=None): 

641 """Create an iterator of awaitables or their results in completion order. 

642 

643 Run the supplied awaitables concurrently. The returned object can be 

644 iterated to obtain the results of the awaitables as they finish. 

645 

646 The object returned can be iterated as an asynchronous iterator or 

647 a plain iterator. When asynchronous iteration is used, the 

648 originally-supplied awaitables are yielded if they are tasks or 

649 futures. This makes it easy to correlate previously-scheduled tasks 

650 with their results: 

651 

652 ipv4_connect = create_task(open_connection("127.0.0.1", 80)) 

653 ipv6_connect = create_task(open_connection("::1", 80)) 

654 tasks = [ipv4_connect, ipv6_connect] 

655 

656 async for earliest_connect in as_completed(tasks): 

657 # earliest_connect is done. The result can be obtained by 

658 # awaiting it or calling earliest_connect.result() 

659 reader, writer = await earliest_connect 

660 

661 if earliest_connect is ipv6_connect: 

662 print("IPv6 connection established.") 

663 else: 

664 print("IPv4 connection established.") 

665 

666 During asynchronous iteration, implicitly-created tasks will be 

667 yielded for supplied awaitables that aren't tasks or futures. 

668 

669 When used as a plain iterator, each iteration yields a new coroutine 

670 that returns the result or raises the exception of the next completed 

671 awaitable. This pattern is compatible with Python versions older than 

672 3.13: 

673 

674 ipv4_connect = create_task(open_connection("127.0.0.1", 80)) 

675 ipv6_connect = create_task(open_connection("::1", 80)) 

676 tasks = [ipv4_connect, ipv6_connect] 

677 

678 for next_connect in as_completed(tasks): 

679 # next_connect is not one of the original task objects. It must 

680 # be awaited to obtain the result value or raise the exception 

681 # of the awaitable that finishes next. 

682 reader, writer = await next_connect 

683 

684 A TimeoutError is raised if the timeout occurs before all awaitables 

685 are done. This is raised by the async for loop during asynchronous 

686 iteration or by the coroutines yielded during plain iteration. 

687 """ 

688 if inspect.isawaitable(fs): 

689 raise TypeError( 

690 f"expects an iterable of awaitables, not {type(fs).__name__}" 

691 ) 

692 

693 return _AsCompletedIterator(fs, timeout) 

694 

695 

696@types.coroutine 

697def __sleep0(): 

698 """Skip one event loop run cycle. 

699 

700 This is a private helper for 'asyncio.sleep()', used 

701 when the 'delay' is set to 0. It uses a bare 'yield' 

702 expression (which Task.__step knows how to handle) 

703 instead of creating a Future object. 

704 """ 

705 yield 

706 

707 

708async def sleep(delay, result=None): 

709 """Coroutine that completes after a given time (in seconds).""" 

710 if delay <= 0: 

711 await __sleep0() 

712 return result 

713 

714 if math.isnan(delay): 

715 raise ValueError("Invalid delay: NaN (not a number)") 

716 

717 loop = events.get_running_loop() 

718 future = loop.create_future() 

719 h = loop.call_later(delay, 

720 futures._set_result_unless_cancelled, 

721 future, result) 

722 try: 

723 return await future 

724 finally: 

725 h.cancel() 

726 

727 

728def ensure_future(coro_or_future, *, loop=None): 

729 """Wrap a coroutine or an awaitable in a future. 

730 

731 If the argument is a Future, it is returned directly. 

732 """ 

733 if futures.isfuture(coro_or_future): 

734 if loop is not None and loop is not futures._get_loop(coro_or_future): 

735 raise ValueError('The future belongs to a different loop than ' 

736 'the one specified as the loop argument') 

737 return coro_or_future 

738 should_close = True 

739 if not coroutines.iscoroutine(coro_or_future): 

740 if inspect.isawaitable(coro_or_future): 

741 async def _wrap_awaitable(awaitable): 

742 return await awaitable 

743 

744 coro_or_future = _wrap_awaitable(coro_or_future) 

745 should_close = False 

746 else: 

747 raise TypeError('An asyncio.Future, a coroutine or an awaitable ' 

748 'is required') 

749 

750 if loop is None: 

751 loop = events.get_event_loop() 

752 try: 

753 return loop.create_task(coro_or_future) 

754 except RuntimeError: 

755 if should_close: 755 ↛ 757line 755 didn't jump to line 757 because the condition on line 755 was always true

756 coro_or_future.close() 

757 raise 

758 

759 

760class _GatheringFuture(futures.Future): 

761 """Helper for gather(). 

762 

763 This overrides cancel() to cancel all the children and act more 

764 like Task.cancel(), which doesn't immediately mark itself as 

765 cancelled. 

766 """ 

767 

768 def __init__(self, children, *, loop): 

769 assert loop is not None 

770 super().__init__(loop=loop) 

771 self._children = children 

772 self._cancel_requested = False 

773 

774 def cancel(self, msg=None): 

775 if self.done(): 

776 return False 

777 ret = False 

778 for child in self._children: 

779 if child.cancel(msg=msg): 

780 ret = True 

781 if ret: 

782 # If any child tasks were actually cancelled, we should 

783 # propagate the cancellation request regardless of 

784 # *return_exceptions* argument. See issue 32684. 

785 self._cancel_requested = True 

786 return ret 

787 

788 

789def _discard_awaited_by(children, waiter, outer): 

790 for fut in children: 

791 futures.future_discard_from_awaited_by(fut, waiter) 

792 

793 

794def gather(*coros_or_futures, return_exceptions=False): 

795 """Return a future aggregating results from the given coroutines/futures. 

796 

797 Coroutines will be wrapped in a future and scheduled in the event 

798 loop. They will not necessarily be scheduled in the same order as 

799 passed in. 

800 

801 All futures must share the same event loop. If all the tasks are 

802 done successfully, the returned future's result is the list of 

803 results (in the order of the original sequence, not necessarily 

804 the order of results arrival). If *return_exceptions* is True, 

805 exceptions in the tasks are treated the same as successful 

806 results, and gathered in the result list; otherwise, the first 

807 raised exception will be immediately propagated to the returned 

808 future. 

809 

810 Cancellation: if the outer Future is cancelled, all children (that 

811 have not completed yet) are also cancelled. If any child is 

812 cancelled, this is treated as if it raised CancelledError -- 

813 the outer Future is *not* cancelled in this case. (This is to 

814 prevent the cancellation of one child to cause other children to 

815 be cancelled.) 

816 

817 If *return_exceptions* is False, cancelling gather() after it 

818 has been marked done won't cancel any submitted awaitables. 

819 For instance, gather can be marked done after propagating an 

820 exception to the caller, therefore, calling ``gather.cancel()`` 

821 after catching an exception (raised by one of the awaitables) from 

822 gather won't cancel any other awaitables. 

823 """ 

824 if not coros_or_futures: 

825 loop = events.get_event_loop() 

826 outer = loop.create_future() 

827 outer.set_result([]) 

828 return outer 

829 

830 loop = events._get_running_loop() 

831 if loop is not None: 

832 cur_task = current_task(loop) 

833 else: 

834 cur_task = None 

835 

836 def _done_callback(fut, cur_task=cur_task): 

837 nonlocal nfinished 

838 nfinished += 1 

839 

840 if cur_task is not None: 

841 futures.future_discard_from_awaited_by(fut, cur_task) 

842 

843 if outer is None or outer.done(): 

844 if not fut.cancelled(): 

845 # Mark exception retrieved. 

846 fut.exception() 

847 return 

848 

849 if not return_exceptions: 

850 if fut.cancelled(): 

851 # Check if 'fut' is cancelled first, as 

852 # 'fut.exception()' will *raise* a CancelledError 

853 # instead of returning it. 

854 exc = fut._make_cancelled_error() 

855 outer.set_exception(exc) 

856 return 

857 else: 

858 exc = fut.exception() 

859 if exc is not None: 

860 outer.set_exception(exc) 

861 return 

862 

863 if nfinished == nfuts: 

864 # All futures are done; create a list of results 

865 # and set it to the 'outer' future. 

866 results = [] 

867 

868 for fut in children: 

869 if fut.cancelled(): 

870 # Check if 'fut' is cancelled first, as 'fut.exception()' 

871 # will *raise* a CancelledError instead of returning it. 

872 # Also, since we're adding the exception return value 

873 # to 'results' instead of raising it, don't bother 

874 # setting __context__. This also lets us preserve 

875 # calling '_make_cancelled_error()' at most once. 

876 res = exceptions.CancelledError( 

877 '' if fut._cancel_message is None else 

878 fut._cancel_message) 

879 else: 

880 res = fut.exception() 

881 if res is None: 

882 res = fut.result() 

883 results.append(res) 

884 

885 if outer._cancel_requested: 

886 # If gather is being cancelled we must propagate the 

887 # cancellation regardless of *return_exceptions* argument. 

888 # See issue 32684. 

889 exc = fut._make_cancelled_error() 

890 outer.set_exception(exc) 

891 else: 

892 outer.set_result(results) 

893 

894 arg_to_fut = {} 

895 children = [] 

896 nfuts = 0 

897 nfinished = 0 

898 done_futs = [] 

899 outer = None # bpo-46672 

900 for arg in coros_or_futures: 

901 if arg not in arg_to_fut: 

902 fut = ensure_future(arg, loop=loop) 

903 if loop is None: 

904 loop = futures._get_loop(fut) 

905 if fut is not arg: 

906 # 'arg' was not a Future, therefore, 'fut' is a new 

907 # Future created specifically for 'arg'. Since the caller 

908 # can't control it, disable the "destroy pending task" 

909 # warning. 

910 fut._log_destroy_pending = False 

911 nfuts += 1 

912 arg_to_fut[arg] = fut 

913 if fut.done(): 

914 done_futs.append(fut) 

915 else: 

916 if cur_task is not None: 

917 futures.future_add_to_awaited_by(fut, cur_task) 

918 fut.add_done_callback(_done_callback) 

919 

920 else: 

921 # There's a duplicate Future object in coros_or_futures. 

922 fut = arg_to_fut[arg] 

923 

924 children.append(fut) 

925 

926 outer = _GatheringFuture(children, loop=loop) 

927 if cur_task is not None: 

928 # gh-157213: a child outliving gather() must lose the awaited-by edge 

929 outer.add_done_callback( 

930 functools.partial(_discard_awaited_by, children, cur_task)) 

931 # Run done callbacks after GatheringFuture created so any post-processing 

932 # can be performed at this point 

933 # optimization: in the special case that *all* futures finished eagerly, 

934 # this will effectively complete the gather eagerly, with the last 

935 # callback setting the result (or exception) on outer before returning it 

936 for fut in done_futs: 

937 _done_callback(fut) 

938 return outer 

939 

940 

941def _log_on_exception(fut): 

942 if fut.cancelled(): 942 ↛ 943line 942 didn't jump to line 943 because the condition on line 942 was never true

943 return 

944 

945 exc = fut.exception() 

946 if exc is None: 

947 return 

948 

949 context = { 

950 'message': 

951 f'{exc.__class__.__name__} exception in shielded future', 

952 'exception': exc, 

953 'future': fut, 

954 } 

955 if fut._source_traceback: 955 ↛ 956line 955 didn't jump to line 956 because the condition on line 955 was never true

956 context['source_traceback'] = fut._source_traceback 

957 fut._loop.call_exception_handler(context) 

958 

959 

960def shield(arg): 

961 """Wait for a future, shielding it from cancellation. 

962 

963 The statement 

964 

965 task = asyncio.create_task(something()) 

966 res = await shield(task) 

967 

968 is exactly equivalent to the statement 

969 

970 res = await something() 

971 

972 *except* that if the coroutine containing it is cancelled, the 

973 task running in something() is not cancelled. From the POV of 

974 something(), the cancellation did not happen. But its caller is 

975 still cancelled, so the yield-from expression still raises 

976 CancelledError. Note: If something() is cancelled by other means 

977 this will still cancel shield(). 

978 

979 If you want to completely ignore cancellation (not recommended) 

980 you can combine shield() with a try/except clause, as follows: 

981 

982 task = asyncio.create_task(something()) 

983 try: 

984 res = await shield(task) 

985 except CancelledError: 

986 res = None 

987 

988 Save a reference to tasks passed to this function, to avoid 

989 a task disappearing mid-execution. The event loop only keeps 

990 weak references to tasks. A task that isn't referenced elsewhere 

991 may get garbage collected at any time, even before it's done. 

992 """ 

993 inner = ensure_future(arg) 

994 if inner.done(): 

995 # Shortcut. 

996 return inner 

997 loop = futures._get_loop(inner) 

998 outer = loop.create_future() 

999 

1000 if loop is not None and (cur_task := current_task(loop)) is not None: 

1001 futures.future_add_to_awaited_by(inner, cur_task) 

1002 else: 

1003 cur_task = None 

1004 

1005 def _clear_awaited_by_callback(inner): 

1006 futures.future_discard_from_awaited_by(inner, cur_task) 

1007 

1008 def _inner_done_callback(inner): 

1009 if outer.cancelled(): 1009 ↛ 1010line 1009 didn't jump to line 1010 because the condition on line 1009 was never true

1010 return 

1011 

1012 if inner.cancelled(): 

1013 outer.cancel() 

1014 else: 

1015 exc = inner.exception() 

1016 if exc is not None: 

1017 outer.set_exception(exc) 

1018 else: 

1019 outer.set_result(inner.result()) 

1020 

1021 def _outer_done_callback(outer): 

1022 if not inner.done(): 

1023 inner.remove_done_callback(_inner_done_callback) 

1024 # Keep only one callback to log on cancel 

1025 inner.remove_done_callback(_log_on_exception) 

1026 inner.add_done_callback(_log_on_exception) 

1027 if cur_task is not None: 

1028 inner.remove_done_callback(_clear_awaited_by_callback) 

1029 futures.future_discard_from_awaited_by(inner, cur_task) 

1030 

1031 if cur_task is not None: 

1032 inner.add_done_callback(_clear_awaited_by_callback) 

1033 

1034 

1035 inner.add_done_callback(_inner_done_callback) 

1036 outer.add_done_callback(_outer_done_callback) 

1037 return outer 

1038 

1039 

1040def run_coroutine_threadsafe(coro, loop): 

1041 """Submit a coroutine object to a given event loop. 

1042 

1043 Return a concurrent.futures.Future to access the result. 

1044 """ 

1045 if not coroutines.iscoroutine(coro): 1045 ↛ 1046line 1045 didn't jump to line 1046 because the condition on line 1045 was never true

1046 raise TypeError('A coroutine object is required') 

1047 future = concurrent.futures.Future() 

1048 

1049 def callback(): 

1050 try: 

1051 futures._chain_future(ensure_future(coro, loop=loop), future) 

1052 except (SystemExit, KeyboardInterrupt): 

1053 raise 

1054 except BaseException as exc: 

1055 if future.set_running_or_notify_cancel(): 1055 ↛ 1057line 1055 didn't jump to line 1057 because the condition on line 1055 was always true

1056 future.set_exception(exc) 

1057 raise 

1058 

1059 loop.call_soon_threadsafe(callback) 

1060 return future 

1061 

1062 

1063def create_eager_task_factory(custom_task_constructor): 

1064 """Create a function suitable for use as a task factory on an event-loop. 

1065 

1066 Example usage: 

1067 

1068 loop.set_task_factory( 

1069 asyncio.create_eager_task_factory(my_task_constructor)) 

1070 

1071 Now, tasks created will be started immediately (rather than being first 

1072 scheduled to an event loop). The constructor argument can be any 

1073 callable that returns a Task-compatible object and has a signature 

1074 compatible with `Task.__init__`; it must have the `eager_start` 

1075 keyword argument. 

1076 

1077 Most applications will use `Task` for `custom_task_constructor` and in 

1078 this case there's no need to call `create_eager_task_factory()` 

1079 directly. Instead the global `eager_task_factory` instance can be 

1080 used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`. 

1081 """ 

1082 

1083 def factory(loop, coro, *, eager_start=True, **kwargs): 

1084 return custom_task_constructor( 

1085 coro, loop=loop, eager_start=eager_start, **kwargs) 

1086 

1087 return factory 

1088 

1089 

1090eager_task_factory = create_eager_task_factory(Task) 

1091 

1092 

1093# Collectively these two sets hold references to the complete set of active 

1094# tasks. Eagerly executed tasks use a faster regular set as an optimization 

1095# but may graduate to a WeakSet if the task blocks on IO. 

1096_scheduled_tasks = weakref.WeakSet() 

1097_eager_tasks = set() 

1098 

1099# Dictionary containing tasks that are currently active in 

1100# all running event loops. {EventLoop: Task} 

1101_current_tasks = {} 

1102 

1103 

1104def _register_task(task): 

1105 """Register an asyncio Task scheduled to run on an event loop.""" 

1106 _scheduled_tasks.add(task) 

1107 

1108 

1109def _register_eager_task(task): 

1110 """Register an asyncio Task about to be eagerly executed.""" 

1111 _eager_tasks.add(task) 

1112 

1113 

1114def _enter_task(loop, task): 

1115 current_task = _current_tasks.get(loop) 

1116 if current_task is not None: 

1117 raise RuntimeError(f"Cannot enter into task {task!r} while another " 

1118 f"task {current_task!r} is being executed.") 

1119 _current_tasks[loop] = task 

1120 

1121 

1122def _leave_task(loop, task): 

1123 current_task = _current_tasks.get(loop) 

1124 if current_task is not task: 

1125 raise RuntimeError(f"Leaving task {task!r} does not match " 

1126 f"the current task {current_task!r}.") 

1127 del _current_tasks[loop] 

1128 

1129 

1130def _swap_current_task(loop, task): 

1131 prev_task = _current_tasks.get(loop) 

1132 if task is None: 

1133 del _current_tasks[loop] 

1134 else: 

1135 _current_tasks[loop] = task 

1136 return prev_task 

1137 

1138 

1139def _unregister_task(task): 

1140 """Unregister a completed, scheduled Task.""" 

1141 _scheduled_tasks.discard(task) 

1142 

1143 

1144def _unregister_eager_task(task): 

1145 """Unregister a task which finished its first eager step.""" 

1146 _eager_tasks.discard(task) 

1147 

1148 

1149_py_current_task = current_task 

1150_py_register_task = _register_task 

1151_py_register_eager_task = _register_eager_task 

1152_py_unregister_task = _unregister_task 

1153_py_unregister_eager_task = _unregister_eager_task 

1154_py_enter_task = _enter_task 

1155_py_leave_task = _leave_task 

1156_py_swap_current_task = _swap_current_task 

1157_py_all_tasks = all_tasks 

1158 

1159try: 

1160 from _asyncio import (_register_task, _register_eager_task, 

1161 _unregister_task, _unregister_eager_task, 

1162 _enter_task, _leave_task, _swap_current_task, 

1163 current_task, all_tasks) 

1164except ImportError: 

1165 pass 

1166else: 

1167 _c_current_task = current_task 

1168 _c_register_task = _register_task 

1169 _c_register_eager_task = _register_eager_task 

1170 _c_unregister_task = _unregister_task 

1171 _c_unregister_eager_task = _unregister_eager_task 

1172 _c_enter_task = _enter_task 

1173 _c_leave_task = _leave_task 

1174 _c_swap_current_task = _swap_current_task 

1175 _c_all_tasks = all_tasks