Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/dataclass_rest/boundmethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .exceptions import ClientLibraryError, MalformedResponse
from .http_request import File, HttpRequest
from .methodspec import MethodSpec
from .response_type import ResponseType

logger = getLogger(__name__)

Expand All @@ -18,11 +19,13 @@ def __init__(
method_spec: MethodSpec,
client: ClientProtocol,
on_error: Optional[Callable[[Any], Any]],
response_type: ResponseType,
):
self.name = name
self.method_spec = method_spec
self.client = client
self.on_error = on_error or self._on_error_default
self.response_type = response_type

def _apply_args(self, *args, **kwargs) -> Dict:
return getcallargs(
Expand Down
12 changes: 11 additions & 1 deletion src/dataclass_rest/http/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ServerError,
)
from dataclass_rest.http_request import HttpRequest
from dataclass_rest.response_type import ResponseType


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

async def _response_body(self, response: ClientResponse) -> Any:
try:
return await response.json()
if self.response_type == ResponseType.JSON:
return await response.json()
elif self.response_type == ResponseType.TEXT:
return await response.text()
elif self.response_type == ResponseType.BYTES:
return await response.read()
elif self.response_type == ResponseType.NO_CONTENT:
return None
else:
raise ValueError("Unknown expected response type")
except AioHttpClientError as e:
raise ClientLibraryError from e
except JSONDecodeError as e:
Expand Down
12 changes: 11 additions & 1 deletion src/dataclass_rest/http/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ServerError,
)
from dataclass_rest.http_request import File, HttpRequest
from dataclass_rest.response_type import ResponseType


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

def _response_body(self, response: Response) -> Any:
try:
return response.json()
if self.response_type == ResponseType.JSON:
return response.json()
elif self.response_type == ResponseType.TEXT:
return response.text
elif self.response_type == ResponseType.BYTES:
return response.content
elif self.response_type == ResponseType.NO_CONTENT:
return None
else:
raise ValueError("Unknown expected response type")
except RequestException as e:
raise ClientLibraryError from e
except JSONDecodeError as e:
Expand Down
4 changes: 4 additions & 0 deletions src/dataclass_rest/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
from .boundmethod import BoundMethod
from .client_protocol import ClientProtocol
from .methodspec import MethodSpec
from .response_type import ResponseType


class Method:
def __init__(
self,
method_spec: MethodSpec,
response_type: ResponseType,
method_class: Optional[Callable[..., BoundMethod]] = None,
):
self.name = method_spec.func.__name__
self.method_spec = method_spec
self.response_type = response_type
self.method_class = method_class
self._on_error = None

Expand Down Expand Up @@ -42,6 +45,7 @@ def __get__(
method_spec=self.method_spec,
client=instance,
on_error=self._on_error,
response_type=self.response_type,
)

def on_error(self, func) -> "Method":
Expand Down
10 changes: 10 additions & 0 deletions src/dataclass_rest/response_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from enum import Enum
from typing import Literal

class ResponseType(Enum):
JSON = "json"
TEXT = "text"
BYTES = "bytes"
NO_CONTENT = "no_content"

ResponseTypeLiteral = Literal["json", "text", "bytes", "no_content"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need this literal?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's more convenient and faster, we remove one useless import

11 changes: 10 additions & 1 deletion src/dataclass_rest/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .boundmethod import BoundMethod
from .method import Method
from .parse_func import DEFAULT_BODY_PARAM, UrlTemplate, parse_func
from .response_type import ResponseTypeLiteral, ResponseType

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

Expand All @@ -15,9 +16,17 @@ def rest(
additional_params: Optional[Dict[str, Any]] = None,
method_class: Optional[Callable[..., BoundMethod]] = None,
send_json: bool = True,
response_type: ResponseTypeLiteral = "json",
) -> Callable[[Callable], Method]:
if additional_params is None:
additional_params = {}
try:
response_type_enum = ResponseType(response_type)
except ValueError:
raise TypeError(
f"'{response_type}' is not a valid response type. "
f"Use one of {list(ResponseTypeLiteral.__args__)}"
)

def dec(func: Callable) -> Method:
method_spec = parse_func(
Expand All @@ -28,7 +37,7 @@ def dec(func: Callable) -> Method:
additional_params=additional_params,
is_json_request=send_json,
)
return Method(method_spec, method_class=method_class)
return Method(method_spec, method_class=method_class, response_type=response_type_enum)

return dec

Expand Down