From 5439975fa8a92d024b7c124c4e033abaae354223 Mon Sep 17 00:00:00 2001 From: Max Fischer Date: Thu, 1 Aug 2024 13:22:28 +0200 Subject: [PATCH 1/6] fix tee.__iter__ annotation (closes #151) --- asyncstdlib/itertools.py | 2 +- asyncstdlib/itertools.pyi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/asyncstdlib/itertools.py b/asyncstdlib/itertools.py index eb29a26..f0e09ef 100644 --- a/asyncstdlib/itertools.py +++ b/asyncstdlib/itertools.py @@ -454,7 +454,7 @@ def __getitem__( ) -> Union[AsyncIterator[T], Tuple[AsyncIterator[T], ...]]: return self._children[item] - def __iter__(self) -> Iterator[AnyIterable[T]]: + def __iter__(self) -> Iterator[AsyncIterator[T]]: yield from self._children async def __aenter__(self) -> "Tee[T]": diff --git a/asyncstdlib/itertools.pyi b/asyncstdlib/itertools.pyi index d97a266..699aed7 100644 --- a/asyncstdlib/itertools.pyi +++ b/asyncstdlib/itertools.pyi @@ -130,7 +130,7 @@ class tee(Generic[T]): def __getitem__(self, item: int) -> AsyncIterator[T]: ... @overload def __getitem__(self, item: slice) -> tuple[AsyncIterator[T], ...]: ... - def __iter__(self) -> Iterator[AnyIterable[T]]: ... + def __iter__(self) -> Iterator[AsyncIterator[T]]: ... async def __aenter__(self: Self) -> Self: ... async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: ... async def aclose(self) -> None: ... From cb68990f898b9598a6d84b0b655c57aaec7818d0 Mon Sep 17 00:00:00 2001 From: Max Fischer Date: Thu, 1 Aug 2024 13:33:26 +0200 Subject: [PATCH 2/6] test unpacking tee --- typetests/test_itertools.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/typetests/test_itertools.py b/typetests/test_itertools.py index d621923..2cac7c3 100644 --- a/typetests/test_itertools.py +++ b/typetests/test_itertools.py @@ -56,6 +56,16 @@ async def test_tee() -> None: assert_type(x, int) +async def test_tee_iter() -> None: + x1, x2 = itertools.tee([1], n=2) + assert_type(x1, AsyncIterator[int]) + assert_type(x2, AsyncIterator[int]) + + for xi in itertools.tee([1], n=2): + async for x in xi: + assert_type(x, int) + + async def test_pairwise() -> None: async for x in itertools.pairwise([1]): assert_type(x, "tuple[int, int]") From 04c0fba0da7a58f6ff4a9e52c4b53abe894760fe Mon Sep 17 00:00:00 2001 From: Max Fischer Date: Thu, 1 Aug 2024 13:42:14 +0200 Subject: [PATCH 3/6] add missing type information, preserve generator tyyping --- asyncstdlib/asynctools.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/asyncstdlib/asynctools.py b/asyncstdlib/asynctools.py index 0be4b9f..b75731b 100644 --- a/asyncstdlib/asynctools.py +++ b/asyncstdlib/asynctools.py @@ -119,7 +119,17 @@ def __repr__(self) -> str: return f"<{self.__class__.__name__} of {self._iterator!r} at 0x{(id(self)):x}>" -def borrow(iterator: AsyncIterator[T], /) -> AsyncIterator[T]: +@overload +def borrow(iterator: AsyncGenerator[T, S], /) -> AsyncGenerator[T, S]: ... + + +@overload +def borrow(iterator: AsyncIterator[T], /) -> AsyncIterator[T]: ... + + +def borrow( + iterator: Union[AsyncIterator[T], AsyncGenerator[T, Any]], / +) -> Union[AsyncIterator[T], AsyncGenerator[T, Any]]: """ Borrow an async iterator, preventing to ``aclose`` it @@ -142,7 +152,7 @@ def borrow(iterator: AsyncIterator[T], /) -> AsyncIterator[T]: "borrowing requires an async iterator " + f"with __aiter__ and __anext__ method, got {type(iterator).__name__}" ) - return _BorrowedAsyncIterator(iterator) + return _BorrowedAsyncIterator[T, Any](iterator) def scoped_iter(iterable: AnyIterable[T], /) -> AsyncContextManager[AsyncIterator[T]]: From 47a18ca83a5fa385ab2e44d77c74cd6540c728b0 Mon Sep 17 00:00:00 2001 From: Max Fischer Date: Thu, 1 Aug 2024 13:44:42 +0200 Subject: [PATCH 4/6] document fake TypeVar --- asyncstdlib/_lrucache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyncstdlib/_lrucache.py b/asyncstdlib/_lrucache.py index ed1abc0..102b98d 100644 --- a/asyncstdlib/_lrucache.py +++ b/asyncstdlib/_lrucache.py @@ -120,7 +120,7 @@ def cache_discard(self, *args: Any, **kwargs: Any) -> None: # these are fake and only exist for placeholders S = TypeVar("S") S2 = TypeVar("S2") -P = TypeVar("P") +P = TypeVar("P") # actually a ParamSpec, see .pyi R = TypeVar("R") From e763db421900d2fe6ade0b6c98a16229950058a2 Mon Sep 17 00:00:00 2001 From: Max Fischer Date: Thu, 1 Aug 2024 13:46:08 +0200 Subject: [PATCH 5/6] ignore impl type lack --- asyncstdlib/_lrucache.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/asyncstdlib/_lrucache.py b/asyncstdlib/_lrucache.py index 102b98d..58b20b3 100644 --- a/asyncstdlib/_lrucache.py +++ b/asyncstdlib/_lrucache.py @@ -81,7 +81,9 @@ def __get__( """Descriptor ``__get__`` for caches to bind them on lookup""" if instance is None: return self - return LRUAsyncBoundCallable(self, instance) + return LRUAsyncBoundCallable( + self, instance + ) # pyright: ignore[reportUnknownVariableType] #: Get the result of ``await __wrapped__(...)`` from the cache or evaluation __call__: AC From c6c1410450ac20f2e1a24021e6509cff03551c94 Mon Sep 17 00:00:00 2001 From: Max Fischer Date: Thu, 1 Aug 2024 14:42:29 +0200 Subject: [PATCH 6/6] do not double-check black formatting --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 00e0021..91608ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [flake8] statistics = True max-line-length = 80 -ignore = E302, E501, E704, B008, B011, B905, B950, W503 +ignore = E302, E501, E704, B008, B011, B905, B950, W503, W504 select = C,E,F,W,B,B9 exclude = docs,.svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg