diff --git a/discord/http.py b/discord/http.py index 1419acb65..c35254519 100644 --- a/discord/http.py +++ b/discord/http.py @@ -28,7 +28,21 @@ import asyncio import json import logging import sys -from typing import Any, Coroutine, List, Optional, TYPE_CHECKING, TypeVar +from typing import ( + Any, + ClassVar, + Coroutine, + Dict, + Final, + Iterable, + List, + Optional, + Sequence, + TYPE_CHECKING, + Tuple, + Type, + TypeVar, +) from urllib.parse import quote as _uriquote import weakref @@ -41,20 +55,45 @@ from . import __version__, utils log = logging.getLogger(__name__) if TYPE_CHECKING: + from .file import File + from .enums import ( + AuditLogAction, + InteractionResponseType, + ) + from .types import ( + appinfo, + audit_log, + channel, + components, + emoji, + embed, + guild, + integration, interactions, invite, + member, + message, + template, + role, + user, + webhook, channel, widget, threads, + voice, ) - from .types.snowflake import Snowflake + from .types.snowflake import Snowflake, SnowflakeList + + from types import TracebackType T = TypeVar('T') + BE = TypeVar('BE', bound=BaseException) + MU = TypeVar('MU', bound='MaybeUnlock') Response = Coroutine[Any, Any, T] -async def json_or_text(response): +async def json_or_text(response: aiohttp.ClientResponse) -> Any: text = await response.text(encoding='utf-8') try: if response.headers['content-type'] == 'application/json': @@ -67,79 +106,90 @@ async def json_or_text(response): class Route: - BASE = 'https://discord.com/api/v8' + BASE: ClassVar[str] = 'https://discord.com/api/v8' - def __init__(self, method, path, **parameters): - self.path = path - self.method = method + def __init__(self, method: str, path: str, **parameters: Any) -> None: + self.path: str = path + self.method: str = method url = self.BASE + self.path if parameters: - self.url = url.format_map({k: _uriquote(v) if isinstance(v, str) else v for k, v in parameters.items()}) - else: - self.url = url + url = url.format_map({k: _uriquote(v) if isinstance(v, str) else v for k, v in parameters.items()}) + self.url: str = url # major parameters: - self.channel_id = parameters.get('channel_id') - self.guild_id = parameters.get('guild_id') - self.webhook_id = parameters.get('webhook_id') - self.webhook_token = parameters.get('webhook_token') + self.channel_id: Optional[Snowflake] = parameters.get('channel_id') + self.guild_id: Optional[Snowflake] = parameters.get('guild_id') + self.webhook_id: Optional[Snowflake] = parameters.get('webhook_id') + self.webhook_token: Optional[str] = parameters.get('webhook_token') @property - def bucket(self): + def bucket(self) -> str: # the bucket is just method + path w/ major parameters return f'{self.channel_id}:{self.guild_id}:{self.path}' class MaybeUnlock: - def __init__(self, lock): - self.lock = lock - self._unlock = True + def __init__(self, lock: asyncio.Lock) -> None: + self.lock: asyncio.Lock = lock + self._unlock: bool = True - def __enter__(self): + def __enter__(self: MU) -> MU: return self - def defer(self): + def defer(self) -> None: self._unlock = False - def __exit__(self, type, value, traceback): + def __exit__(self, + exc_type: Optional[Type[BE]], + exc: Optional[BE], + traceback: Optional[TracebackType], + ) -> None: if self._unlock: self.lock.release() # For some reason, the Discord voice websocket expects this header to be # completely lowercase while aiohttp respects spec and does it as case-insensitive -aiohttp.hdrs.WEBSOCKET = 'websocket' +aiohttp.hdrs.WEBSOCKET = 'websocket' #type: ignore class HTTPClient: """Represents an HTTP client sending HTTP requests to the Discord API.""" - SUCCESS_LOG = '{method} {url} has received {text}' - REQUEST_LOG = '{method} {url} with {json} has returned {status}' + SUCCESS_LOG: Final[ClassVar[str]] = '{method} {url} has received {text}' + REQUEST_LOG: Final[ClassVar[str]] = '{method} {url} with {json} has returned {status}' - def __init__(self, connector=None, *, proxy=None, proxy_auth=None, loop=None, unsync_clock=True): - self.loop = asyncio.get_event_loop() if loop is None else loop + def __init__( + self, + connector: Optional[aiohttp.BaseConnector] = None, + *, + proxy: Optional[str] = None, + proxy_auth: Optional[aiohttp.BasicAuth] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + unsync_clock: bool = True + ) -> None: + self.loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() if loop is None else loop self.connector = connector - self.__session = None # filled in static_login - self._locks = weakref.WeakValueDictionary() - self._global_over = asyncio.Event() + self.__session: Optional[aiohttp.ClientSession] = None # filled in static_login + self._locks: weakref.WeakValueDictionary = weakref.WeakValueDictionary() + self._global_over: asyncio.Event = asyncio.Event() self._global_over.set() - self.token = None - self.bot_token = False - self.proxy = proxy - self.proxy_auth = proxy_auth - self.use_clock = not unsync_clock + self.token: Optional[str] = None + self.bot_token: bool = False + self.proxy: Optional[str] = proxy + self.proxy_auth: Optional[aiohttp.BasicAuth] = proxy_auth + self.use_clock: bool = not unsync_clock user_agent = 'DiscordBot (https://github.com/Rapptz/discord.py {0}) Python/{1[0]}.{1[1]} aiohttp/{2}' - self.user_agent = user_agent.format(__version__, sys.version_info, aiohttp.__version__) + self.user_agent: str = user_agent.format(__version__, sys.version_info, aiohttp.__version__) - def recreate(self): + def recreate(self) -> None: if self.__session.closed: self.__session = aiohttp.ClientSession( connector=self.connector, ws_response_class=DiscordClientWebSocketResponse ) - async def ws_connect(self, url, *, compress=0): + async def ws_connect(self, url: str, *, compress: int = 0) -> Any: kwargs = { 'proxy_auth': self.proxy_auth, 'proxy': self.proxy, @@ -154,7 +204,14 @@ class HTTPClient: return await self.__session.ws_connect(url, **kwargs) - async def request(self, route, *, files=None, form=None, **kwargs) -> Any: + async def request( + self, + route: Route, + *, + files: Optional[Sequence[File]] = None, + form: Optional[Iterable[Dict[str, Any]]] = None, + **kwargs: Any + ) -> Any: bucket = route.bucket method = route.method url = route.url @@ -289,7 +346,7 @@ class HTTPClient: raise HTTPException(r, data) - async def get_from_cdn(self, url): + async def get_from_cdn(self, url: str) -> bytes: async with self.__session.get(url) as resp: if resp.status == 200: return await resp.read() @@ -302,13 +359,13 @@ class HTTPClient: # state management - async def close(self): + async def close(self) -> None: if self.__session: await self.__session.close() # login management - async def static_login(self, token): + async def static_login(self, token: str) -> user.User: # Necessary to get aiohttp to stop complaining about session creation self.__session = aiohttp.ClientSession(connector=self.connector, ws_response_class=DiscordClientWebSocketResponse) old_token = self.token @@ -324,24 +381,24 @@ class HTTPClient: return data - def logout(self): + def logout(self) -> Response[None]: return self.request(Route('POST', '/auth/logout')) # Group functionality - def start_group(self, user_id, recipients): + def start_group(self, user_id: Snowflake, recipients: List[int]) -> Response[channel.GroupDMChannel]: payload = { 'recipients': recipients, } return self.request(Route('POST', '/users/{user_id}/channels', user_id=user_id), json=payload) - def leave_group(self, channel_id): + def leave_group(self, channel_id) -> Response[None]: return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id)) # Message management - def start_private_message(self, user_id): + def start_private_message(self, user_id: Snowflake) -> Response[channel.DMChannel]: payload = { 'recipient_id': user_id, } @@ -350,16 +407,16 @@ class HTTPClient: def send_message( self, - channel_id, - content, + channel_id: Snowflake, + content: str, *, - tts=False, - embed=None, - nonce=None, - allowed_mentions=None, - message_reference=None, - components=None, - ): + tts: bool = False, + embed: Optional[embed.Embed] = None, + nonce: Optional[str] = None, + allowed_mentions: bool = None, + message_reference: bool = None, + components: Optional[List[components.Component]] = None, + ) -> Response[message.Message]: r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id) payload = {} @@ -386,26 +443,26 @@ class HTTPClient: return self.request(r, json=payload) - def send_typing(self, channel_id): + def send_typing(self, channel_id: Snowflake) -> Response[None]: return self.request(Route('POST', '/channels/{channel_id}/typing', channel_id=channel_id)) def send_multipart_helper( self, - route, + route: Route, *, - files, - content=None, - tts=False, - embed=None, - embeds=None, - nonce=None, - allowed_mentions=None, - message_reference=None, - components=None, - ): + files: Sequence[File], + content: Optional[str] = None, + tts: bool = False, + embed: Optional[embed.Embed] = None, + embeds: Iterable[Optional[embed.Embed]] = None, + nonce: Optional[str] = None, + allowed_mentions: Optional[message.AllowedMentions] = None, + message_reference: Optional[message.MessageReference] = None, + components: Optional[List[components.Component]] = None, + ) -> Response[message.Message]: form = [] - payload = {'tts': tts} + payload: Dict[str, Any] = {'tts': tts} if content: payload['content'] = content if embed: @@ -447,17 +504,17 @@ class HTTPClient: def send_files( self, - channel_id, + channel_id: Snowflake, *, - files, - content=None, - tts=False, - embed=None, - nonce=None, - allowed_mentions=None, - message_reference=None, - components=None, - ): + files: Sequence[File], + content: Optional[str] = None, + tts: bool = False, + embed: Optional[embed.Embed] = None, + nonce: Optional[str] = None, + allowed_mentions: Optional[message.AllowedMentions] = None, + message_reference: Optional[message.MessageReference] = None, + components: Optional[List[components.Component]] = None, + ) -> Response[message.Message]: r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id) return self.send_multipart_helper( r, @@ -471,11 +528,11 @@ class HTTPClient: components=components, ) - def delete_message(self, channel_id, message_id, *, reason=None): + def delete_message(self, channel_id: Snowflake, message_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route('DELETE', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id) return self.request(r, reason=reason) - def delete_messages(self, channel_id, message_ids, *, reason=None): + def delete_messages(self, channel_id: Snowflake, message_ids: SnowflakeList, *, reason: Optional[str] = None) -> Response[None]: r = Route('POST', '/channels/{channel_id}/messages/bulk-delete', channel_id=channel_id) payload = { 'messages': message_ids, @@ -483,11 +540,11 @@ class HTTPClient: return self.request(r, json=payload, reason=reason) - def edit_message(self, channel_id, message_id, **fields): + def edit_message(self, channel_id: Snowflake, message_id: Snowflake, **fields: Any) -> Response[message.Message]: r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id) return self.request(r, json=fields) - def add_reaction(self, channel_id, message_id, emoji): + def add_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]: r = Route( 'PUT', '/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me', @@ -497,7 +554,7 @@ class HTTPClient: ) return self.request(r) - def remove_reaction(self, channel_id, message_id, emoji, member_id): + def remove_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str, member_id: Snowflake) -> Response[None]: r = Route( 'DELETE', '/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/{member_id}', @@ -508,7 +565,7 @@ class HTTPClient: ) return self.request(r) - def remove_own_reaction(self, channel_id, message_id, emoji): + def remove_own_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]: r = Route( 'DELETE', '/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me', @@ -518,7 +575,14 @@ class HTTPClient: ) return self.request(r) - def get_reaction_users(self, channel_id, message_id, emoji, limit, after=None): + def get_reaction_users( + self, + channel_id: Snowflake, + message_id: Snowflake, + emoji: str, + limit: int, + after: Optional[Snowflake] = None, + ) -> Response[List[user.User]]: r = Route( 'GET', '/channels/{channel_id}/messages/{message_id}/reactions/{emoji}', @@ -534,7 +598,7 @@ class HTTPClient: params['after'] = after return self.request(r, params=params) - def clear_reactions(self, channel_id, message_id): + def clear_reactions(self, channel_id: Snowflake, message_id: Snowflake) -> Response[None]: r = Route( 'DELETE', '/channels/{channel_id}/messages/{message_id}/reactions', @@ -544,7 +608,7 @@ class HTTPClient: return self.request(r) - def clear_single_reaction(self, channel_id, message_id, emoji): + def clear_single_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]: r = Route( 'DELETE', '/channels/{channel_id}/messages/{message_id}/reactions/{emoji}', @@ -554,16 +618,23 @@ class HTTPClient: ) return self.request(r) - def get_message(self, channel_id, message_id): + def get_message(self, channel_id: Snowflake, message_id: Snowflake) -> Response[message.Message]: r = Route('GET', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id) return self.request(r) - def get_channel(self, channel_id): + def get_channel(self, channel_id: Snowflake) -> Response[channel.Channel]: r = Route('GET', '/channels/{channel_id}', channel_id=channel_id) return self.request(r) - def logs_from(self, channel_id, limit, before=None, after=None, around=None): - params = { + def logs_from( + self, + channel_id: Snowflake, + limit: int, + before: Optional[Snowflake] = None, + after: Optional[Snowflake] = None, + around: Optional[Snowflake] = None, + ) -> Response[List[message.Message]]: + params: Dict[str, Any] = { 'limit': limit, } @@ -576,7 +647,7 @@ class HTTPClient: return self.request(Route('GET', '/channels/{channel_id}/messages', channel_id=channel_id), params=params) - def publish_message(self, channel_id, message_id): + def publish_message(self, channel_id: Snowflake, message_id: Snowflake) -> Response[message.Message]: return self.request( Route( 'POST', @@ -586,7 +657,7 @@ class HTTPClient: ) ) - def pin_message(self, channel_id, message_id, reason=None): + def pin_message(self, channel_id: Snowflake, message_id: Snowflake, reason: Optional[str] = None) -> Response[None]: r = Route( 'PUT', '/channels/{channel_id}/pins/{message_id}', @@ -595,7 +666,7 @@ class HTTPClient: ) return self.request(r, reason=reason) - def unpin_message(self, channel_id, message_id, reason=None): + def unpin_message(self, channel_id: Snowflake, message_id: Snowflake, reason: Optional[str] = None) -> Response[None]: r = Route( 'DELETE', '/channels/{channel_id}/pins/{message_id}', @@ -604,12 +675,12 @@ class HTTPClient: ) return self.request(r, reason=reason) - def pins_from(self, channel_id): + def pins_from(self, channel_id: Snowflake) -> Response[List[message.Message]]: return self.request(Route('GET', '/channels/{channel_id}/pins', channel_id=channel_id)) # Member management - def kick(self, user_id, guild_id, reason=None): + def kick(self, user_id: Snowflake, guild_id: Snowflake, reason: Optional[str] = None) -> Response[None]: r = Route('DELETE', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) if reason: # thanks aiohttp @@ -617,7 +688,13 @@ class HTTPClient: return self.request(r) - def ban(self, user_id, guild_id, delete_message_days=1, reason=None): + def ban( + self, + user_id: Snowflake, + guild_id: Snowflake, + delete_message_days: int = 1, + reason: Optional[str] = None, + ) -> Response[None]: r = Route('PUT', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id) params = { 'delete_message_days': delete_message_days, @@ -629,11 +706,19 @@ class HTTPClient: return self.request(r, params=params) - def unban(self, user_id, guild_id, *, reason=None): + def unban(self, user_id: Snowflake, guild_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route('DELETE', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id) return self.request(r, reason=reason) - def guild_voice_state(self, user_id, guild_id, *, mute=None, deafen=None, reason=None): + def guild_voice_state( + self, + user_id: Snowflake, + guild_id: Snowflake, + *, + mute: Optional[bool] = None, + deafen: Optional[bool] = None, + reason: Optional[str] = None, + ) -> Response[member.Member]: r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) payload = {} if mute is not None: @@ -644,7 +729,7 @@ class HTTPClient: return self.request(r, json=payload, reason=reason) - def edit_profile(self, username, avatar): + def edit_profile(self, username: Optional[str], avatar: Optional[bytes]) -> Response[user.User]: payload = {} if avatar is not None: payload['avatar'] = avatar @@ -653,35 +738,61 @@ class HTTPClient: return self.request(Route('PATCH', '/users/@me'), json=payload) - def change_my_nickname(self, guild_id, nickname, *, reason=None): + def change_my_nickname( + self, + guild_id: Snowflake, + nickname: str, + *, + reason: Optional[str] = None, + ) -> Response[member.Nickname]: r = Route('PATCH', '/guilds/{guild_id}/members/@me/nick', guild_id=guild_id) payload = { 'nick': nickname, } return self.request(r, json=payload, reason=reason) - def change_nickname(self, guild_id, user_id, nickname, *, reason=None): + def change_nickname( + self, + guild_id: Snowflake, + user_id: Snowflake, + nickname: str, + *, + reason: Optional[str] = None, + ) -> Response[member.Member]: r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) payload = { 'nick': nickname, } return self.request(r, json=payload, reason=reason) - def edit_my_voice_state(self, guild_id, payload): + def edit_my_voice_state(self, guild_id: Snowflake, payload: voice.VoiceState) -> Response[None]: r = Route('PATCH', '/guilds/{guild_id}/voice-states/@me', guild_id=guild_id) return self.request(r, json=payload) - def edit_voice_state(self, guild_id, user_id, payload): + def edit_voice_state(self, guild_id: Snowflake, user_id: Snowflake, payload: voice.VoiceState) -> Response[None]: r = Route('PATCH', '/guilds/{guild_id}/voice-states/{user_id}', guild_id=guild_id, user_id=user_id) return self.request(r, json=payload) - def edit_member(self, guild_id, user_id, *, reason=None, **fields): + def edit_member( + self, + guild_id: Snowflake, + user_id: Snowflake, + *, + reason: Optional[str] = None, + **fields: Any, + ) -> Response[member.Member]: r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) return self.request(r, json=fields, reason=reason) # Channel management - def edit_channel(self, channel_id, *, reason=None, **options): + def edit_channel( + self, + channel_id: Snowflake, + *, + reason: Optional[str] = None, + **options: Any, + ) -> Response[channel.Channel]: r = Route('PATCH', '/channels/{channel_id}', channel_id=channel_id) valid_keys = ( 'name', @@ -703,11 +814,24 @@ class HTTPClient: payload = {k: v for k, v in options.items() if k in valid_keys} return self.request(r, reason=reason, json=payload) - def bulk_channel_update(self, guild_id, data, *, reason=None): + def bulk_channel_update( + self, + guild_id: Snowflake, + data: List[guild.ChannelPositionUpdate], + *, + reason: Optional[str] = None, + ) -> Response[None]: r = Route('PATCH', '/guilds/{guild_id}/channels', guild_id=guild_id) return self.request(r, json=data, reason=reason) - def create_channel(self, guild_id, channel_type, *, reason=None, **options): + def create_channel( + self, + guild_id: Snowflake, + channel_type: channel.ChannelType, + *, + reason: Optional[str] = None, + **options: Any, + ) -> Response[channel.GuildChannel]: payload = { 'type': channel_type, } @@ -730,19 +854,24 @@ class HTTPClient: return self.request(Route('POST', '/guilds/{guild_id}/channels', guild_id=guild_id), json=payload, reason=reason) - def delete_channel(self, channel_id, *, reason=None): + def delete_channel( + self, + channel_id: Snowflake, + *, + reason: Optional[str] = None, + ) -> Response[None]: return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id), reason=reason) # Thread management def start_public_thread( self, - channel_id: int, - message_id: int, + channel_id: Snowflake, + message_id: Snowflake, *, name: str, - auto_archive_duration: int, - type: int, + auto_archive_duration: threads.ThreadArchiveDuration, + type: threads.ThreadType, ) -> Response[threads.Thread]: payload = { 'name': name, @@ -757,11 +886,11 @@ class HTTPClient: def start_private_thread( self, - channel_id: int, + channel_id: Snowflake, *, name: str, - auto_archive_duration: int, - type: int, + auto_archive_duration: threads.ThreadArchiveDuration, + type: threads.ThreadType, ) -> Response[threads.Thread]: payload = { 'name': name, @@ -772,23 +901,23 @@ class HTTPClient: route = Route('POST', '/channels/{channel_id}/threads', channel_id=channel_id) return self.request(route, json=payload) - def join_thread(self, channel_id: int): + def join_thread(self, channel_id: Snowflake) -> Response[None]: return self.request(Route('POST', '/channels/{channel_id}/thread-members/@me', channel_id=channel_id)) - def add_user_to_thread(self, channel_id: int, user_id: int): + def add_user_to_thread(self, channel_id: Snowflake, user_id: Snowflake) -> Response[None]: return self.request( Route('PUT', '/channels/{channel_id}/thread-members/{user_id}', channel_id=channel_id, user_id=user_id) ) - def leave_thread(self, channel_id: int): + def leave_thread(self, channel_id: Snowflake) -> Response[None]: return self.request(Route('DELETE', '/channels/{channel_id}/thread-members/@me', channel_id=channel_id)) - def remove_user_from_thread(self, channel_id: int, user_id: int): + def remove_user_from_thread(self, channel_id: Snowflake, user_id: Snowflake) -> Response[None]: route = Route('DELETE', '/channels/{channel_id}/thread-members/{user_id}', channel_id=channel_id, user_id=user_id) return self.request(route) def get_public_archived_threads( - self, channel_id: int, before=None, limit: int = 50 + self, channel_id: Snowflake, before: Optional[Snowflake] = None, limit: int = 50 ) -> Response[threads.ThreadPaginationPayload]: route = Route('GET', '/channels/{channel_id}/threads/archived/public', channel_id=channel_id) @@ -799,7 +928,7 @@ class HTTPClient: return self.request(route, params=params) def get_private_archived_threads( - self, channel_id: int, before=None, limit: int = 50 + self, channel_id: Snowflake, before: Optional[Snowflake] = None, limit: int = 50 ) -> Response[threads.ThreadPaginationPayload]: route = Route('GET', '/channels/{channel_id}/threads/archived/private', channel_id=channel_id) @@ -810,7 +939,7 @@ class HTTPClient: return self.request(route, params=params) def get_joined_private_archived_threads( - self, channel_id: int, before=None, limit: int = 50 + self, channel_id: Snowflake, before: Optional[Snowflake] = None, limit: int = 50 ) -> Response[threads.ThreadPaginationPayload]: route = Route('GET', '/channels/{channel_id}/users/@me/threads/archived/private', channel_id=channel_id) params = {} @@ -819,18 +948,25 @@ class HTTPClient: params['limit'] = limit return self.request(route, params=params) - def get_active_threads(self, channel_id: int) -> Response[threads.ThreadPaginationPayload]: + def get_active_threads(self, channel_id: Snowflake) -> Response[threads.ThreadPaginationPayload]: route = Route('GET', '/channels/{channel_id}/threads/active', channel_id=channel_id) return self.request(route) - def get_thread_members(self, channel_id: int) -> Response[List[threads.ThreadMember]]: + def get_thread_members(self, channel_id: Snowflake) -> Response[List[threads.ThreadMember]]: route = Route('GET', '/channels/{channel_id}/thread-members', channel_id=channel_id) return self.request(route) # Webhook management - def create_webhook(self, channel_id, *, name, avatar=None, reason=None): - payload = { + def create_webhook( + self, + channel_id: Snowflake, + *, + name: str, + avatar: Optional[bytes] = None, + reason: Optional[str] = None, + ) -> Response[webhook.Webhook]: + payload: Dict[str, Any] = { 'name': name, } if avatar is not None: @@ -839,16 +975,21 @@ class HTTPClient: r = Route('POST', '/channels/{channel_id}/webhooks', channel_id=channel_id) return self.request(r, json=payload, reason=reason) - def channel_webhooks(self, channel_id): + def channel_webhooks(self, channel_id: Snowflake) -> Response[List[webhook.Webhook]]: return self.request(Route('GET', '/channels/{channel_id}/webhooks', channel_id=channel_id)) - def guild_webhooks(self, guild_id): + def guild_webhooks(self, guild_id: Snowflake) -> Response[List[webhook.Webhook]]: return self.request(Route('GET', '/guilds/{guild_id}/webhooks', guild_id=guild_id)) - def get_webhook(self, webhook_id): + def get_webhook(self, webhook_id: Snowflake) -> Response[webhook.Webhook]: return self.request(Route('GET', '/webhooks/{webhook_id}', webhook_id=webhook_id)) - def follow_webhook(self, channel_id, webhook_channel_id, reason=None): + def follow_webhook( + self, + channel_id: Snowflake, + webhook_channel_id: Snowflake, + reason: Optional[str] = None, + ) -> Response[None]: payload = { 'webhook_channel_id': str(webhook_channel_id), } @@ -858,8 +999,13 @@ class HTTPClient: # Guild management - def get_guilds(self, limit, before=None, after=None): - params = { + def get_guilds( + self, + limit: int, + before: Optional[Snowflake] = None, + after: Optional[Snowflake] = None, + ) -> Response[List[guild.Guild]]: + params: Dict[str, Any] = { 'limit': limit, } @@ -870,16 +1016,16 @@ class HTTPClient: return self.request(Route('GET', '/users/@me/guilds'), params=params) - def leave_guild(self, guild_id): + def leave_guild(self, guild_id: Snowflake) -> Response[None]: return self.request(Route('DELETE', '/users/@me/guilds/{guild_id}', guild_id=guild_id)) - def get_guild(self, guild_id): + def get_guild(self, guild_id: Snowflake) -> Response[guild.Guild]: return self.request(Route('GET', '/guilds/{guild_id}', guild_id=guild_id)) - def delete_guild(self, guild_id): + def delete_guild(self, guild_id: Snowflake) -> Response[None]: return self.request(Route('DELETE', '/guilds/{guild_id}', guild_id=guild_id)) - def create_guild(self, name, region, icon): + def create_guild(self, name: str, region: str, icon: bytes) -> Response[guild.Guild]: payload = { 'name': name, 'icon': icon, @@ -888,7 +1034,7 @@ class HTTPClient: return self.request(Route('POST', '/guilds'), json=payload) - def edit_guild(self, guild_id, *, reason=None, **fields): + def edit_guild(self, guild_id: Snowflake, *, reason: Optional[str] = None, **fields: Any) -> Response[guild.Guild]: valid_keys = ( 'name', 'region', @@ -915,19 +1061,19 @@ class HTTPClient: return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload, reason=reason) - def get_template(self, code): + def get_template(self, code: str) -> Response[template.Template]: return self.request(Route('GET', '/guilds/templates/{code}', code=code)) - def guild_templates(self, guild_id): + def guild_templates(self, guild_id: Snowflake) -> Response[List[template.Template]]: return self.request(Route('GET', '/guilds/{guild_id}/templates', guild_id=guild_id)) - def create_template(self, guild_id, payload): + def create_template(self, guild_id: Snowflake, payload: template.CreateTemplate) -> Response[template.Template]: return self.request(Route('POST', '/guilds/{guild_id}/templates', guild_id=guild_id), json=payload) - def sync_template(self, guild_id, code): + def sync_template(self, guild_id: Snowflake, code: str) -> Response[template.Template]: return self.request(Route('PUT', '/guilds/{guild_id}/templates/{code}', guild_id=guild_id, code=code)) - def edit_template(self, guild_id, code, payload): + def edit_template(self, guild_id: Snowflake, code: str, payload) -> Response[template.Template]: valid_keys = ( 'name', 'description', @@ -937,10 +1083,10 @@ class HTTPClient: Route('PATCH', '/guilds/{guild_id}/templates/{code}', guild_id=guild_id, code=code), json=payload ) - def delete_template(self, guild_id, code): + def delete_template(self, guild_id: Snowflake, code: str) -> Response[None]: return self.request(Route('DELETE', '/guilds/{guild_id}/templates/{code}', guild_id=guild_id, code=code)) - def create_from_template(self, code, name, region, icon): + def create_from_template(self, code: str, name: str, region: str, icon: bytes) -> Response[guild.Guild]: payload = { 'name': name, 'icon': icon, @@ -948,24 +1094,24 @@ class HTTPClient: } return self.request(Route('POST', '/guilds/templates/{code}', code=code), json=payload) - def get_bans(self, guild_id): + def get_bans(self, guild_id: Snowflake) -> Response[List[guild.Ban]]: return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id)) - def get_ban(self, user_id, guild_id): + def get_ban(self, user_id: Snowflake, guild_id: Snowflake) -> Response[guild.Ban]: return self.request(Route('GET', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id)) - def get_vanity_code(self, guild_id): + def get_vanity_code(self, guild_id: Snowflake) -> Response[invite.VanityInvite]: return self.request(Route('GET', '/guilds/{guild_id}/vanity-url', guild_id=guild_id)) - def change_vanity_code(self, guild_id, code, *, reason=None): - payload = {'code': code} + def change_vanity_code(self, guild_id: Snowflake, code: str, *, reason: Optional[str] = None) -> Response[None]: + payload: Dict[str, Any] = {'code': code} return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload, reason=reason) - def get_all_guild_channels(self, guild_id): + def get_all_guild_channels(self, guild_id: Snowflake) -> Response[List[guild.GuildChannel]]: return self.request(Route('GET', '/guilds/{guild_id}/channels', guild_id=guild_id)) - def get_members(self, guild_id, limit, after): - params = { + def get_members(self, guild_id: Snowflake, limit: int, after: Optional[Snowflake]) -> Response[List[member.Member]]: + params: Dict[str, Any] = { 'limit': limit, } if after: @@ -974,11 +1120,19 @@ class HTTPClient: r = Route('GET', '/guilds/{guild_id}/members', guild_id=guild_id) return self.request(r, params=params) - def get_member(self, guild_id, member_id): + def get_member(self, guild_id: Snowflake, member_id: Snowflake) -> Response[member.Member]: return self.request(Route('GET', '/guilds/{guild_id}/members/{member_id}', guild_id=guild_id, member_id=member_id)) - def prune_members(self, guild_id, days, compute_prune_count, roles, *, reason=None): - payload = { + def prune_members( + self, + guild_id: Snowflake, + days: int, + compute_prune_count: bool, + roles: List[str], + *, + reason: Optional[str] = None, + ) -> Response[guild.GuildPrune]: + payload: Dict[str, Any] = { 'days': days, 'compute_prune_count': 'true' if compute_prune_count else 'false', } @@ -987,8 +1141,13 @@ class HTTPClient: return self.request(Route('POST', '/guilds/{guild_id}/prune', guild_id=guild_id), json=payload, reason=reason) - def estimate_pruned_members(self, guild_id, days, roles): - params = { + def estimate_pruned_members( + self, + guild_id: Snowflake, + days: int, + roles: List[str], + ) -> Response[guild.GuildPrune]: + params: Dict[str, Any] = { 'days': days, } if roles: @@ -996,13 +1155,21 @@ class HTTPClient: return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params) - def get_all_custom_emojis(self, guild_id): + def get_all_custom_emojis(self, guild_id: Snowflake) -> Response[List[emoji.Emoji]]: return self.request(Route('GET', '/guilds/{guild_id}/emojis', guild_id=guild_id)) - def get_custom_emoji(self, guild_id, emoji_id): + def get_custom_emoji(self, guild_id: Snowflake, emoji_id: Snowflake) -> Response[emoji.Emoji]: return self.request(Route('GET', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id)) - def create_custom_emoji(self, guild_id, name, image, *, roles=None, reason=None): + def create_custom_emoji( + self, + guild_id: Snowflake, + name: str, + image: bytes, + *, + roles: Optional[SnowflakeList] = None, + reason: Optional[str] = None, + ) -> Response[emoji.Emoji]: payload = { 'name': name, 'image': image, @@ -1012,20 +1179,33 @@ class HTTPClient: r = Route('POST', '/guilds/{guild_id}/emojis', guild_id=guild_id) return self.request(r, json=payload, reason=reason) - def delete_custom_emoji(self, guild_id, emoji_id, *, reason=None): + def delete_custom_emoji( + self, + guild_id: Snowflake, + emoji_id: Snowflake, + *, + reason: Optional[str] = None, + ) -> Response[None]: r = Route('DELETE', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) return self.request(r, reason=reason) - def edit_custom_emoji(self, guild_id: int, emoji_id: int, *, payload, reason: Optional[str] = None): + def edit_custom_emoji( + self, + guild_id: Snowflake, + emoji_id: Snowflake, + *, + payload: Dict[str, Any], + reason: Optional[str] = None, + ) -> Response[emoji.Emoji]: r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) return self.request(r, json=payload, reason=reason) - def get_all_integrations(self, guild_id): + def get_all_integrations(self, guild_id: Snowflake) -> Response[List[integration.Integration]]: r = Route('GET', '/guilds/{guild_id}/integrations', guild_id=guild_id) return self.request(r) - def create_integration(self, guild_id, type, id): + def create_integration(self, guild_id: Snowflake, type: integration.IntegrationType, id: int) -> Response[None]: payload = { 'type': type, 'id': id, @@ -1034,29 +1214,37 @@ class HTTPClient: r = Route('POST', '/guilds/{guild_id}/integrations', guild_id=guild_id) return self.request(r, json=payload) - def edit_integration(self, guild_id, integration_id, **payload): + def edit_integration(self, guild_id: Snowflake, integration_id: Snowflake, **payload: Any) -> Response[None]: r = Route( 'PATCH', '/guilds/{guild_id}/integrations/{integration_id}', guild_id=guild_id, integration_id=integration_id ) return self.request(r, json=payload) - def sync_integration(self, guild_id, integration_id): + def sync_integration(self, guild_id: Snowflake, integration_id: Snowflake) -> Response[None]: r = Route( 'POST', '/guilds/{guild_id}/integrations/{integration_id}/sync', guild_id=guild_id, integration_id=integration_id ) return self.request(r) - def delete_integration(self, guild_id, integration_id): + def delete_integration(self, guild_id: Snowflake, integration_id: Snowflake) -> Response[None]: r = Route( 'DELETE', '/guilds/{guild_id}/integrations/{integration_id}', guild_id=guild_id, integration_id=integration_id ) return self.request(r) - def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None): - params = {'limit': limit} + def get_audit_logs( + self, + guild_id: Snowflake, + limit: int = 100, + before: Optional[Snowflake] = None, + after: Optional[Snowflake] = None, + user_id: Optional[Snowflake] = None, + action_type: Optional[AuditLogAction] = None, + ) -> Response[audit_log.AuditLog]: + params: Dict[str, Any] = {'limit': limit} if before: params['before'] = before if after: @@ -1079,16 +1267,16 @@ class HTTPClient: def create_invite( self, - channel_id: int, + channel_id: Snowflake, *, reason: Optional[str] = None, max_age: int = 0, max_uses: int = 0, temporary: bool = False, unique: bool = True, - target_type: Optional[int] = None, - target_user_id: Optional[int] = None, - target_application_id: Optional[int] = None + target_type: Optional[invite.InviteTargetType] = None, + target_user_id: Optional[Snowflake] = None, + target_application_id: Optional[Snowflake] = None ) -> Response[invite.Invite]: r = Route('POST', '/channels/{channel_id}/invites', channel_id=channel_id) payload = { @@ -1122,36 +1310,49 @@ class HTTPClient: def invites_from_channel(self, channel_id: Snowflake) -> Response[List[invite.Invite]]: return self.request(Route('GET', '/channels/{channel_id}/invites', channel_id=channel_id)) - def delete_invite(self, invite_id: str, *, reason: bool = None) -> Response[None]: + def delete_invite(self, invite_id: str, *, reason: Optional[str] = None) -> Response[None]: return self.request(Route('DELETE', '/invites/{invite_id}', invite_id=invite_id), reason=reason) # Role management - def get_roles(self, guild_id): + def get_roles(self, guild_id: Snowflake) -> Response[List[role.Role]]: return self.request(Route('GET', '/guilds/{guild_id}/roles', guild_id=guild_id)) - def edit_role(self, guild_id, role_id, *, reason=None, **fields): + def edit_role(self, guild_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None, **fields: Any) -> Response[role.Role]: r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable') payload = {k: v for k, v in fields.items() if k in valid_keys} return self.request(r, json=payload, reason=reason) - def delete_role(self, guild_id, role_id, *, reason=None): + def delete_role(self, guild_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route('DELETE', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) return self.request(r, reason=reason) - def replace_roles(self, user_id, guild_id, role_ids, *, reason=None): + def replace_roles( + self, + user_id: Snowflake, + guild_id: Snowflake, + role_ids: List[int], + *, + reason: Optional[str] = None, + ) -> Response[member.Member]: return self.edit_member(guild_id=guild_id, user_id=user_id, roles=role_ids, reason=reason) - def create_role(self, guild_id, *, reason=None, **fields): + def create_role(self, guild_id: Snowflake, *, reason: Optional[str] = None, **fields: Any) -> Response[role.Role]: r = Route('POST', '/guilds/{guild_id}/roles', guild_id=guild_id) return self.request(r, json=fields, reason=reason) - def move_role_position(self, guild_id, positions, *, reason=None): + def move_role_position( + self, + guild_id: Snowflake, + positions: List[guild.RolePositionUpdate], + *, + reason: Optional[str] = None, + ) -> Response[List[role.Role]]: r = Route('PATCH', '/guilds/{guild_id}/roles', guild_id=guild_id) return self.request(r, json=positions, reason=reason) - def add_role(self, guild_id, user_id, role_id, *, reason=None): + def add_role(self, guild_id: Snowflake, user_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route( 'PUT', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', @@ -1161,7 +1362,7 @@ class HTTPClient: ) return self.request(r, reason=reason) - def remove_role(self, guild_id, user_id, role_id, *, reason=None): + def remove_role(self, guild_id: Snowflake, user_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route( 'DELETE', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', @@ -1171,18 +1372,40 @@ class HTTPClient: ) return self.request(r, reason=reason) - def edit_channel_permissions(self, channel_id, target, allow, deny, type, *, reason=None): + def edit_channel_permissions( + self, + channel_id: Snowflake, + target: Snowflake, + allow: str, + deny: str, + type: channel.OverwriteType, + *, + reason: Optional[str] = None, + ) -> Response[None]: payload = {'id': target, 'allow': allow, 'deny': deny, 'type': type} r = Route('PUT', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) return self.request(r, json=payload, reason=reason) - def delete_channel_permissions(self, channel_id, target, *, reason=None): + def delete_channel_permissions( + self, + channel_id: Snowflake, + target: channel.OverwriteType, + *, + reason: Optional[str] = None + ) -> Response[None]: r = Route('DELETE', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) return self.request(r, reason=reason) # Voice management - def move_member(self, user_id, guild_id, channel_id, *, reason=None): + def move_member( + self, + user_id: Snowflake, + guild_id: Snowflake, + channel_id: Snowflake, + *, + reason: Optional[str] = None, + ) -> Response[member.Member]: return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason) # Stage instance management @@ -1214,10 +1437,10 @@ class HTTPClient: # Application commands (global) - def get_global_commands(self, application_id) -> Response[List[interactions.ApplicationCommand]]: + def get_global_commands(self, application_id: Snowflake) -> Response[List[interactions.ApplicationCommand]]: return self.request(Route('GET', '/applications/{application_id}/commands', application_id=application_id)) - def get_global_command(self, application_id, command_id) -> Response[interactions.ApplicationCommand]: + def get_global_command(self, application_id: Snowflake, command_id: Snowflake) -> Response[interactions.ApplicationCommand]: r = Route( 'GET', '/applications/{application_id}/commands/{command_id}', @@ -1226,17 +1449,21 @@ class HTTPClient: ) return self.request(r) - def upsert_global_command(self, application_id, payload) -> Response[interactions.ApplicationCommand]: + def upsert_global_command(self, application_id: Snowflake, payload) -> Response[interactions.ApplicationCommand]: r = Route('POST', '/applications/{application_id}/commands', application_id=application_id) return self.request(r, json=payload) - def edit_global_command(self, application_id, command_id, payload) -> Response[interactions.ApplicationCommand]: + def edit_global_command(self, + application_id: Snowflake, + command_id: Snowflake, + payload: interactions.EditApplicationCommand, + ) -> Response[interactions.ApplicationCommand]: valid_keys = ( 'name', 'description', 'options', ) - payload = {k: v for k, v in payload.items() if k in valid_keys} + payload = {k: v for k, v in payload.items() if k in valid_keys} # type: ignore r = Route( 'PATCH', '/applications/{application_id}/commands/{command_id}', @@ -1245,7 +1472,7 @@ class HTTPClient: ) return self.request(r, json=payload) - def delete_global_command(self, application_id, command_id): + def delete_global_command(self, application_id: Snowflake, command_id: Snowflake) -> Response[None]: r = Route( 'DELETE', '/applications/{application_id}/commands/{command_id}', @@ -1254,13 +1481,13 @@ class HTTPClient: ) return self.request(r) - def bulk_upsert_global_commands(self, application_id, payload) -> Response[List[interactions.ApplicationCommand]]: + def bulk_upsert_global_commands(self, application_id: Snowflake, payload) -> Response[List[interactions.ApplicationCommand]]: r = Route('PUT', '/applications/{application_id}/commands', application_id=application_id) return self.request(r, json=payload) # Application commands (guild) - def get_guild_commands(self, application_id, guild_id) -> Response[List[interactions.ApplicationCommand]]: + def get_guild_commands(self, application_id: Snowflake, guild_id: Snowflake) -> Response[List[interactions.ApplicationCommand]]: r = Route( 'GET', '/applications/{application_id}/guilds/{guild_id}/commands', @@ -1269,7 +1496,12 @@ class HTTPClient: ) return self.request(r) - def get_guild_command(self, application_id, guild_id, command_id) -> Response[interactions.ApplicationCommand]: + def get_guild_command( + self, + application_id: Snowflake, + guild_id: Snowflake, + command_id: Snowflake, + ) -> Response[interactions.ApplicationCommand]: r = Route( 'GET', '/applications/{application_id}/guilds/{guild_id}/commands/{command_id}', @@ -1279,7 +1511,12 @@ class HTTPClient: ) return self.request(r) - def upsert_guild_command(self, application_id, guild_id, payload) -> Response[interactions.ApplicationCommand]: + def upsert_guild_command( + self, + application_id: Snowflake, + guild_id: Snowflake, + payload: interactions.EditApplicationCommand, + ) -> Response[interactions.ApplicationCommand]: r = Route( 'POST', '/applications/{application_id}/guilds/{guild_id}/commands', @@ -1288,13 +1525,18 @@ class HTTPClient: ) return self.request(r, json=payload) - def edit_guild_command(self, application_id, guild_id, command_id, payload) -> Response[interactions.ApplicationCommand]: + def edit_guild_command(self, + application_id: Snowflake, + guild_id: Snowflake, + command_id: Snowflake, + payload: interactions.EditApplicationCommand, + ) -> Response[interactions.ApplicationCommand]: valid_keys = ( 'name', 'description', 'options', ) - payload = {k: v for k, v in payload.items() if k in valid_keys} + payload = {k: v for k, v in payload.items() if k in valid_keys} # type: ignore r = Route( 'PATCH', '/applications/{application_id}/guilds/{guild_id}/commands/{command_id}', @@ -1304,7 +1546,12 @@ class HTTPClient: ) return self.request(r, json=payload) - def delete_guild_command(self, application_id, guild_id, command_id): + def delete_guild_command( + self, + application_id: Snowflake, + guild_id: Snowflake, + command_id: Snowflake, + ) -> Response[None]: r = Route( 'DELETE', '/applications/{application_id}/guilds/{guild_id}/commands/{command_id}', @@ -1315,7 +1562,10 @@ class HTTPClient: return self.request(r) def bulk_upsert_guild_commands( - self, application_id, guild_id, payload + self, + application_id: Snowflake, + guild_id: Snowflake, + payload: List[interactions.EditApplicationCommand], ) -> Response[List[interactions.ApplicationCommand]]: r = Route( 'PUT', @@ -1329,14 +1579,14 @@ class HTTPClient: def _edit_webhook_helper( self, - route, - file=None, - content=None, - embeds=None, - allowed_mentions=None, + route: Route, + file: Optional[File] = None, + content: Optional[str] = None, + embeds: Optional[List[embed.Embed]] = None, + allowed_mentions: Optional[message.AllowedMentions] = None, ): - payload = {} + payload: Dict[str, Any] = {} if content: payload['content'] = content if embeds: @@ -1344,7 +1594,7 @@ class HTTPClient: if allowed_mentions: payload['allowed_mentions'] = allowed_mentions - form = [ + form: List[Dict[str, Any]] = [ { 'name': 'payload_json', 'value': utils.to_json(payload), @@ -1361,16 +1611,23 @@ class HTTPClient: } ) - return self.request(route, form=form, files=[file]) + return self.request(route, form=form, files=[file] if file else None) - def create_interaction_response(self, interaction_id, token, *, type, data=None): + def create_interaction_response( + self, + interaction_id: Snowflake, + token: str, + *, + type: InteractionResponseType, + data: Optional[interactions.InteractionApplicationCommandCallbackData] = None + ) -> Response[None]: r = Route( 'POST', '/interactions/{interaction_id}/{interaction_token}/callback', interaction_id=interaction_id, interaction_token=token, ) - payload = { + payload: Dict[str, Any] = { 'type': type, } @@ -1381,9 +1638,9 @@ class HTTPClient: def get_original_interaction_response( self, - application_id, - token, - ): + application_id: Snowflake, + token: str, + ) -> Response[message.Message]: r = Route( 'GET', '/webhooks/{application_id}/{interaction_token}/messages/@original', @@ -1394,13 +1651,13 @@ class HTTPClient: def edit_original_interaction_response( self, - application_id, - token, - file=None, - content=None, - embeds=None, - allowed_mentions=None, - ): + application_id: Snowflake, + token: str, + file: Optional[File] = None, + content: Optional[str] = None, + embeds: Optional[List[embed.Embed]] = None, + allowed_mentions: Optional[message.AllowedMentions] = None, + ) -> Response[message.Message]: r = Route( 'PATCH', '/webhooks/{application_id}/{interaction_token}/messages/@original', @@ -1409,7 +1666,7 @@ class HTTPClient: ) return self._edit_webhook_helper(r, file=file, content=content, embeds=embeds, allowed_mentions=allowed_mentions) - def delete_original_interaction_response(self, application_id, token): + def delete_original_interaction_response(self, application_id: Snowflake, token: str) -> Response[None]: r = Route( 'DELETE', '/webhooks/{application_id}/{interaction_token}/messages/@original', @@ -1420,14 +1677,14 @@ class HTTPClient: def create_followup_message( self, - application_id, - token, - files=None, - content=None, - tts=False, - embeds=None, - allowed_mentions=None, - ): + application_id: Snowflake, + token: str, + files: List[File] = [], + content: Optional[str] = None, + tts: bool = False, + embeds: Optional[List[embed.Embed]] = None, + allowed_mentions: Optional[message.AllowedMentions] = None, + ) -> Response[message.Message]: r = Route( 'POST', '/webhooks/{application_id}/{interaction_token}', @@ -1445,14 +1702,14 @@ class HTTPClient: def edit_followup_message( self, - application_id, - token, - message_id, - file=None, - content=None, - embeds=None, - allowed_mentions=None, - ): + application_id: Snowflake, + token: str, + message_id: Snowflake, + file: Optional[File] = None, + content: Optional[str] = None, + embeds: Optional[List[embed.Embed]] = None, + allowed_mentions: Optional[message.AllowedMentions] = None, + )-> Response[message.Message]: r = Route( 'PATCH', '/webhooks/{application_id}/{interaction_token}/messages/{message_id}', @@ -1462,7 +1719,7 @@ class HTTPClient: ) return self._edit_webhook_helper(r, file=file, content=content, embeds=embeds, allowed_mentions=allowed_mentions) - def delete_followup_message(self, application_id, token, message_id): + def delete_followup_message(self, application_id: Snowflake, token: str, message_id: Snowflake) -> Response[None]: r = Route( 'DELETE', '/webhooks/{application_id}/{interaction_token}/messages/{message_id}', @@ -1473,7 +1730,9 @@ class HTTPClient: return self.request(r) def get_guild_application_command_permissions( - self, application_id, guild_id + self, + application_id: Snowflake, + guild_id: Snowflake, ) -> Response[List[interactions.GuildApplicationCommandPermissions]]: r = Route( 'GET', @@ -1484,7 +1743,10 @@ class HTTPClient: return self.request(r) def get_application_command_permissions( - self, application_id, guild_id, command_id + self, + application_id: Snowflake, + guild_id: Snowflake, + command_id: Snowflake, ) -> Response[interactions.GuildApplicationCommandPermissions]: r = Route( 'GET', @@ -1495,7 +1757,13 @@ class HTTPClient: ) return self.request(r) - def edit_application_command_permissions(self, application_id, guild_id, command_id, payload): + def edit_application_command_permissions( + self, + application_id: Snowflake, + guild_id: Snowflake, + command_id: Snowflake, + payload: interactions.BaseGuildApplicationCommandPermissions, + ) -> Response[None]: r = Route( 'PUT', '/applications/{application_id}/guilds/{guild_id}/commands/{command_id}/permissions', @@ -1505,7 +1773,12 @@ class HTTPClient: ) return self.request(r, json=payload) - def bulk_edit_guild_application_command_permissions(self, application_id, guild_id, payload): + def bulk_edit_guild_application_command_permissions( + self, + application_id: Snowflake, + guild_id: Snowflake, + payload: List[interactions.PartialGuildApplicationCommandPermissions], + ) -> Response[None]: r = Route( 'PUT', '/applications/{application_id}/guilds/{guild_id}/commands/permissions', @@ -1516,10 +1789,10 @@ class HTTPClient: # Misc - def application_info(self): + def application_info(self) -> Response[appinfo.AppInfo]: return self.request(Route('GET', '/oauth2/applications/@me')) - async def get_gateway(self, *, encoding='json', zlib=True): + async def get_gateway(self, *, encoding: str = 'json', zlib: bool = True) -> str: try: data = await self.request(Route('GET', '/gateway')) except HTTPException as exc: @@ -1530,7 +1803,7 @@ class HTTPClient: value = '{0}?encoding={1}&v=9' return value.format(data['url'], encoding) - async def get_bot_gateway(self, *, encoding='json', zlib=True): + async def get_bot_gateway(self, *, encoding: str = 'json', zlib: bool = True) -> Tuple[int, str]: try: data = await self.request(Route('GET', '/gateway/bot')) except HTTPException as exc: @@ -1542,5 +1815,5 @@ class HTTPClient: value = '{0}?encoding={1}&v=9' return data['shards'], value.format(data['url'], encoding) - def get_user(self, user_id): + def get_user(self, user_id: Snowflake) -> Response[user.User]: return self.request(Route('GET', '/users/{user_id}', user_id=user_id)) diff --git a/discord/types/channel.py b/discord/types/channel.py index d4f4cf3d2..ca6c54da6 100644 --- a/discord/types/channel.py +++ b/discord/types/channel.py @@ -28,9 +28,12 @@ from .snowflake import Snowflake from .threads import ThreadMetadata, ThreadMember +OverwriteType = Literal[0, 1] + + class PermissionOverwrite(TypedDict): id: Snowflake - type: Literal[0, 1] + type: OverwriteType allow: str deny: str diff --git a/discord/types/emoji.py b/discord/types/emoji.py index 94121bf9b..d54690c14 100644 --- a/discord/types/emoji.py +++ b/discord/types/emoji.py @@ -39,3 +39,8 @@ class Emoji(PartialEmoji, total=False): managed: bool animated: bool available: bool + + +class EditEmoji(TypedDict): + name: str + roles: Optional[SnowflakeList] diff --git a/discord/types/gateway.py b/discord/types/gateway.py new file mode 100644 index 000000000..bcf3e4673 --- /dev/null +++ b/discord/types/gateway.py @@ -0,0 +1,41 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from typing import TypedDict + + +class SessionStartLimit(TypedDict): + total: int + remaining: int + reset_after: int + max_concurrency: int + + +class Gateway(TypedDict): + url: str + + +class GatewayBot(Gateway): + shards: int + session_start_limit: SessionStartLimit diff --git a/discord/types/guild.py b/discord/types/guild.py index c5e24b2f1..57a4b115f 100644 --- a/discord/types/guild.py +++ b/discord/types/guild.py @@ -140,3 +140,20 @@ class InviteGuild(Guild, total=False): class GuildWithCounts(Guild, _GuildPreviewUnique): ... + + +class GuildPrune(TypedDict): + pruned: Optional[int] + + +class ChannelPositionUpdate(TypedDict): + id: Snowflake + position: Optional[int] + lock_permissions: Optional[bool] + parent_id: Optional[Snowflake] + +class _RolePositionRequired(TypedDict): + id: Snowflake + +class RolePositionUpdate(_RolePositionRequired, total=False): + position: Optional[Snowflake] diff --git a/discord/types/interactions.py b/discord/types/interactions.py index 6740aef39..466e4192d 100644 --- a/discord/types/interactions.py +++ b/discord/types/interactions.py @@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. from __future__ import annotations -from typing import TYPE_CHECKING, Dict, TypedDict, Union, List, Literal +from typing import Optional, TYPE_CHECKING, Dict, TypedDict, Union, List, Literal from .snowflake import Snowflake from .components import Component, ComponentType from .embed import Embed @@ -77,11 +77,14 @@ class ApplicationCommandPermissions(TypedDict): permission: bool -class PartialGuildApplicationCommandPermissions(TypedDict): - id: Snowflake +class BaseGuildApplicationCommandPermissions(TypedDict): permissions: List[ApplicationCommandPermissions] +class PartialGuildApplicationCommandPermissions(BaseGuildApplicationCommandPermissions): + id: Snowflake + + class GuildApplicationCommandPermissions(PartialGuildApplicationCommandPermissions): application_id: Snowflake guild_id: Snowflake @@ -95,7 +98,9 @@ class _ApplicationCommandInteractionDataOptionOptional(TypedDict, total=False): options: List[ApplicationCommandInteractionDataOption] -class ApplicationCommandInteractionDataOption(_ApplicationCommandInteractionDataOptionOptional): +class ApplicationCommandInteractionDataOption( + _ApplicationCommandInteractionDataOptionOptional +): name: str type: ApplicationCommandOptionType @@ -149,6 +154,7 @@ class Interaction(_InteractionOptional): token: str version: int + class InteractionApplicationCommandCallbackData(TypedDict, total=False): tts: bool content: str @@ -174,3 +180,10 @@ class MessageInteraction(TypedDict): type: InteractionType name: str user: User + + +class EditApplicationCommand(TypedDict): + name: str + description: str + options: Optional[List[ApplicationCommandOption]] + default_permission: bool diff --git a/discord/types/invite.py b/discord/types/invite.py index 7290d36fe..50b69bd4a 100644 --- a/discord/types/invite.py +++ b/discord/types/invite.py @@ -52,6 +52,10 @@ class _InviteMetadata(TypedDict, total=False): expires_at: Optional[str] +class VanityInvite(_InviteMetadata): + code: Optional[str] + + class IncompleteInvite(_InviteMetadata): code: str channel: PartialChannel diff --git a/discord/types/member.py b/discord/types/member.py index 4c162ef1a..b80ab6130 100644 --- a/discord/types/member.py +++ b/discord/types/member.py @@ -27,6 +27,10 @@ from .snowflake import SnowflakeList from .user import User +class Nickname(TypedDict): + nick: str + + class PartialMember(TypedDict): roles: SnowflakeList joined_at: str diff --git a/discord/types/template.py b/discord/types/template.py index eaf5e756e..85c698911 100644 --- a/discord/types/template.py +++ b/discord/types/template.py @@ -30,6 +30,11 @@ from .user import User from .guild import Guild +class CreateTemplate(TypedDict): + name: str + icon: Optional[bytes] + + class Template(TypedDict): code: str name: str diff --git a/discord/types/threads.py b/discord/types/threads.py index c0f0c10b4..baf8def40 100644 --- a/discord/types/threads.py +++ b/discord/types/threads.py @@ -27,7 +27,7 @@ from typing import List, Literal, Optional, TypedDict from .snowflake import Snowflake -ThreadTypes = Literal[10, 11, 12] +ThreadType = Literal[10, 11, 12] ThreadArchiveDuration = Literal[60, 1440, 4320, 10080] @@ -61,7 +61,7 @@ class Thread(_ThreadOptional): parent_id: Snowflake owner_id: Snowflake name: str - type: ThreadTypes + type: ThreadType member_count: int message_count: int rate_limit_per_user: int