diff --git a/dataclass_rest/rest.py b/dataclass_rest/rest.py index 9394811..53f1f32 100644 --- a/dataclass_rest/rest.py +++ b/dataclass_rest/rest.py @@ -1,3 +1,4 @@ +import inspect from functools import partial from typing import Any, Dict, Optional, Callable @@ -6,30 +7,48 @@ from .parse_func import parse_func, DEFAULT_BODY_PARAM -def rest( - url_template: str, - *, - method: str, - body_name: str = DEFAULT_BODY_PARAM, - additional_params: Optional[Dict[str, Any]] = None, - method_class: Optional[Callable[..., BoundMethod]] = None, - send_json: bool = True, -) -> Callable[[Callable], Method]: - if additional_params is None: - additional_params = {} +class rest: + def __init__( + self, + url_template: str, + *, + method: str, + body_name: str = DEFAULT_BODY_PARAM, + additional_params: Optional[Dict[str, Any]] = None, + method_class: Optional[Callable[..., BoundMethod]] = None, + send_json: bool = True, + ): + if additional_params is None: + additional_params = {} + self.url_template = url_template + self.method = method + self.body_name = body_name + self.additional_params = additional_params + self.method_class = method_class + self.send_json = send_json - def dec(func: Callable) -> Method: + def __set_name__(self, owner, name): + for cls in inspect.getmro(owner): + if cls is owner: + continue + func = getattr(cls, name, None) + if not func: + continue + method = self(func) + setattr(owner, name, method) + method.__set_name__(owner, name) + return + + def __call__(self, func: Callable) -> Method: method_spec = parse_func( func=func, - body_param_name=body_name, - url_template=url_template, - method=method, - additional_params=additional_params, - is_json_request=send_json, + body_param_name=self.body_name, + url_template=self.url_template, + method=self.method, + additional_params=self.additional_params, + is_json_request=self.send_json, ) - return Method(method_spec, method_class=method_class) - - return dec + return Method(method_spec, method_class=self.method_class) get = partial(rest, method="GET") diff --git a/examples/with_protocol.py b/examples/with_protocol.py new file mode 100644 index 0000000..cd1358a --- /dev/null +++ b/examples/with_protocol.py @@ -0,0 +1,46 @@ +import logging +from dataclasses import dataclass +from typing import Optional, List, Protocol + +from adaptix import Retort, name_mapping, NameStyle + +from dataclass_rest import get +from dataclass_rest.http.requests import RequestsClient + + +@dataclass +class Todo: + id: int + user_id: int + title: str + completed: bool + + +class Client(Protocol): + def get_todo(self, id: str) -> Todo: + pass + + def list_todos(self, user_id: Optional[int]) -> List[Todo]: + pass + + +class RealClient(RequestsClient, Client): + def __init__(self): + super().__init__( + base_url="https://jsonplaceholder.typicode.com/", + ) + + def _init_request_body_factory(self) -> Retort: + return Retort(recipe=[ + name_mapping(name_style=NameStyle.CAMEL), + ]) + + get_todo = get("todos/{id}") + list_todos = get("todos") + + +logging.basicConfig(level=logging.INFO) +client = RealClient() + +print(client.list_todos(user_id=1)) +print(client.get_todo(id="1"))