From 2aae2dcedd5dc165cf20baebacd9932a33ddaeba Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 00:15:50 -0500 Subject: [PATCH 01/14] Add typing for `_core/_asyncgens.py` --- trio/_core/_asyncgens.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 5f02ebe76d..74163112fa 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -1,7 +1,11 @@ +from __future__ import annotations + import logging import sys import warnings import weakref +from collections.abc import AsyncGenerator +from typing import TYPE_CHECKING, Any, Generic, TypeVar import attr @@ -9,6 +13,9 @@ from .._util import name_asyncgen from . import _run +if TYPE_CHECKING: + from ._run import Runner + # Used to log exceptions in async generator finalizers ASYNCGEN_LOGGER = logging.getLogger("trio.async_generator_errors") @@ -22,17 +29,17 @@ class AsyncGenerators: # asyncgens after the system nursery has been closed, it's a # regular set so we don't have to deal with GC firing at # unexpected times. - alive = attr.ib(factory=weakref.WeakSet) + alive: weakref.WeakSet[AsyncGenerator[Any, Any]] | set[AsyncGenerator[Any, Any]] = attr.ib(factory=weakref.WeakSet) # type: ignore[assignment] # This collects async generators that get garbage collected during # the one-tick window between the system nursery closing and the # init task starting end-of-run asyncgen finalization. - trailing_needs_finalize = attr.ib(factory=set) + trailing_needs_finalize: set[AsyncGenerator[Any, Any]] = attr.ib(factory=set) prev_hooks = attr.ib(init=False) - def install_hooks(self, runner): - def firstiter(agen): + def install_hooks(self, runner: Runner) -> None: + def firstiter(agen: AsyncGenerator[Any, Any]) -> None: if hasattr(_run.GLOBAL_RUN_CONTEXT, "task"): self.alive.add(agen) else: @@ -46,7 +53,9 @@ def firstiter(agen): if self.prev_hooks.firstiter is not None: self.prev_hooks.firstiter(agen) - def finalize_in_trio_context(agen, agen_name): + def finalize_in_trio_context( + agen: AsyncGenerator[Any, Any], agen_name: str + ) -> None: try: runner.spawn_system_task( self._finalize_one, @@ -61,7 +70,7 @@ def finalize_in_trio_context(agen, agen_name): # have hit it. self.trailing_needs_finalize.add(agen) - def finalizer(agen): + def finalizer(agen: AsyncGenerator[Any, Any]) -> None: agen_name = name_asyncgen(agen) try: is_ours = not agen.ag_frame.f_locals.get("@trio_foreign_asyncgen") @@ -114,12 +123,12 @@ def finalizer(agen): self.prev_hooks = sys.get_asyncgen_hooks() sys.set_asyncgen_hooks(firstiter=firstiter, finalizer=finalizer) - async def finalize_remaining(self, runner): + async def finalize_remaining(self, runner: Runner) -> None: # This is called from init after shutting down the system nursery. # The only tasks running at this point are init and # the run_sync_soon task, and since the system nursery is closed, # there's no way for user code to spawn more. - assert _core.current_task() is runner.init_task + assert _core.current_task() is runner.init_task # type: ignore[attr-defined] assert len(runner.tasks) == 2 # To make async generator finalization easier to reason @@ -130,8 +139,8 @@ async def finalize_remaining(self, runner): # Process all pending run_sync_soon callbacks, in case one of # them was an asyncgen finalizer that snuck in under the wire. runner.entry_queue.run_sync_soon(runner.reschedule, runner.init_task) - await _core.wait_task_rescheduled( - lambda _: _core.Abort.FAILED # pragma: no cover + await _core.wait_task_rescheduled( # type: ignore[attr-defined] + lambda _: _core.Abort.FAILED # noqa ) self.alive.update(self.trailing_needs_finalize) self.trailing_needs_finalize.clear() @@ -174,15 +183,17 @@ async def finalize_remaining(self, runner): for agen in batch: await self._finalize_one(agen, name_asyncgen(agen)) - def close(self): + def close(self) -> None: sys.set_asyncgen_hooks(*self.prev_hooks) - async def _finalize_one(self, agen, name): + async def _finalize_one( + self, agen: AsyncGenerator[Any, Any], name: str | object + ) -> None: try: # This shield ensures that finalize_asyncgen never exits # with an exception, not even a Cancelled. The inside # is cancelled so there's no deadlock risk. - with _core.CancelScope(shield=True) as cancel_scope: + with _core.CancelScope(shield=True) as cancel_scope: # type: ignore[attr-defined] cancel_scope.cancel() await agen.aclose() except BaseException: From b9cc13060832232293bcd8e17f8bd32b87b6153e Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 00:25:53 -0500 Subject: [PATCH 02/14] Fix unused type ignores --- trio/_core/_asyncgens.py | 8 ++++---- trio/_util.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 74163112fa..2d9d658103 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -128,7 +128,7 @@ async def finalize_remaining(self, runner: Runner) -> None: # The only tasks running at this point are init and # the run_sync_soon task, and since the system nursery is closed, # there's no way for user code to spawn more. - assert _core.current_task() is runner.init_task # type: ignore[attr-defined] + assert _core.current_task() is runner.init_task assert len(runner.tasks) == 2 # To make async generator finalization easier to reason @@ -139,8 +139,8 @@ async def finalize_remaining(self, runner: Runner) -> None: # Process all pending run_sync_soon callbacks, in case one of # them was an asyncgen finalizer that snuck in under the wire. runner.entry_queue.run_sync_soon(runner.reschedule, runner.init_task) - await _core.wait_task_rescheduled( # type: ignore[attr-defined] - lambda _: _core.Abort.FAILED # noqa + await _core.wait_task_rescheduled( + lambda _: _core.Abort.FAILED # pragma: no cover ) self.alive.update(self.trailing_needs_finalize) self.trailing_needs_finalize.clear() @@ -193,7 +193,7 @@ async def _finalize_one( # This shield ensures that finalize_asyncgen never exits # with an exception, not even a Cancelled. The inside # is cancelled so there's no deadlock risk. - with _core.CancelScope(shield=True) as cancel_scope: # type: ignore[attr-defined] + with _core.CancelScope(shield=True) as cancel_scope: cancel_scope.cancel() await agen.aclose() except BaseException: diff --git a/trio/_util.py b/trio/_util.py index a87f1fc02c..a15717021b 100644 --- a/trio/_util.py +++ b/trio/_util.py @@ -338,7 +338,7 @@ def _create(cls: t.Type[T], *args: object, **kwargs: object) -> T: return super().__call__(*args, **kwargs) # type: ignore -def name_asyncgen(agen): +def name_asyncgen(agen: t.AsyncGenerator[t.Any, t.Any]) -> str: """Return the fully-qualified name of the async generator function that produced the async generator iterator *agen*. """ From 4bd0290e7a7eae7ea019119ef1cfed142120330c Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 00:33:00 -0500 Subject: [PATCH 03/14] Remove unused imports and update `__qualname__` get --- trio/_core/_asyncgens.py | 2 +- trio/_util.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 2d9d658103..dc5f6b1b33 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -5,7 +5,7 @@ import warnings import weakref from collections.abc import AsyncGenerator -from typing import TYPE_CHECKING, Any, Generic, TypeVar +from typing import TYPE_CHECKING, Any import attr diff --git a/trio/_util.py b/trio/_util.py index 61d4285f80..0c80c59138 100644 --- a/trio/_util.py +++ b/trio/_util.py @@ -370,8 +370,5 @@ def name_asyncgen(agen: collections.abc.AsyncGenerator[object, t.NoReturn]) -> s module = agen.ag_frame.f_globals["__name__"] except (AttributeError, KeyError): module = f"<{agen.ag_code.co_filename}>" - try: - qualname = agen.__qualname__ - except AttributeError: - qualname = agen.ag_code.co_name + qualname = getattr(agen, "__qualname__", agen.ag_code.co_name) return f"{module}.{qualname}" From 0205c8f6ab5d565b90b00d6e172c97fd22d6c407 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 01:31:49 -0500 Subject: [PATCH 04/14] Add suggestions from @TeamSpen210 --- trio/_core/_asyncgens.py | 30 ++++++++++++++++-------------- trio/_util.py | 4 ++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index dc5f6b1b33..21abc51b2d 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -4,8 +4,9 @@ import sys import warnings import weakref -from collections.abc import AsyncGenerator -from typing import TYPE_CHECKING, Any +from collections.abc import MutableSet +from types import AsyncGeneratorType +from typing import Any, NoReturn import attr @@ -13,9 +14,6 @@ from .._util import name_asyncgen from . import _run -if TYPE_CHECKING: - from ._run import Runner - # Used to log exceptions in async generator finalizers ASYNCGEN_LOGGER = logging.getLogger("trio.async_generator_errors") @@ -29,17 +27,21 @@ class AsyncGenerators: # asyncgens after the system nursery has been closed, it's a # regular set so we don't have to deal with GC firing at # unexpected times. - alive: weakref.WeakSet[AsyncGenerator[Any, Any]] | set[AsyncGenerator[Any, Any]] = attr.ib(factory=weakref.WeakSet) # type: ignore[assignment] + alive: MutableSet[AsyncGeneratorType[object, NoReturn]] = attr.ib( + factory=weakref.WeakSet + ) # This collects async generators that get garbage collected during # the one-tick window between the system nursery closing and the # init task starting end-of-run asyncgen finalization. - trailing_needs_finalize: set[AsyncGenerator[Any, Any]] = attr.ib(factory=set) + trailing_needs_finalize: set[AsyncGeneratorType[object, NoReturn]] = attr.ib( + factory=set + ) prev_hooks = attr.ib(init=False) - def install_hooks(self, runner: Runner) -> None: - def firstiter(agen: AsyncGenerator[Any, Any]) -> None: + def install_hooks(self, runner: _run.Runner) -> None: + def firstiter(agen: AsyncGeneratorType[object, NoReturn]) -> None: if hasattr(_run.GLOBAL_RUN_CONTEXT, "task"): self.alive.add(agen) else: @@ -54,7 +56,7 @@ def firstiter(agen: AsyncGenerator[Any, Any]) -> None: self.prev_hooks.firstiter(agen) def finalize_in_trio_context( - agen: AsyncGenerator[Any, Any], agen_name: str + agen: AsyncGeneratorType[object, NoReturn], agen_name: str ) -> None: try: runner.spawn_system_task( @@ -70,7 +72,7 @@ def finalize_in_trio_context( # have hit it. self.trailing_needs_finalize.add(agen) - def finalizer(agen: AsyncGenerator[Any, Any]) -> None: + def finalizer(agen: AsyncGeneratorType[object, NoReturn]) -> None: agen_name = name_asyncgen(agen) try: is_ours = not agen.ag_frame.f_locals.get("@trio_foreign_asyncgen") @@ -121,9 +123,9 @@ def finalizer(agen: AsyncGenerator[Any, Any]) -> None: ) self.prev_hooks = sys.get_asyncgen_hooks() - sys.set_asyncgen_hooks(firstiter=firstiter, finalizer=finalizer) + sys.set_asyncgen_hooks(firstiter=firstiter, finalizer=finalizer) # type: ignore[arg-type] # Finalizer doesn't use AsyncGeneratorType - async def finalize_remaining(self, runner: Runner) -> None: + async def finalize_remaining(self, runner: _run.Runner) -> None: # This is called from init after shutting down the system nursery. # The only tasks running at this point are init and # the run_sync_soon task, and since the system nursery is closed, @@ -187,7 +189,7 @@ def close(self) -> None: sys.set_asyncgen_hooks(*self.prev_hooks) async def _finalize_one( - self, agen: AsyncGenerator[Any, Any], name: str | object + self, agen: AsyncGeneratorType[object, NoReturn], name: object ) -> None: try: # This shield ensures that finalize_asyncgen never exits diff --git a/trio/_util.py b/trio/_util.py index 0c80c59138..5f332d2081 100644 --- a/trio/_util.py +++ b/trio/_util.py @@ -9,7 +9,7 @@ import typing as t from abc import ABCMeta from functools import update_wrapper -from types import TracebackType +from types import AsyncGeneratorType, TracebackType import trio @@ -360,7 +360,7 @@ def _create(cls: t.Type[T], *args: object, **kwargs: object) -> T: return super().__call__(*args, **kwargs) # type: ignore -def name_asyncgen(agen: collections.abc.AsyncGenerator[object, t.NoReturn]) -> str: +def name_asyncgen(agen: AsyncGeneratorType[object, t.NoReturn]) -> str: """Return the fully-qualified name of the async generator function that produced the async generator iterator *agen*. """ From 2e255eb8da2787009f72cf2a53ba29025c62bf24 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 01:47:56 -0500 Subject: [PATCH 05/14] Fix type issues --- trio/_core/_asyncgens.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 21abc51b2d..2d85ad26f2 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -6,7 +6,7 @@ import weakref from collections.abc import MutableSet from types import AsyncGeneratorType -from typing import Any, NoReturn +from typing import TYPE_CHECKING, NoReturn import attr @@ -17,6 +17,13 @@ # Used to log exceptions in async generator finalizers ASYNCGEN_LOGGER = logging.getLogger("trio.async_generator_errors") +if TYPE_CHECKING: + _WEAK_ASYNC_GEN_SET = weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] + _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] +else: + _WEAK_ASYNC_GEN_SET = weakref.WeakSet + _ASYNC_GEN_SET = set + @attr.s(eq=False, slots=True) class AsyncGenerators: @@ -27,15 +34,15 @@ class AsyncGenerators: # asyncgens after the system nursery has been closed, it's a # regular set so we don't have to deal with GC firing at # unexpected times. - alive: MutableSet[AsyncGeneratorType[object, NoReturn]] = attr.ib( - factory=weakref.WeakSet - ) + alive: weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] | set[ + AsyncGeneratorType[object, NoReturn] + ] = attr.ib(factory=_WEAK_ASYNC_GEN_SET) # This collects async generators that get garbage collected during # the one-tick window between the system nursery closing and the # init task starting end-of-run asyncgen finalization. trailing_needs_finalize: set[AsyncGeneratorType[object, NoReturn]] = attr.ib( - factory=set + factory=_ASYNC_GEN_SET ) prev_hooks = attr.ib(init=False) @@ -181,7 +188,7 @@ async def finalize_remaining(self, runner: _run.Runner) -> None: # all are gone. while self.alive: batch = self.alive - self.alive = set() + self.alive = _ASYNC_GEN_SET() for agen in batch: await self._finalize_one(agen, name_asyncgen(agen)) From 28512aa0e05a4f2973afac9c6b683cc43f6d7360 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 01:51:54 -0500 Subject: [PATCH 06/14] Add explain comment --- trio/_core/_asyncgens.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 2d85ad26f2..2c8fff5729 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -18,6 +18,7 @@ ASYNCGEN_LOGGER = logging.getLogger("trio.async_generator_errors") if TYPE_CHECKING: + # TODO: Remove when dropping 3.8 support, __class_getitem__ added in 3.9 _WEAK_ASYNC_GEN_SET = weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] else: From 89e0212de0074ec6def0b8f48d59e55295960b9d Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 02:00:48 -0500 Subject: [PATCH 07/14] Attempt to fix python 3.8 issues --- trio/_core/_asyncgens.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 2c8fff5729..7b88174a17 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -20,7 +20,12 @@ if TYPE_CHECKING: # TODO: Remove when dropping 3.8 support, __class_getitem__ added in 3.9 _WEAK_ASYNC_GEN_SET = weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] - _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] + if sys.version_info < (3, 10): + from collections.abc import Set + + _ASYNC_GEN_SET = Set[AsyncGeneratorType[object, NoReturn]] + else: + _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] else: _WEAK_ASYNC_GEN_SET = weakref.WeakSet _ASYNC_GEN_SET = set From 73f53f50192d1f18ca89e5cb2da5d43d1f069b84 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 02:05:14 -0500 Subject: [PATCH 08/14] Second attempt to fix 3.8 --- trio/_core/_asyncgens.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 7b88174a17..9a767eca45 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -21,7 +21,7 @@ # TODO: Remove when dropping 3.8 support, __class_getitem__ added in 3.9 _WEAK_ASYNC_GEN_SET = weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] if sys.version_info < (3, 10): - from collections.abc import Set + from typing import Set _ASYNC_GEN_SET = Set[AsyncGeneratorType[object, NoReturn]] else: From 3ef537c5d8083df1b0d8eb4c32ade4d410bfc908 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 02:07:36 -0500 Subject: [PATCH 09/14] Remove unused import --- trio/_core/_asyncgens.py | 1 - 1 file changed, 1 deletion(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 9a767eca45..8743ce7eda 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -4,7 +4,6 @@ import sys import warnings import weakref -from collections.abc import MutableSet from types import AsyncGeneratorType from typing import TYPE_CHECKING, NoReturn From 82900e523b03a840a5cde4186d9226fa8501d448 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Fri, 4 Aug 2023 23:18:31 -0500 Subject: [PATCH 10/14] Revert try except conversion --- trio/_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trio/_util.py b/trio/_util.py index 5f332d2081..ba56c18385 100644 --- a/trio/_util.py +++ b/trio/_util.py @@ -370,5 +370,8 @@ def name_asyncgen(agen: AsyncGeneratorType[object, t.NoReturn]) -> str: module = agen.ag_frame.f_globals["__name__"] except (AttributeError, KeyError): module = f"<{agen.ag_code.co_filename}>" - qualname = getattr(agen, "__qualname__", agen.ag_code.co_name) + try: + qualname = agen.__qualname__ + except AttributeError: + qualname = agen.ag_code.co_name return f"{module}.{qualname}" From cd19e84a9749c2417ec73b54b27199a7e1dedfbd Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 6 Aug 2023 16:41:26 -0500 Subject: [PATCH 11/14] Add asyncgens to stricter type checking block --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 90bc98f64f..f82b719069 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ disallow_untyped_defs = false # Fully typed, enable stricter checks module = [ "trio._abc", + "trio._core._asyncgens.py", "trio._core._entry_queue", "trio._core._local", "trio._core._unbounded_queue", From 07b26fa472a985d172d658c2ea2078ba65fa49c6 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 6 Aug 2023 20:36:54 -0500 Subject: [PATCH 12/14] Fix issues noted by @TeamSpen210 --- pyproject.toml | 4 ++-- trio/_core/_asyncgens.py | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 41ddcfb46f..7de35f0b0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,14 +50,14 @@ disallow_untyped_defs = false # Fully typed, enable stricter checks module = [ "trio._abc", - "trio._core._asyncgens.py", + "trio._core._asyncgens", "trio._core._entry_queue", "trio._core._local", "trio._core._unbounded_queue", "trio._deprecate", "trio._dtls", "trio._file_io", - "trio._highlevel_open_tcp_stream.py", + "trio._highlevel_open_tcp_stream", "trio._ki", "trio._socket", "trio._sync", diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 8743ce7eda..be0f669d8a 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -17,14 +17,8 @@ ASYNCGEN_LOGGER = logging.getLogger("trio.async_generator_errors") if TYPE_CHECKING: - # TODO: Remove when dropping 3.8 support, __class_getitem__ added in 3.9 _WEAK_ASYNC_GEN_SET = weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] - if sys.version_info < (3, 10): - from typing import Set - - _ASYNC_GEN_SET = Set[AsyncGeneratorType[object, NoReturn]] - else: - _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] + _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] else: _WEAK_ASYNC_GEN_SET = weakref.WeakSet _ASYNC_GEN_SET = set From b6f28e9c037d94643ee6f9c7ad96e2e45f08ec6f Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 6 Aug 2023 21:15:45 -0500 Subject: [PATCH 13/14] Change to typing Set because pre-3.9 --- trio/_core/_asyncgens.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index be0f669d8a..1ce5154421 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -17,8 +17,10 @@ ASYNCGEN_LOGGER = logging.getLogger("trio.async_generator_errors") if TYPE_CHECKING: + from typing import Set + _WEAK_ASYNC_GEN_SET = weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] - _ASYNC_GEN_SET = set[AsyncGeneratorType[object, NoReturn]] + _ASYNC_GEN_SET = Set[AsyncGeneratorType[object, NoReturn]] else: _WEAK_ASYNC_GEN_SET = weakref.WeakSet _ASYNC_GEN_SET = set From d2c5f3c2fa659fde97ccad44fdcd5b960f00a6ec Mon Sep 17 00:00:00 2001 From: CoolCat467 Date: Sat, 5 Aug 2023 21:42:13 -0500 Subject: [PATCH 14/14] Change to use type aliases --- trio/_core/_asyncgens.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/trio/_core/_asyncgens.py b/trio/_core/_asyncgens.py index 1ce5154421..4261328278 100644 --- a/trio/_core/_asyncgens.py +++ b/trio/_core/_asyncgens.py @@ -35,16 +35,12 @@ class AsyncGenerators: # asyncgens after the system nursery has been closed, it's a # regular set so we don't have to deal with GC firing at # unexpected times. - alive: weakref.WeakSet[AsyncGeneratorType[object, NoReturn]] | set[ - AsyncGeneratorType[object, NoReturn] - ] = attr.ib(factory=_WEAK_ASYNC_GEN_SET) + alive: _WEAK_ASYNC_GEN_SET | _ASYNC_GEN_SET = attr.ib(factory=_WEAK_ASYNC_GEN_SET) # This collects async generators that get garbage collected during # the one-tick window between the system nursery closing and the # init task starting end-of-run asyncgen finalization. - trailing_needs_finalize: set[AsyncGeneratorType[object, NoReturn]] = attr.ib( - factory=_ASYNC_GEN_SET - ) + trailing_needs_finalize: _ASYNC_GEN_SET = attr.ib(factory=_ASYNC_GEN_SET) prev_hooks = attr.ib(init=False)