-
Notifications
You must be signed in to change notification settings - Fork 556
bidi - async - remove cancelling call #1357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,17 +6,17 @@ | |
| """ | ||
|
|
||
| import asyncio | ||
| from typing import Any, Coroutine | ||
| from typing import Any, Coroutine, cast | ||
|
|
||
|
|
||
| class _TaskGroup: | ||
| """Shim of asyncio.TaskGroup for use in Python 3.10. | ||
|
|
||
| Attributes: | ||
| _tasks: List of tasks in group. | ||
| _tasks: Set of tasks in group. | ||
| """ | ||
|
|
||
| _tasks: list[asyncio.Task] | ||
| _tasks: set[asyncio.Task] | ||
|
|
||
| def create_task(self, coro: Coroutine[Any, Any, Any]) -> asyncio.Task: | ||
| """Create an async task and add to group. | ||
|
|
@@ -25,12 +25,12 @@ def create_task(self, coro: Coroutine[Any, Any, Any]) -> asyncio.Task: | |
| The created task. | ||
| """ | ||
| task = asyncio.create_task(coro) | ||
| self._tasks.append(task) | ||
| self._tasks.add(task) | ||
| return task | ||
|
|
||
| async def __aenter__(self) -> "_TaskGroup": | ||
| """Setup self managed task group context.""" | ||
| self._tasks = [] | ||
| self._tasks = set() | ||
| return self | ||
|
|
||
| async def __aexit__(self, *_: Any) -> None: | ||
|
|
@@ -42,20 +42,28 @@ async def __aexit__(self, *_: Any) -> None: | |
| - The context re-raises CancelledErrors to the caller only if the context itself was cancelled. | ||
| """ | ||
| try: | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have the execution rules listed above in the docstring. To repeat here: |
||
| await asyncio.gather(*self._tasks) | ||
| pending_tasks = self._tasks | ||
| while pending_tasks: | ||
| done_tasks, pending_tasks = await asyncio.wait(pending_tasks, return_when=asyncio.FIRST_EXCEPTION) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we reassign |
||
|
|
||
| except (Exception, asyncio.CancelledError) as error: | ||
| if any(exception := done_task.exception() for done_task in done_tasks if not done_task.cancelled()): | ||
| break | ||
|
|
||
| else: # all tasks completed/cancelled successfully | ||
| return | ||
|
|
||
| for pending_task in pending_tasks: | ||
| pending_task.cancel() | ||
|
|
||
| await asyncio.gather(*pending_tasks, return_exceptions=True) | ||
| raise cast(BaseException, exception) | ||
|
|
||
| except asyncio.CancelledError: # context itself was cancelled | ||
| for task in self._tasks: | ||
| task.cancel() | ||
|
|
||
| await asyncio.gather(*self._tasks, return_exceptions=True) | ||
|
|
||
| if not isinstance(error, asyncio.CancelledError): | ||
| raise | ||
|
|
||
| context_task = asyncio.current_task() | ||
| if context_task and context_task.cancelling() > 0: # context itself was cancelled | ||
| raise | ||
| raise | ||
|
|
||
| finally: | ||
| self._tasks = [] | ||
| self._tasks = set() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching to set to be consistent with
asyncio.waitwhich putsdone_tasksandpending_tasksinto sets. This in turn helps to resolve a mypy error.