Repository navigation
Restore async iterator compatibility #1168
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
Changes from all commits
d32f860
6c80f17
30a5d3f
0ea708f
0258f75
8045a42
625b319
8975595
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 |
|---|---|---|
|
|
@@ -27,6 +27,20 @@ async def async_streaming_body() -> typing.AsyncIterator[bytes]: | |
| yield b"world!" | ||
|
|
||
|
|
||
| class PlainAsyncIterator: | ||
| def __init__(self, chunks: list[bytes]) -> None: | ||
| self._chunks = iter(chunks) | ||
|
|
||
| def __aiter__(self) -> PlainAsyncIterator: | ||
| return self | ||
|
|
||
| async def __anext__(self) -> bytes: | ||
| try: | ||
| return next(self._chunks) | ||
| except StopIteration: | ||
| raise StopAsyncIteration from None | ||
|
|
||
|
|
||
| def autodetect(content: bytes) -> str | None: | ||
| return chardet.detect(content).get("encoding") | ||
|
|
||
|
|
@@ -493,6 +507,26 @@ async def test_aiter_raw_with_chunksize() -> None: | |
| assert parts == [b"Hello, world!"] | ||
|
|
||
|
|
||
| @pytest.mark.anyio | ||
| async def test_aiter_bytes_override() -> None: | ||
|
Contributor
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. P2: These rewritten tests only exercise async-generator overrides, so they pass without exercising the two behaviors this PR claims to restore/preserve: subclass overrides returning plain async iterators without Prompt for AI agents |
||
| class CustomResponse(httpx2.Response): | ||
| def aiter_bytes(self, chunk_size: int | None = None) -> typing.AsyncIterator[bytes]: | ||
| return PlainAsyncIterator([b"Hello, ", b"world!"]) | ||
|
|
||
| response = CustomResponse(200, content=async_streaming_body()) | ||
| assert await response.aread() == b"Hello, world!" | ||
|
|
||
|
|
||
| @pytest.mark.anyio | ||
| async def test_aiter_raw_override() -> None: | ||
| class CustomResponse(httpx2.Response): | ||
| def aiter_raw(self, chunk_size: int | None = None) -> typing.AsyncIterator[bytes]: | ||
| return PlainAsyncIterator([b"Hello, ", b"world!"]) | ||
|
|
||
| response = CustomResponse(200, content=async_streaming_body()) | ||
| assert await response.aread() == b"Hello, world!" | ||
|
|
||
|
|
||
| @pytest.mark.anyio | ||
| async def test_aiter_raw_on_sync() -> None: | ||
| response = httpx2.Response( | ||
|
|
||
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.
P2: When an
AsyncByteStreamreturns a custom iterator withaclose(),aiter_raw()skips that cleanup becauseAsyncGeneratoris not a structural check for custom iterators. Detect and await an exposedaclose()method instead.Prompt for AI agents