From 4bf836904ce121b64b887bb7f556afeb57b12c0e Mon Sep 17 00:00:00 2001 From: Lev Vereshchagin Date: Thu, 21 Nov 2024 18:46:35 +0300 Subject: [PATCH 1/6] Fix `AsyncResponse.iter_lines()` Doesn't work now. Causes an exception:`TypeError: 'async for' requires an object with __aiter__ method, got coroutine` --- src/niquests/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/niquests/models.py b/src/niquests/models.py index 39f5603abf..e1633d496a 100644 --- a/src/niquests/models.py +++ b/src/niquests/models.py @@ -1800,7 +1800,7 @@ async def iter_lines( # type: ignore[misc] pending = None - async for chunk in self.iter_content( # type: ignore[call-overload] + async for chunk in await self.iter_content( # type: ignore[call-overload] chunk_size=chunk_size, decode_unicode=decode_unicode ): if pending is not None: @@ -1816,7 +1816,7 @@ async def iter_lines( # type: ignore[misc] else: pending = None - async for line in lines: + for line in lines: yield line if pending is not None: From 7e41d91e97c0c17461c5ad4cfdaec81c1bd656fc Mon Sep 17 00:00:00 2001 From: Ahmed TAHRI Date: Fri, 22 Nov 2024 08:05:23 +0100 Subject: [PATCH 2/6] :heavy_check_mark: Add test case for async iter_lines() --- tests/test_async.py | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/tests/test_async.py b/tests/test_async.py index 0b18a4afa0..90a81c52e8 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -106,28 +106,15 @@ async def callback_on_early(early_resp) -> None: assert resp.status_code == 200 assert received_early_response is True - # async def test_http_trailer_preload(self) -> None: - # async with AsyncSession() as s: - # r = await s.get("https://httpbingo.org/trailers?foo=baz") - # - # assert r.ok - # assert r.trailers - # assert "foo" in r.trailers - # assert r.trailers["foo"] == "baz" - # - # async def test_http_trailer_no_preload(self) -> None: - # async with AsyncSession() as s: - # r = await s.get("https://httpbingo.org/trailers?foo=baz", stream=True) - # - # assert r.ok - # assert not r.trailers - # assert "foo" not in r.trailers - # - # await r.content - # - # assert r.trailers - # assert "foo" in r.trailers - # assert r.trailers["foo"] == "baz" + async def test_iter_line(self) -> None: + async with AsyncSession() as s: + r = await s.get("https://httpbingo.org/html", stream=True) + content = b"" + + async for line in r.iter_lines(): + content += line + + assert content @pytest.mark.usefixtures("requires_wan") From 97ca75d9eab22ccf606e73b2aefdab2227547526 Mon Sep 17 00:00:00 2001 From: Ahmed TAHRI Date: Fri, 22 Nov 2024 08:06:45 +0100 Subject: [PATCH 3/6] :bookmark: add changelog entry --- HISTORY.md | 6 ++++++ src/niquests/__version__.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index a096d0cd98..6a47c4313e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,12 @@ Release History =============== +3.11.1 (2024-11-22) +------------------- + +**Fixed** +- async version of ``iter_line``. (#182) + 3.11.0 (2024-11-20) ------------------- diff --git a/src/niquests/__version__.py b/src/niquests/__version__.py index f3332a04e3..3de8b4490a 100644 --- a/src/niquests/__version__.py +++ b/src/niquests/__version__.py @@ -9,9 +9,9 @@ __url__: str = "https://niquests.readthedocs.io" __version__: str -__version__ = "3.11.0" +__version__ = "3.11.1" -__build__: int = 0x031100 +__build__: int = 0x031101 __author__: str = "Kenneth Reitz" __author_email__: str = "me@kennethreitz.org" __license__: str = "Apache-2.0" From 324994fa44d8c3e47556a75378bc54356cf48cb3 Mon Sep 17 00:00:00 2001 From: Ahmed TAHRI Date: Fri, 22 Nov 2024 08:12:42 +0100 Subject: [PATCH 4/6] :pencil: mention async iter_line in docs --- docs/user/quickstart.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst index 8b0690d5b1..deb82503bc 100644 --- a/docs/user/quickstart.rst +++ b/docs/user/quickstart.rst @@ -806,6 +806,22 @@ Delaying the content consumption in an async context can be easily achieved usin asyncio.run(main()) +Or using the ``iter_line`` method as such:: + + import niquests + import asyncio + + async def main() -> None: + + async with niquests.AsyncSession() as s: + r = await s.get("https://pie.dev/get", stream=True) + + async for chunk in r.iter_line(): + print(chunk) + + if __name__ == "__main__": + asyncio.run(main()) + Or simply by doing:: import niquests From 1ab275ebbe26abd6e25d79ef54b3df270782e972 Mon Sep 17 00:00:00 2001 From: Ahmed TAHRI Date: Fri, 22 Nov 2024 08:13:07 +0100 Subject: [PATCH 5/6] :heavy_check_mark: add test case async iter_line with decode --- tests/test_async.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_async.py b/tests/test_async.py index 90a81c52e8..3ff17a0df0 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -112,6 +112,18 @@ async def test_iter_line(self) -> None: content = b"" async for line in r.iter_lines(): + assert isinstance(line, bytes) + content += line + + assert content + + async def test_iter_line_decode(self) -> None: + async with AsyncSession() as s: + r = await s.get("https://httpbingo.org/html", stream=True) + content = "" + + async for line in r.iter_lines(decode_unicode=True): + assert isinstance(line, str) content += line assert content From 777ccf3a055bf1e0a14454d9505573cf57359f6d Mon Sep 17 00:00:00 2001 From: Ahmed TAHRI Date: Fri, 22 Nov 2024 08:15:32 +0100 Subject: [PATCH 6/6] :heavy_check_mark: ensure both test case output expected content --- tests/test_async.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_async.py b/tests/test_async.py index 3ff17a0df0..a94ee9dd7a 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -116,6 +116,7 @@ async def test_iter_line(self) -> None: content += line assert content + assert b"Herman Melville - Moby-Dick" in content async def test_iter_line_decode(self) -> None: async with AsyncSession() as s: @@ -127,6 +128,7 @@ async def test_iter_line_decode(self) -> None: content += line assert content + assert "Herman Melville - Moby-Dick" in content @pytest.mark.usefixtures("requires_wan")