diff --git a/topgg/autopost.py b/topgg/autopost.py index c2ffb3a..aae19ea 100644 --- a/topgg/autopost.py +++ b/topgg/autopost.py @@ -54,7 +54,7 @@ class AutoPoster: An instance of DBLClient. """ - __slots__ = ( + __slots__: t.Tuple[str, ...] = ( "_error", "_success", "_interval", diff --git a/topgg/client.py b/topgg/client.py index 919e6ed..9622018 100644 --- a/topgg/client.py +++ b/topgg/client.py @@ -53,7 +53,8 @@ class DBLClient(DataContainerMixin): Arbitrary kwargs to be passed to :class:`aiohttp.ClientSession` if session was not provided. """ - __slots__ = ("http", "bot_id", "_token", "_is_closed", "_autopost") + __slots__: t.Tuple[str, ...] = ("http", "bot_id", "_token", "_is_closed", "_autopost") + http: HTTPClient def __init__( diff --git a/topgg/data.py b/topgg/data.py index abceaa6..639c8d2 100644 --- a/topgg/data.py +++ b/topgg/data.py @@ -20,7 +20,10 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -__all__ = ("data", "DataContainerMixin",) +__all__ = ( + "data", + "DataContainerMixin", +) import inspect import typing as t @@ -61,7 +64,7 @@ def get_stats(client: Client = topgg.data(Client)): class Data(t.Generic[T]): - __slots__ = ("type",) + __slots__: t.Tuple[str, ...] = ("type",) def __init__(self, type_: t.Type[T]) -> None: self.type: t.Type[T] = type_ @@ -75,7 +78,7 @@ class DataContainerMixin: as arguments in your functions. """ - __slots__ = ("_data",) + __slots__: t.Tuple[str, ...] = ("_data",) def __init__(self) -> None: self._data: t.Dict[t.Type, t.Any] = {type(self): self} diff --git a/topgg/http.py b/topgg/http.py index d52dc8d..7c09d5d 100644 --- a/topgg/http.py +++ b/topgg/http.py @@ -29,7 +29,7 @@ import sys import warnings from datetime import datetime -from typing import Any, Coroutine, Dict, Iterable, List, Optional, Sequence, Union, cast +from typing import Any, Coroutine, Dict, Iterable, List, Optional, Sequence, Union, cast, Tuple import aiohttp from aiohttp import ClientResponse @@ -49,6 +49,9 @@ async def _json_or_text( return text +BASE = "https://top.gg/api" + + class HTTPClient: """Represents an HTTP client sending HTTP requests to the Top.gg API. @@ -65,6 +68,16 @@ class HTTPClient: Arbitrary kwargs to be passed to :class:`aiohttp.ClientSession`. """ + __slots__: Tuple[str, ...] = ( + "token", + "_own_session", + "session", + "global_rate_limiter", + "bot_rate_limiter", + "rate_limiters", + "user_agent", + ) + def __init__( self, token: str, @@ -72,7 +85,6 @@ def __init__( session: Optional[aiohttp.ClientSession] = None, **kwargs: Any, ) -> None: - self.BASE = "https://top.gg/api" self.token = token self._own_session = session is None self.session: aiohttp.ClientSession = session or aiohttp.ClientSession(**kwargs) @@ -87,7 +99,7 @@ def __init__( async def request(self, method: str, endpoint: str, **kwargs: Any) -> dict: """Handles requests to the API.""" rate_limiters = self.rate_limiters if endpoint.startswith("/bots") else self.global_rate_limiter - url = f"{self.BASE}{endpoint}" + url = BASE + endpoint if not self.token: raise errors.UnauthorizedDetected("Top.gg API token not provided") diff --git a/topgg/ratelimiter.py b/topgg/ratelimiter.py index 77b7a08..b95e5e9 100644 --- a/topgg/ratelimiter.py +++ b/topgg/ratelimiter.py @@ -24,7 +24,7 @@ import collections from datetime import datetime from types import TracebackType -from typing import Any, Awaitable, Callable, List, Optional, Type +from typing import Any, Awaitable, Callable, List, Optional, Type, Tuple class AsyncRateLimiter: @@ -32,6 +32,8 @@ class AsyncRateLimiter: Provides rate limiting for an operation with a configurable number of requests for a time period. """ + __slots__: Tuple[str, ...] = ("__lock", "callback", "max_calls", "period", "calls") + __lock: asyncio.Lock callback: Optional[Callable[[float], Awaitable[Any]]] max_calls: int @@ -85,6 +87,8 @@ def _timespan(self) -> float: class AsyncRateLimiterManager: + __slots__: Tuple[str, ...] = ("rate_limiters",) + rate_limiters: List[AsyncRateLimiter] def __init__(self, rate_limiters: List[AsyncRateLimiter]): diff --git a/topgg/types.py b/topgg/types.py index 84d9191..746a109 100644 --- a/topgg/types.py +++ b/topgg/types.py @@ -140,6 +140,8 @@ class WidgetOptions(DataDict[str, t.Any]): """Model that represents widget options that are passed to Top.gg widget URL generated via :meth:`DBLClient.generate_widget`.""" + __slots__: t.Tuple[str, ...] = () + id: t.Optional[int] """ID of a bot to generate the widget for. Must resolve to an ID of a listed bot when converted to a string.""" colors: Colors @@ -200,6 +202,8 @@ class BotData(DataDict[str, t.Any]): """Model that contains information about a listed bot on top.gg. The data this model contains can be found `here `__.""" + __slots__: t.Tuple[str, ...] = () + id: int """The ID of the bot.""" @@ -270,6 +274,8 @@ def __init__(self, **kwargs: t.Any): class BotStatsData(DataDict[str, t.Any]): """Model that contains information about a listed bot's guild and shard count.""" + __slots__: t.Tuple[str, ...] = () + server_count: t.Optional[int] """The amount of servers the bot is in.""" shards: t.List[int] @@ -284,6 +290,8 @@ def __init__(self, **kwargs: t.Any): class BriefUserData(DataDict[str, t.Any]): """Model that contains brief information about a Top.gg user.""" + __slots__: t.Tuple[str, ...] = () + id: int """The Discord ID of the user.""" username: str @@ -300,6 +308,8 @@ def __init__(self, **kwargs: t.Any): class SocialData(DataDict[str, str]): """Model that contains social information about a top.gg user.""" + __slots__: t.Tuple[str, ...] = () + youtube: str """The YouTube channel ID of the user.""" reddit: str @@ -316,6 +326,8 @@ class UserData(DataDict[str, t.Any]): """Model that contains information about a top.gg user. The data this model contains can be found `here `__.""" + __slots__: t.Tuple[str, ...] = () + id: int """The ID of the user.""" @@ -353,6 +365,8 @@ def __init__(self, **kwargs: t.Any): class VoteDataDict(DataDict[str, t.Any]): """Base model that represents received information from Top.gg via webhooks.""" + __slots__: t.Tuple[str, ...] = () + type: str """Type of the action (``upvote`` or ``test``).""" user: int @@ -367,6 +381,8 @@ def __init__(self, **kwargs: t.Any): class BotVoteData(VoteDataDict): """Model that contains information about a bot vote.""" + __slots__: t.Tuple[str, ...] = () + bot: int """ID of the bot the user voted for.""" is_weekend: bool @@ -376,6 +392,8 @@ class BotVoteData(VoteDataDict): class GuildVoteData(VoteDataDict): """Model that contains information about a guild vote.""" + __slots__: t.Tuple[str, ...] = () + guild: int """ID of the guild the user voted for.""" diff --git a/topgg/webhook.py b/topgg/webhook.py index 1e95fba..0b85bd9 100644 --- a/topgg/webhook.py +++ b/topgg/webhook.py @@ -50,6 +50,8 @@ class WebhookType(enum.Enum): """An enum that represents the type of an endpoint.""" + __slots__: t.Tuple[str, ...] = () + BOT = enum.auto() """Marks the endpoint as a bot webhook.""" @@ -62,10 +64,11 @@ class WebhookManager(DataContainerMixin): A class for managing Top.gg webhooks. """ + __slots__: t.Tuple[str, ...] = ("__app", "_webserver", "_is_running") + __app: web.Application _webserver: web.TCPSite - _is_closed: bool - __slots__ = ("__app", "_webserver", "_is_running") + _is_running: bool def __init__(self) -> None: super().__init__() @@ -173,7 +176,7 @@ class WebhookEndpoint: A helper class to setup webhook endpoint. """ - __slots__ = ("_callback", "_auth", "_route", "_type") + __slots__: t.Tuple[str, ...] = ("_callback", "_auth", "_route", "_type") def __init__(self) -> None: self._auth = "" @@ -298,7 +301,7 @@ def on_vote(vote_data: topgg.BotVoteData): ... endpoint.add_to_manager() """ - __slots__ = ("manager",) + __slots__: t.Tuple[str, ...] = ("manager",) def __init__(self, manager: WebhookManager): super().__init__()