Skip to content

Commit 59e6135

Browse files
authored
✨ close and map stream exception
1 parent 5598607 commit 59e6135

File tree

2 files changed

+44
-38
lines changed

2 files changed

+44
-38
lines changed

githubkit/response.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from collections.abc import AsyncIterator, Iterator
2+
from contextlib import asynccontextmanager, contextmanager
23
from typing import Any, Generic, Optional
34
from typing_extensions import TypeVar
45

56
import httpx
67

78
from .compat import type_validate_json
9+
from .exception import RequestError, RequestTimeout
810

911
MT = TypeVar("MT", default=Any)
1012
JT = TypeVar("JT", default=Any)
@@ -94,32 +96,62 @@ def json(self, **kwargs: Any) -> JT:
9496
def parsed_data(self) -> MT:
9597
return type_validate_json(self._data_model, self.content)
9698

99+
@contextmanager
100+
def _catch_and_close(self):
101+
try:
102+
yield
103+
except httpx.TimeoutException as e:
104+
raise RequestTimeout(e) from e
105+
except Exception as e:
106+
raise RequestError(e) from e
107+
finally:
108+
self._response.close()
109+
110+
@asynccontextmanager
111+
async def _acatch_and_close(self):
112+
try:
113+
yield
114+
except httpx.TimeoutException as e:
115+
raise RequestTimeout(e) from e
116+
except Exception as e:
117+
raise RequestError(e) from e
118+
finally:
119+
await self._response.aclose()
120+
97121
def iter_bytes(self, chunk_size: Optional[int] = None) -> Iterator[bytes]:
98-
yield from self._response.iter_bytes(chunk_size=chunk_size)
122+
with self._catch_and_close():
123+
yield from self._response.iter_bytes(chunk_size=chunk_size)
99124

100125
def iter_text(self, chunk_size: Optional[int] = None) -> Iterator[str]:
101-
yield from self._response.iter_text(chunk_size=chunk_size)
126+
with self._catch_and_close():
127+
yield from self._response.iter_text(chunk_size=chunk_size)
102128

103129
def iter_lines(self) -> Iterator[str]:
104-
yield from self._response.iter_lines()
130+
with self._catch_and_close():
131+
yield from self._response.iter_lines()
105132

106133
def iter_raw(self, chunk_size: Optional[int] = None) -> Iterator[bytes]:
107-
yield from self._response.iter_raw(chunk_size=chunk_size)
134+
with self._catch_and_close():
135+
yield from self._response.iter_raw(chunk_size=chunk_size)
108136

109137
async def aiter_bytes(
110138
self, chunk_size: Optional[int] = None
111139
) -> AsyncIterator[bytes]:
112-
async for chunk in self._response.aiter_bytes(chunk_size=chunk_size):
113-
yield chunk
140+
async with self._acatch_and_close():
141+
async for chunk in self._response.aiter_bytes(chunk_size=chunk_size):
142+
yield chunk
114143

115144
async def aiter_text(self, chunk_size: Optional[int] = None) -> AsyncIterator[str]:
116-
async for chunk in self._response.aiter_text(chunk_size=chunk_size):
117-
yield chunk
145+
async with self._acatch_and_close():
146+
async for chunk in self._response.aiter_text(chunk_size=chunk_size):
147+
yield chunk
118148

119149
async def aiter_lines(self) -> AsyncIterator[str]:
120-
async for line in self._response.aiter_lines():
121-
yield line
150+
async with self._acatch_and_close():
151+
async for line in self._response.aiter_lines():
152+
yield line
122153

123154
async def aiter_raw(self, chunk_size: Optional[int] = None) -> AsyncIterator[bytes]:
124-
async for chunk in self._response.aiter_raw(chunk_size=chunk_size):
125-
yield chunk
155+
async with self._acatch_and_close():
156+
async for chunk in self._response.aiter_raw(chunk_size=chunk_size):
157+
yield chunk

tests/test_rest/test_call.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from functools import partial
22

3-
from httpx import ResponseNotRead
43
import pytest
54

65
from githubkit import GitHub
@@ -65,31 +64,6 @@ async def test_async_call_with_raw_body(g: GitHub):
6564
assert isinstance(resp.text, str)
6665

6766

68-
def test_call_streaming(g: GitHub):
69-
resp = g.rest.repos.download_tarball_archive(OWNER, REPO, REF, stream=True)
70-
71-
with pytest.raises(ResponseNotRead):
72-
resp.content
73-
74-
for chunk in resp.iter_bytes():
75-
assert isinstance(chunk, bytes)
76-
assert len(chunk) > 0
77-
78-
79-
@pytest.mark.anyio
80-
async def test_async_call_streaming(g: GitHub):
81-
resp = await g.rest.repos.async_download_tarball_archive(
82-
OWNER, REPO, REF, stream=True
83-
)
84-
85-
with pytest.raises(ResponseNotRead):
86-
resp.content
87-
88-
async for chunk in resp.aiter_bytes():
89-
assert isinstance(chunk, bytes)
90-
assert len(chunk) > 0
91-
92-
9367
def test_paginate(g: GitHub):
9468
paginator = g.rest.paginate(
9569
g.rest.issues.list_for_repo, owner=OWNER, repo=REPO, state="all", per_page=50

0 commit comments

Comments
 (0)