diff --git a/lunarapi/api.py b/lunarapi/api.py index dea1a37..0ff36b7 100644 --- a/lunarapi/api.py +++ b/lunarapi/api.py @@ -1,25 +1,29 @@ from __future__ import annotations +from typing import TYPE_CHECKING, Any, Callable, Dict, Generic, Literal, Type, TypeVar -from typing import Any, Callable, Generic, ParamSpec, Type, TypeVar - -from aiohttp import ClientSession from yarl import URL -from . import models +if TYPE_CHECKING: + from typing_extensions import ParamSpec + from aiohttp import ClientSession + from .models import BaseModel + +if TYPE_CHECKING: + P = ParamSpec('P') +else: + P = TypeVar('P') __all__ = "Client", "Endpoint", "ep" BASE = "https://api.lunardev.group/" -T = TypeVar("T", bound=models.BaseModel) -P = ParamSpec("P") +ModalT = TypeVar("ModalT", bound="BaseModel") - -class Endpoint(Generic[T, P]): - def __init__(self, route: str, *, model: Type[T], fn: Callable[P, Any]): - self.url = URL(BASE + route) - self.model = model - self.fn = fn +class Endpoint(Generic[ModalT, P]): + def __init__(self, route: str, *, model: Type[ModalT], fn: Callable[P, Any]) -> None: + self.url: URL = URL(BASE + route) + self.model: Type[ModalT] = model + self.fn: Callable[P, Any] = fn async def request( self, @@ -27,26 +31,25 @@ async def request( headers: dict[str, str], *args: P.args, **kwargs: P.kwargs, - ) -> T: + ) -> ModalT: url = self.url.with_query(**kwargs) if kwargs else self.url resp = await session.get(url, headers=headers) return self.model(resp) - -def ep(route: str, model: Type[T]): - def inner(fn: Callable[P, Any]) -> Endpoint[T, P]: +def ep(route: str, model: Type[ModalT]) -> Callable[[Callable[P, Any]], Endpoint[ModalT, P]]: + def inner(fn: Callable[P, Any]) -> Endpoint[ModalT, P]: return Endpoint(route, model=model, fn=fn) return inner class Client: - def __init__(self, *, session: ClientSession, token: str): - self._session = session - self.__headers = {"Authorization": f"Bearer {token}"} + def __init__(self, *, session: ClientSession, token: str) -> None: + self._session: ClientSession = session + self.__headers: Dict[Literal["Authorization"], str] = {"Authorization": f"Bearer {token}"} async def request( - self, endpoint: Endpoint[T, P], *args: P.args, **kwargs: P.kwargs - ): + self, endpoint: Endpoint[ModalT, P], *args: P.args, **kwargs: P.kwargs + ) -> ModalT: res = await endpoint.request(self._session, self.__headers, *args, **kwargs) return res diff --git a/lunarapi/endpoints.py b/lunarapi/endpoints.py index 7edfcde..7bf6251 100644 --- a/lunarapi/endpoints.py +++ b/lunarapi/endpoints.py @@ -1,10 +1,10 @@ -from typing import Literal, Optional +from typing import Any, Literal, Optional from . import models from .api import Endpoint, ep @ep("gen/welcome", models.Image) -def generate_welcome(avatar: str, username: str, members: str, dev: any): +def generate_welcome(avatar: str, username: str, members: str, dev: Any): ... @ep("gen/achievement", models.Image) diff --git a/lunarapi/models.py b/lunarapi/models.py index 5f09a8d..09f85b0 100644 --- a/lunarapi/models.py +++ b/lunarapi/models.py @@ -1,23 +1,35 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Any + from io import BytesIO import aiohttp +if TYPE_CHECKING: + from typing import Callable, Protocol, Union + + from aiohttp import ClientResponse + + class DiscordT(Protocol): + File: Callable[[Union[BytesIO, Any], str], Any] +else: + DiscordT: Any class BaseModel: - def __init__(self, response: aiohttp.ClientResponse): - self.response = response + def __init__(self, response: ClientResponse) -> None: + self.response: ClientResponse = response class Image(BaseModel): - async def bytes(self): + async def bytes(self) -> bytes: return await self.response.read() - async def file(self, discord): # sourcery skip: avoid-builtin-shadow + async def file(self, module: DiscordT): # sourcery skip: avoid-builtin-shadow b = await self.response.read() - return discord.File(BytesIO(b), "image.png") + return module.File(BytesIO(b), "image.png") - async def save(self, fp: str): + async def save(self, fp: str) -> None: with open(fp, "wb") as f: f.write(await self.bytes()) class JSON(BaseModel): - async def to_dict(self): + async def to_dict(self) -> dict[Any, Any]: return await self.response.json() diff --git a/pyproject.toml b/pyproject.toml index de8d691..efbb6b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,10 +9,11 @@ documentation = "https://docs.lunardev.group/" keywords = ["discord", "api", "wrapper"] [tool.poetry.dependencies] -python = "^3.10" +python = "^3.8" aiohttp = ">=3.6.0,<3.8.0" python-dotenv = "^0.20.0" Pillow = "^9.2.0" +typing-extensions = {version = ">=4.1.0,<4.3.0", python = ">=3.8,<3.9"} [tool.poetry.dev-dependencies] pytest = "^5.2"