Skip to content

Commit 18fc5ec

Browse files
committed
allow specifying expected response type
1 parent 204bbd1 commit 18fc5ec

File tree

6 files changed

+49
-3
lines changed

6 files changed

+49
-3
lines changed

src/dataclass_rest/boundmethod.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .exceptions import ClientLibraryError, MalformedResponse
88
from .http_request import File, HttpRequest
99
from .methodspec import MethodSpec
10+
from .response_type import ResponseType
1011

1112
logger = getLogger(__name__)
1213

@@ -18,11 +19,13 @@ def __init__(
1819
method_spec: MethodSpec,
1920
client: ClientProtocol,
2021
on_error: Optional[Callable[[Any], Any]],
22+
response_type: ResponseType,
2123
):
2224
self.name = name
2325
self.method_spec = method_spec
2426
self.client = client
2527
self.on_error = on_error or self._on_error_default
28+
self.response_type = response_type
2629

2730
def _apply_args(self, *args, **kwargs) -> Dict:
2831
return getcallargs(

src/dataclass_rest/http/aiohttp.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
ServerError,
2121
)
2222
from dataclass_rest.http_request import HttpRequest
23+
from dataclass_rest.response_type import ResponseType
2324

2425

2526
class AiohttpMethod(AsyncMethod):
@@ -34,7 +35,16 @@ async def _release_raw_response(self, response: ClientResponse) -> None:
3435

3536
async def _response_body(self, response: ClientResponse) -> Any:
3637
try:
37-
return await response.json()
38+
if self.response_type == ResponseType.JSON:
39+
return await response.json()
40+
elif self.response_type == ResponseType.TEXT:
41+
return await response.text()
42+
elif self.response_type == ResponseType.BYTES:
43+
return await response.read()
44+
elif self.response_type == ResponseType.NO_CONTENT:
45+
return None
46+
else:
47+
raise ValueError("Unknown expected response type")
3848
except AioHttpClientError as e:
3949
raise ClientLibraryError from e
4050
except JSONDecodeError as e:

src/dataclass_rest/http/requests.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
ServerError,
1414
)
1515
from dataclass_rest.http_request import File, HttpRequest
16+
from dataclass_rest.response_type import ResponseType
1617

1718

1819
class RequestsMethod(SyncMethod):
@@ -27,7 +28,16 @@ def _response_ok(self, response: Response) -> bool:
2728

2829
def _response_body(self, response: Response) -> Any:
2930
try:
30-
return response.json()
31+
if self.response_type == ResponseType.JSON:
32+
return response.json()
33+
elif self.response_type == ResponseType.TEXT:
34+
return response.text
35+
elif self.response_type == ResponseType.BYTES:
36+
return response.content
37+
elif self.response_type == ResponseType.NO_CONTENT:
38+
return None
39+
else:
40+
raise ValueError("Unknown expected response type")
3141
except RequestException as e:
3242
raise ClientLibraryError from e
3343
except JSONDecodeError as e:

src/dataclass_rest/method.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
from .boundmethod import BoundMethod
44
from .client_protocol import ClientProtocol
55
from .methodspec import MethodSpec
6+
from .response_type import ResponseType
67

78

89
class Method:
910
def __init__(
1011
self,
1112
method_spec: MethodSpec,
13+
response_type: ResponseType,
1214
method_class: Optional[Callable[..., BoundMethod]] = None,
1315
):
1416
self.name = method_spec.func.__name__
1517
self.method_spec = method_spec
18+
self.response_type = response_type
1619
self.method_class = method_class
1720
self._on_error = None
1821

@@ -42,6 +45,7 @@ def __get__(
4245
method_spec=self.method_spec,
4346
client=instance,
4447
on_error=self._on_error,
48+
response_type=self.response_type,
4549
)
4650

4751
def on_error(self, func) -> "Method":
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from enum import Enum
2+
from typing import Literal
3+
4+
class ResponseType(Enum):
5+
JSON = "json"
6+
TEXT = "text"
7+
BYTES = "bytes"
8+
NO_CONTENT = "no_content"
9+
10+
ResponseTypeLiteral = Literal["json", "text", "bytes", "no_content"]

src/dataclass_rest/rest.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .boundmethod import BoundMethod
44
from .method import Method
55
from .parse_func import DEFAULT_BODY_PARAM, UrlTemplate, parse_func
6+
from .response_type import ResponseTypeLiteral, ResponseType
67

78
_Func = TypeVar("_Func", bound=Callable[..., Any])
89

@@ -15,9 +16,17 @@ def rest(
1516
additional_params: Optional[Dict[str, Any]] = None,
1617
method_class: Optional[Callable[..., BoundMethod]] = None,
1718
send_json: bool = True,
19+
response_type: Optional[ResponseTypeLiteral] = "json",
1820
) -> Callable[[Callable], Method]:
1921
if additional_params is None:
2022
additional_params = {}
23+
try:
24+
response_type_enum = ResponseType(response_type)
25+
except ValueError:
26+
raise TypeError(
27+
f"'{response_type}' is not a valid response type. "
28+
f"Use one of {list(ResponseTypeLiteral.__args__)}"
29+
)
2130

2231
def dec(func: Callable) -> Method:
2332
method_spec = parse_func(
@@ -28,7 +37,7 @@ def dec(func: Callable) -> Method:
2837
additional_params=additional_params,
2938
is_json_request=send_json,
3039
)
31-
return Method(method_spec, method_class=method_class)
40+
return Method(method_spec, method_class=method_class, response_type=response_type_enum)
3241

3342
return dec
3443

0 commit comments

Comments
 (0)