From ce762f2c00d59d29d18c54ee2d189a23b971a097 Mon Sep 17 00:00:00 2001 From: endercheif Date: Sun, 5 Dec 2021 13:57:17 -0800 Subject: [PATCH 01/17] :sparkles: Added sticker support --- pincer/objects/guild/guild.py | 363 +++++++++++++++++++----------- pincer/objects/message/sticker.py | 59 +++++ 2 files changed, 294 insertions(+), 128 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 5c70b983..44ad7b78 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -5,7 +5,7 @@ from dataclasses import dataclass, field from enum import IntEnum -from typing import AsyncGenerator, overload, TYPE_CHECKING +from typing import AsyncGenerator, overload, TYPE_CHECKING, Generator from ...exceptions import UnavailableGuildError from ...utils.api_object import APIObject @@ -31,7 +31,7 @@ from ..voice.region import VoiceRegion from ..events.presence import PresenceUpdateEvent from ..message.emoji import Emoji - from ..message.sticker import Sticker + from ..message.sticker import Sticker, StickerPack from ..user.voice_state import VoiceState from ...client import Client from ...utils.timestamp import Timestamp @@ -443,14 +443,14 @@ async def get_member(self, _id: int) -> GuildMember: @overload async def modify_member( - self, - *, - _id: int, - nick: Optional[str] = None, - roles: Optional[List[Snowflake]] = None, - mute: Optional[bool] = None, - deaf: Optional[bool] = None, - channel_id: Optional[Snowflake] = None, + self, + *, + _id: int, + nick: Optional[str] = None, + roles: Optional[List[Snowflake]] = None, + mute: Optional[bool] = None, + deaf: Optional[bool] = None, + channel_id: Optional[Snowflake] = None, ) -> GuildMember: """|coro| Modifies a member in the guild from its identifier and based on the @@ -483,10 +483,10 @@ async def modify_member(self, _id: int, **kwargs) -> GuildMember: return GuildMember.from_dict(construct_client_dict(self._client, data)) async def ban( - self, - member_id: int, - reason: str = None, - delete_message_days: int = None + self, + member_id: int, + reason: str = None, + delete_message_days: int = None ): """ Parameters @@ -550,16 +550,16 @@ async def get_roles(self) -> AsyncGenerator[Role, None]: @overload async def create_role( - self, - reason: Optional[str] = None, - *, - name: Optional[str] = "new role", - permissions: Optional[str] = None, - color: Optional[int] = 0, - hoist: Optional[bool] = False, - icon: Optional[str] = None, - unicode_emoji: Optional[str] = None, - mentionable: Optional[bool] = False, + self, + reason: Optional[str] = None, + *, + name: Optional[str] = "new role", + permissions: Optional[str] = None, + color: Optional[int] = 0, + hoist: Optional[bool] = False, + icon: Optional[str] = None, + unicode_emoji: Optional[str] = None, + mentionable: Optional[bool] = False, ) -> Role: """|coro| Creates a new role for the guild. @@ -597,9 +597,9 @@ async def create_role( ... async def create_role( - self, - reason: Optional[str] = None, - **kwargs + self, + reason: Optional[str] = None, + **kwargs ) -> Role: return Role.from_dict( construct_client_dict( @@ -613,10 +613,10 @@ async def create_role( ) async def edit_role_position( - self, - id: Snowflake, - reason: Optional[str] = None, - position: Optional[int] = None + self, + id: Snowflake, + reason: Optional[str] = None, + position: Optional[int] = None ) -> AsyncGenerator[Role, None]: """|coro| Edits the position of a role. @@ -645,17 +645,17 @@ async def edit_role_position( @overload async def edit_role( - self, - id: Snowflake, - reason: Optional[str] = None, - *, - name: Optional[str] = None, - permissions: Optional[str] = None, - color: Optional[int] = None, - hoist: Optional[bool] = None, - icon: Optional[str] = None, - unicode_emoji: Optional[str] = None, - mentionable: Optional[bool] = None, + self, + id: Snowflake, + reason: Optional[str] = None, + *, + name: Optional[str] = None, + permissions: Optional[str] = None, + color: Optional[int] = None, + hoist: Optional[bool] = None, + icon: Optional[str] = None, + unicode_emoji: Optional[str] = None, + mentionable: Optional[bool] = None, ) -> Role: """|coro| Edits a role. @@ -694,10 +694,10 @@ async def edit_role( ... async def edit_role( - self, - id: Snowflake, - reason: Optional[str] = None, - **kwargs + self, + id: Snowflake, + reason: Optional[str] = None, + **kwargs ) -> Role: return Role.from_dict( construct_client_dict( @@ -779,27 +779,27 @@ async def unban(self, id: Snowflake, reason: Optional[str] = None): @overload async def edit( - self, - *, - name: Optional[str] = None, - region: Optional[str] = None, - verification_level: Optional[int] = None, - default_message_notifications: Optional[int] = None, - explicit_content_filter: Optional[int] = None, - afk_channel_id: Optional[Snowflake] = None, - afk_timeout: Optional[int] = None, - icon: Optional[str] = None, - owner_id: Optional[Snowflake] = None, - splash: Optional[str] = None, - discovery_splash: Optional[str] = None, - banner: Optional[str] = None, - system_channel_id: Optional[Snowflake] = None, - system_channel_flags: Optional[int] = None, - rules_channel_id: Optional[Snowflake] = None, - public_updates_channel_id: Optional[Snowflake] = None, - preferred_locale: Optional[str] = None, - features: Optional[List[GuildFeature]] = None, - description: Optional[str] = None, + self, + *, + name: Optional[str] = None, + region: Optional[str] = None, + verification_level: Optional[int] = None, + default_message_notifications: Optional[int] = None, + explicit_content_filter: Optional[int] = None, + afk_channel_id: Optional[Snowflake] = None, + afk_timeout: Optional[int] = None, + icon: Optional[str] = None, + owner_id: Optional[Snowflake] = None, + splash: Optional[str] = None, + discovery_splash: Optional[str] = None, + banner: Optional[str] = None, + system_channel_id: Optional[Snowflake] = None, + system_channel_flags: Optional[int] = None, + rules_channel_id: Optional[Snowflake] = None, + public_updates_channel_id: Optional[Snowflake] = None, + preferred_locale: Optional[str] = None, + features: Optional[List[GuildFeature]] = None, + description: Optional[str] = None, ) -> Guild: """|coro| Modifies the guild @@ -884,9 +884,9 @@ async def delete(self): await self._http.delete(f"guilds/{self.id}") async def prune_count( - self, - days: Optional[int] = 7, - include_roles: Optional[str] = None + self, + days: Optional[int] = 7, + include_roles: Optional[str] = None ) -> int: """|coro| Returns the number of members that @@ -911,11 +911,11 @@ async def prune_count( )["pruned"] async def prune( - self, - days: Optional[int] = 7, - compute_prune_days: Optional[bool] = True, - include_roles: Optional[List[Snowflake]] = None, - reason: Optional[str] = None + self, + days: Optional[int] = 7, + compute_prune_days: Optional[bool] = True, + include_roles: Optional[List[Snowflake]] = None, + reason: Optional[str] = None ) -> int: """|coro| Prunes members from the guild. Requires the ``KICK_MEMBERS`` permission. @@ -960,7 +960,8 @@ async def get_voice_regions(self) -> AsyncGenerator[VoiceRegion, None]: """ data = await self._http.get(f"guilds/{self.id}/regions") for voice_region_data in data: - yield VoiceRegion.from_dict(construct_client_dict(self._client, voice_region_data)) + yield VoiceRegion.from_dict( + construct_client_dict(self._client, voice_region_data)) async def get_invites(self) -> AsyncGenerator[Invite, None]: """|coro| @@ -974,7 +975,8 @@ async def get_invites(self) -> AsyncGenerator[Invite, None]: """ data = await self._http.get(f"guilds/{self.id}/invites") for invite_data in data: - yield Invite.from_dict(construct_client_dict(self._client, invite_data)) + yield Invite.from_dict( + construct_client_dict(self._client, invite_data)) async def get_integrations(self) -> AsyncGenerator[Integration, None]: """|coro| @@ -988,12 +990,13 @@ async def get_integrations(self) -> AsyncGenerator[Integration, None]: """ data = await self._http.get(f"guilds/{self.id}/integrations") for integration_data in data: - yield Integration.from_dict(construct_client_dict(self._client, integration_data)) + yield Integration.from_dict( + construct_client_dict(self._client, integration_data)) async def delete_integration( - self, - integration: Integration, - reason: Optional[str] = None + self, + integration: Integration, + reason: Optional[str] = None ): """|coro| Deletes an integration. @@ -1029,9 +1032,9 @@ async def get_widget_settings(self) -> GuildWidget: ) async def modify_widget( - self, - reason: Optional[str] = None, - **kwargs + self, + reason: Optional[str] = None, + **kwargs ) -> GuildWidget: """|coro| Modifies the guild widget for the guild. @@ -1077,7 +1080,8 @@ async def vanity_url(self) -> Invite: data = await self._http.get(f"guilds/{self.id}/vanity-url") return Invite.from_dict(construct_client_dict(self._client, data)) - async def get_widget_image(self, style: Optional[str] = "shield") -> str: # TODO Replace str with ImageURL object + async def get_widget_image(self, style: Optional[ + str] = "shield") -> str: # TODO Replace str with ImageURL object """|coro| Returns a PNG image widget for the guild. Requires no permissions or authentication. @@ -1122,14 +1126,15 @@ async def get_welcome_screen(self) -> WelcomeScreen: The welcome screen for the guild. """ data = await self._http.get(f"guilds/{self.id}/welcome-screen") - return WelcomeScreen.from_dict(construct_client_dict(self._client, data)) + return WelcomeScreen.from_dict( + construct_client_dict(self._client, data)) async def modify_welcome_screen( - self, - enabled: Optional[bool] = None, - welcome_channels: Optional[List[WelcomeScreenChannel]] = None, - description: Optional[str] = None, - reason: Optional[str] = None + self, + enabled: Optional[bool] = None, + welcome_channels: Optional[List[WelcomeScreenChannel]] = None, + description: Optional[str] = None, + reason: Optional[str] = None ) -> WelcomeScreen: """|coro| Modifies the guild's Welcome Screen. @@ -1162,13 +1167,14 @@ async def modify_welcome_screen( }, headers=remove_none({"X-Audit-Log-Reason": reason}) ) - return WelcomeScreen.from_dict(construct_client_dict(self._client, data)) + return WelcomeScreen.from_dict( + construct_client_dict(self._client, data)) async def modify_current_user_voice_state( - self, - channel_id: Snowflake, - suppress: Optional[bool] = None, - request_to_speak_timestamp: Optional[Timestamp] = None + self, + channel_id: Snowflake, + suppress: Optional[bool] = None, + request_to_speak_timestamp: Optional[Timestamp] = None ): """|coro| Updates the current user's voice state. @@ -1202,10 +1208,10 @@ async def modify_current_user_voice_state( ) async def modify_user_voice_state( - self, - user: User, - channel_id: Snowflake, - suppress: Optional[bool] = None + self, + user: User, + channel_id: Snowflake, + suppress: Optional[bool] = None ): """|coro| Updates another user's voice state. @@ -1292,12 +1298,12 @@ async def get_emoji(self, id: Snowflake) -> Emoji: ) async def create_emoji( - self, - *, - name: str, - image: str, - roles: List[Snowflake], - reason: Optional[str] = None + self, + *, + name: str, + image: str, + roles: List[Snowflake], + reason: Optional[str] = None ) -> Emoji: """|coro| Creates a new emoji for the guild. @@ -1336,12 +1342,12 @@ async def create_emoji( ) async def edit_emoji( - self, - id: Snowflake, - *, - name: Optional[str] = None, - roles: Optional[List[Snowflake]] = None, - reason: Optional[str] = None + self, + id: Snowflake, + *, + name: Optional[str] = None, + roles: Optional[List[Snowflake]] = None, + reason: Optional[str] = None ) -> Emoji: """|coro| Modifies the given emoji. @@ -1376,10 +1382,10 @@ async def edit_emoji( ) async def delete_emoji( - self, - id: Snowflake, - *, - reason: Optional[str] = None + self, + id: Snowflake, + *, + reason: Optional[str] = None ): """|coro| Deletes the given emoji. @@ -1413,9 +1419,9 @@ async def get_templates(self) -> AsyncGenerator[GuildTemplate, None]: ) async def create_template( - self, - name: str, - description: Optional[str] = None + self, + name: str, + description: Optional[str] = None ) -> GuildTemplate: """|coro| Creates a new template for the guild. @@ -1445,8 +1451,8 @@ async def create_template( ) async def sync_template( - self, - template: GuildTemplate + self, + template: GuildTemplate ) -> GuildTemplate: """|coro| Syncs the given template. @@ -1470,11 +1476,11 @@ async def sync_template( ) async def edit_template( - self, - template: GuildTemplate, - *, - name: Optional[str] = None, - description: Optional[str] = None + self, + template: GuildTemplate, + *, + name: Optional[str] = None, + description: Optional[str] = None ) -> GuildTemplate: """|coro| Modifies the template's metadata. @@ -1508,8 +1514,8 @@ async def edit_template( ) async def delete_template( - self, - template: GuildTemplate + self, + template: GuildTemplate ) -> GuildTemplate: """|coro| Deletes the given template. @@ -1532,6 +1538,106 @@ async def delete_template( construct_client_dict(self._client, data) ) + + @classmethod + async def sticker_packs(cls) -> Generator[StickerPack, None, None]: + """|coro| + Returns the list of sticker packs available to Nitro subscribers. + + Yields + ------ + :class:`~pincer.objects.message.sticker.StickerPack` + a sticker pack + """ + packs = await cls._http.get("sticker-packs") + return (StickerPack.from_dict(pack) for pack in packs) + + async def list_stickers(self) -> Generator[Sticker, None, None]: + """|coro| + Returns an array of sticker objects for the current guild. + Includes ``user`` fields if the bot has the ``MANAGE_EMOJIS_AND_STICKERS`` permission. + + Yields + ------ + :class:`~pincer.objects.message.sticker.Sticker` + a sticker for the current guild + """ + return ( + Sticker.from_dict(sticker) + for sticker in await self._http.get(f"guild/{self.id}/stickers") + ) + + async def get_sticker(self, _id: Snowflake): + """|coro| + Returns a sticker object for the current guild and sticker IDs. + Includes the ``user`` field if the bot has the ``MANAGE_EMOJIS_AND_STICKERS`` permission. + + Parameters + ---------- + _id : int + id of the sticker + + Returns + ------- + :class:`~pincer.objects.message.sticker.Sticker` + the sticker requested + """ + sticker = await self._http.get(f"guilds/{self.id}/stickers/{_id}") + return Sticker.from_dict(sticker) + + async def create_sticker( + self, + name: str, + tags: str, + file, + description: str = "", + reason: Optional[str] = None + ) -> Sticker: + """NOT IMPLEMENTED: DOES NOT WORK""" + raise NotImplementedError + # TODO: Fix this once File is fixed + # """|coro| + # Create a new sticker for the guild. + # Requires the ``MANAGE_EMOJIS_AND_STICKERS permission``. + # + # Parameters + # ---------- + # name : str + # name of the sticker (2-30 characters) + # tags : str + # autocomplete/suggestion tags for the sticker (max 200 characters) + # file : + # the sticker file to upload, must be a PNG, APNG, or Lottie JSON file, max 500 KB + # description : Optional[:class:`str`] + # description of the sticker (empty or 2-100 characters) |default| :data:`""` + # reason : Optional[:class:`str`] |default| :data:`None` + # reason for creating the sticker + # + # Returns + # ------- + # :class:`~pincer.objects.message.sticker.Sticker` + # the newly created sticker + # """ + # sticker = await self._http.post( + # f"guilds/{self.id}/stickers", + # headers=remove_none({"X-Audit-Log-Reason": reason}) + # ) + # + # return Sticker.from_dict(sticker) + + + async def delete_sticker(self, _id: Snowflake) -> None: + """|coro| + Delete the given sticker. + Requires the ``MANAGE_EMOJIS_AND_STICKERS`` permission. + + Parameters + ---------- + _id: Snowflake + id of the sticker + """ + await self._http.delete(f"guilds/{self.id}/stickers/{_id}") + @classmethod def from_dict(cls, data) -> Guild: """ @@ -1544,6 +1650,7 @@ def from_dict(cls, data) -> Guild: :class:`~pincer.objects.guild.guild.Guild` The new guild object. Raises + ------ :class:`~pincer.exceptions.UnavailableGuildError` The guild is unavailable due to a discord outage. """ diff --git a/pincer/objects/message/sticker.py b/pincer/objects/message/sticker.py index bd213174..75993381 100644 --- a/pincer/objects/message/sticker.py +++ b/pincer/objects/message/sticker.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING from ...utils.api_object import APIObject +from ...utils.conversion import remove_none from ...utils.types import MISSING if TYPE_CHECKING: @@ -94,6 +95,64 @@ class Sticker(APIObject): sort_value: APINullable[int] = MISSING user: APINullable[User] = MISSING + @classmethod + async def from_id(cls, _id: Snowflake) -> Sticker: + """|coro| + Returns a sticker object for the given sticker ID. + + Parameters + ---------- + _id : Snowflake + id of the sticker + + Returns + ------- + :class:`~pincer.objects.message.sticker.Sticker` + sticker object of the given ID + """ + sticker = await cls._http.get(f"stickers/{_id}") + return cls.from_dict(sticker) + + + async def modify( + self, + name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[str] = None, + reason: Optional[str] = None + ) -> Sticker: + """|coro| + Modify the given sticker. + Requires the ``MANAGE_EMOJIS_AND_STICKERS permission.`` + + Parameters + ---------- + name : Optional[:class:`str`] |default| :data:`None` + name of the sticker (2-30 characters) + description : Optional[:class:`str`] |default| :data:`None` + description of the sticker (2-100 characters) + tags : Optional[:class:`str`] |default| :data:`None` + autocomplete/suggestion tags for the sticker (max 200 characters) + reason : Optional[:class:`str`] + reason for modifying the sticker + + Returns + ------- + :class:`~pincer.objects.message.sticker.Sticker` + the modified sticker + """ + sticker = self._http.patch( + f"guilds/{self.guild_id}/stickers/{self.id}", + data=remove_none( + dict(name=name, description=description, tags=tags) + ), + headers=remove_none({"X-Audit-Log-Reason": reason}) + ) + + return Sticker.from_dict(sticker) + + + @dataclass class StickerItem(APIObject): From 2a1e003f4313003c1be0f3de80f84dd4d8fe63c5 Mon Sep 17 00:00:00 2001 From: Yohann Boniface Date: Mon, 6 Dec 2021 00:17:00 +0100 Subject: [PATCH 02/17] =?UTF-8?q?=F0=9F=8E=A8=20Improving=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> 🎨 Improving formatting Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> 🎨 Improving formatting Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> 🎨 Improving formatting Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> 🎨 Improving formatting Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/guild/guild.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index b03e37de..cc75e03c 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -968,7 +968,8 @@ async def get_voice_regions(self) -> AsyncGenerator[VoiceRegion, None]: data = await self._http.get(f"guilds/{self.id}/regions") for voice_region_data in data: yield VoiceRegion.from_dict( - construct_client_dict(self._client, voice_region_data)) + construct_client_dict(self._client, voice_region_data) + ) async def get_invites(self) -> AsyncGenerator[Invite, None]: """|coro| @@ -983,7 +984,8 @@ async def get_invites(self) -> AsyncGenerator[Invite, None]: data = await self._http.get(f"guilds/{self.id}/invites") for invite_data in data: yield Invite.from_dict( - construct_client_dict(self._client, invite_data)) + construct_client_dict(self._client, invite_data) + ) async def get_integrations(self) -> AsyncGenerator[Integration, None]: """|coro| @@ -998,7 +1000,8 @@ async def get_integrations(self) -> AsyncGenerator[Integration, None]: data = await self._http.get(f"guilds/{self.id}/integrations") for integration_data in data: yield Integration.from_dict( - construct_client_dict(self._client, integration_data)) + construct_client_dict(self._client, integration_data) + ) async def delete_integration( self, @@ -1087,8 +1090,10 @@ async def vanity_url(self) -> Invite: data = await self._http.get(f"guilds/{self.id}/vanity-url") return Invite.from_dict(construct_client_dict(self._client, data)) - async def get_widget_image(self, style: Optional[ - str] = "shield") -> str: # TODO Replace str with ImageURL object + async def get_widget_image( + self, + style: Optional[str] = "shield" + ) -> str: # TODO Replace str with ImageURL object """|coro| Returns a PNG image widget for the guild. Requires no permissions or authentication. @@ -1134,7 +1139,8 @@ async def get_welcome_screen(self) -> WelcomeScreen: """ data = await self._http.get(f"guilds/{self.id}/welcome-screen") return WelcomeScreen.from_dict( - construct_client_dict(self._client, data)) + construct_client_dict(self._client, data) + ) async def modify_welcome_screen( self, From 219cf5ca9c6e5ed502b07ccbd8284a0b8d3f3354 Mon Sep 17 00:00:00 2001 From: Yohann Boniface Date: Mon, 6 Dec 2021 00:17:54 +0100 Subject: [PATCH 03/17] Update pincer/objects/guild/guild.py Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/guild/guild.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index cc75e03c..c51368e8 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1181,7 +1181,8 @@ async def modify_welcome_screen( headers=remove_none({"X-Audit-Log-Reason": reason}) ) return WelcomeScreen.from_dict( - construct_client_dict(self._client, data)) + construct_client_dict(self._client, data) + ) async def modify_current_user_voice_state( self, From fa794d20e24949238ee0e3c4bdc12dd97f6c5dfc Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Sun, 5 Dec 2021 20:40:47 -0800 Subject: [PATCH 04/17] :label: annotation on get_sticker Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/guild/guild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index c51368e8..a773330f 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1580,7 +1580,7 @@ async def list_stickers(self) -> Generator[Sticker, None, None]: for sticker in await self._http.get(f"guild/{self.id}/stickers") ) - async def get_sticker(self, _id: Snowflake): + async def get_sticker(self, _id: Snowflake) -> Sticker: """|coro| Returns a sticker object for the current guild and sticker IDs. Includes the ``user`` field if the bot has the ``MANAGE_EMOJIS_AND_STICKERS`` permission. From fe2176b7b7ce0680d57dca02f0f0bd3eaddffe40 Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Sun, 5 Dec 2021 20:41:01 -0800 Subject: [PATCH 05/17] :label: remove annotation on delete_sticker Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/guild/guild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index a773330f..d5977008 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1639,7 +1639,7 @@ async def create_sticker( # return Sticker.from_dict(sticker) - async def delete_sticker(self, _id: Snowflake) -> None: + async def delete_sticker(self, _id: Snowflake): """|coro| Delete the given sticker. Requires the ``MANAGE_EMOJIS_AND_STICKERS`` permission. From 6bd58d1b0924089ab0a2e939401fba190d97f953 Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Sun, 5 Dec 2021 20:41:31 -0800 Subject: [PATCH 06/17] :art: Better `dict` creation Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/message/sticker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/objects/message/sticker.py b/pincer/objects/message/sticker.py index 9be642a8..6f565c81 100644 --- a/pincer/objects/message/sticker.py +++ b/pincer/objects/message/sticker.py @@ -144,7 +144,7 @@ async def modify( sticker = self._http.patch( f"guilds/{self.guild_id}/stickers/{self.id}", data=remove_none( - dict(name=name, description=description, tags=tags) + {"name": name, "description": description, "tags": tags} ), headers=remove_none({"X-Audit-Log-Reason": reason}) ) From 4588fad306ed143b0162c4b321cd086ee96b4fb9 Mon Sep 17 00:00:00 2001 From: endercheif Date: Sun, 5 Dec 2021 22:01:33 -0800 Subject: [PATCH 07/17] :art: Formatting with black --- pincer/objects/guild/guild.py | 319 +++++++++++++----------------- pincer/objects/message/sticker.py | 17 +- 2 files changed, 141 insertions(+), 195 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index d5977008..30d6aa2d 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -172,7 +172,6 @@ class SystemChannelFlags(IntEnum): SUPPRESS_JOIN_NOTIFICATION_REPLIES = 1 << 3 - @dataclass(repr=False) class GuildPreview(APIObject): """Represents a guild preview. @@ -351,7 +350,9 @@ class Guild(APIObject): system_channel_flags: APINullable[SystemChannelFlags] = MISSING explicit_content_filter: APINullable[ExplicitContentFilterLevel] = MISSING premium_tier: APINullable[PremiumTier] = MISSING - default_message_notifications: APINullable[DefaultMessageNotificationLevel] = MISSING + default_message_notifications: APINullable[ + DefaultMessageNotificationLevel + ] = MISSING mfa_level: APINullable[MFALevel] = MISSING owner_id: APINullable[Snowflake] = MISSING afk_timeout: APINullable[int] = MISSING @@ -450,14 +451,14 @@ async def get_member(self, _id: int) -> GuildMember: @overload async def modify_member( - self, - *, - _id: int, - nick: Optional[str] = None, - roles: Optional[List[Snowflake]] = None, - mute: Optional[bool] = None, - deaf: Optional[bool] = None, - channel_id: Optional[Snowflake] = None, + self, + *, + _id: int, + nick: Optional[str] = None, + roles: Optional[List[Snowflake]] = None, + mute: Optional[bool] = None, + deaf: Optional[bool] = None, + channel_id: Optional[Snowflake] = None, ) -> GuildMember: """|coro| Modifies a member in the guild from its identifier and based on the @@ -490,10 +491,10 @@ async def modify_member(self, _id: int, **kwargs) -> GuildMember: return GuildMember.from_dict(construct_client_dict(self._client, data)) async def ban( - self, - member_id: int, - reason: str = None, - delete_message_days: int = None + self, + member_id: int, + reason: str = None, + delete_message_days: int = None, ): """ Parameters @@ -516,9 +517,7 @@ async def ban( data["delete_message_days"] = delete_message_days await self._http.put( - f"/guilds/{self.id}/bans/{member_id}", - data=data, - headers=headers + f"/guilds/{self.id}/bans/{member_id}", data=data, headers=headers ) async def kick(self, member_id: int, reason: Optional[str] = None): @@ -538,8 +537,7 @@ async def kick(self, member_id: int, reason: Optional[str] = None): headers["X-Audit-Log-Reason"] = reason await self._http.delete( - f"/guilds/{self.id}/members/{member_id}", - header=headers + f"/guilds/{self.id}/members/{member_id}", header=headers ) async def get_roles(self) -> AsyncGenerator[Role, None]: @@ -557,16 +555,16 @@ async def get_roles(self) -> AsyncGenerator[Role, None]: @overload async def create_role( - self, - reason: Optional[str] = None, - *, - name: Optional[str] = "new role", - permissions: Optional[str] = None, - color: Optional[int] = 0, - hoist: Optional[bool] = False, - icon: Optional[str] = None, - unicode_emoji: Optional[str] = None, - mentionable: Optional[bool] = False, + self, + reason: Optional[str] = None, + *, + name: Optional[str] = "new role", + permissions: Optional[str] = None, + color: Optional[int] = 0, + hoist: Optional[bool] = False, + icon: Optional[str] = None, + unicode_emoji: Optional[str] = None, + mentionable: Optional[bool] = False, ) -> Role: """|coro| Creates a new role for the guild. @@ -603,27 +601,23 @@ async def create_role( """ ... - async def create_role( - self, - reason: Optional[str] = None, - **kwargs - ) -> Role: + async def create_role(self, reason: Optional[str] = None, **kwargs) -> Role: return Role.from_dict( construct_client_dict( self._client, await self._http.post( f"guilds/{self.id}/roles", data=kwargs, - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ), ) ) async def edit_role_position( - self, - id: Snowflake, - reason: Optional[str] = None, - position: Optional[int] = None + self, + id: Snowflake, + reason: Optional[str] = None, + position: Optional[int] = None, ) -> AsyncGenerator[Role, None]: """|coro| Edits the position of a role. @@ -645,24 +639,24 @@ async def edit_role_position( data = await self._http.patch( f"guilds/{self.id}/roles", data={"id": id, "position": position}, - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) for role_data in data: yield Role.from_dict(construct_client_dict(self._client, role_data)) @overload async def edit_role( - self, - id: Snowflake, - reason: Optional[str] = None, - *, - name: Optional[str] = None, - permissions: Optional[str] = None, - color: Optional[int] = None, - hoist: Optional[bool] = None, - icon: Optional[str] = None, - unicode_emoji: Optional[str] = None, - mentionable: Optional[bool] = None, + self, + id: Snowflake, + reason: Optional[str] = None, + *, + name: Optional[str] = None, + permissions: Optional[str] = None, + color: Optional[int] = None, + hoist: Optional[bool] = None, + icon: Optional[str] = None, + unicode_emoji: Optional[str] = None, + mentionable: Optional[bool] = None, ) -> Role: """|coro| Edits a role. @@ -701,10 +695,7 @@ async def edit_role( ... async def edit_role( - self, - id: Snowflake, - reason: Optional[str] = None, - **kwargs + self, id: Snowflake, reason: Optional[str] = None, **kwargs ) -> Role: return Role.from_dict( construct_client_dict( @@ -712,7 +703,7 @@ async def edit_role( await self._http.patch( f"guilds/{self.id}/roles/{id}", data=kwargs, - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ), ) ) @@ -731,7 +722,7 @@ async def delete_role(self, id: Snowflake, reason: Optional[str] = None): """ await self._http.delete( f"guilds/{self.id}/roles/{id}", - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) async def get_bans(self) -> AsyncGenerator[Ban, None]: @@ -781,32 +772,32 @@ async def unban(self, id: Snowflake, reason: Optional[str] = None): """ await self._http.delete( f"guilds/{self.id}/bans/{id}", - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) @overload async def edit( - self, - *, - name: Optional[str] = None, - region: Optional[str] = None, - verification_level: Optional[int] = None, - default_message_notifications: Optional[int] = None, - explicit_content_filter: Optional[int] = None, - afk_channel_id: Optional[Snowflake] = None, - afk_timeout: Optional[int] = None, - icon: Optional[str] = None, - owner_id: Optional[Snowflake] = None, - splash: Optional[str] = None, - discovery_splash: Optional[str] = None, - banner: Optional[str] = None, - system_channel_id: Optional[Snowflake] = None, - system_channel_flags: Optional[int] = None, - rules_channel_id: Optional[Snowflake] = None, - public_updates_channel_id: Optional[Snowflake] = None, - preferred_locale: Optional[str] = None, - features: Optional[List[GuildFeature]] = None, - description: Optional[str] = None, + self, + *, + name: Optional[str] = None, + region: Optional[str] = None, + verification_level: Optional[int] = None, + default_message_notifications: Optional[int] = None, + explicit_content_filter: Optional[int] = None, + afk_channel_id: Optional[Snowflake] = None, + afk_timeout: Optional[int] = None, + icon: Optional[str] = None, + owner_id: Optional[Snowflake] = None, + splash: Optional[str] = None, + discovery_splash: Optional[str] = None, + banner: Optional[str] = None, + system_channel_id: Optional[Snowflake] = None, + system_channel_flags: Optional[int] = None, + rules_channel_id: Optional[Snowflake] = None, + public_updates_channel_id: Optional[Snowflake] = None, + preferred_locale: Optional[str] = None, + features: Optional[List[GuildFeature]] = None, + description: Optional[str] = None, ) -> Guild: """|coro| Modifies the guild @@ -891,9 +882,7 @@ async def delete(self): await self._http.delete(f"guilds/{self.id}") async def prune_count( - self, - days: Optional[int] = 7, - include_roles: Optional[str] = None + self, days: Optional[int] = 7, include_roles: Optional[str] = None ) -> int: """|coro| Returns the number of members that @@ -918,11 +907,11 @@ async def prune_count( )["pruned"] async def prune( - self, - days: Optional[int] = 7, - compute_prune_days: Optional[bool] = True, - include_roles: Optional[List[Snowflake]] = None, - reason: Optional[str] = None + self, + days: Optional[int] = 7, + compute_prune_days: Optional[bool] = True, + include_roles: Optional[List[Snowflake]] = None, + reason: Optional[str] = None, ) -> int: """|coro| Prunes members from the guild. Requires the ``KICK_MEMBERS`` permission. @@ -951,9 +940,9 @@ async def prune( data={ "days": days, "compute_prune_days": compute_prune_days, - "include_roles": include_roles + "include_roles": include_roles, }, - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), )["pruned"] async def get_voice_regions(self) -> AsyncGenerator[VoiceRegion, None]: @@ -1004,9 +993,7 @@ async def get_integrations(self) -> AsyncGenerator[Integration, None]: ) async def delete_integration( - self, - integration: Integration, - reason: Optional[str] = None + self, integration: Integration, reason: Optional[str] = None ): """|coro| Deletes an integration. @@ -1021,7 +1008,7 @@ async def delete_integration( """ await self._http.delete( f"guilds/{self.id}/integrations/{integration.id}", - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) async def get_widget_settings(self) -> GuildWidget: @@ -1036,15 +1023,12 @@ async def get_widget_settings(self) -> GuildWidget: """ return GuildWidget.from_dict( construct_client_dict( - self._client, - await self._http.get(f"guilds/{self.id}/widget") + self._client, await self._http.get(f"guilds/{self.id}/widget") ) ) async def modify_widget( - self, - reason: Optional[str] = None, - **kwargs + self, reason: Optional[str] = None, **kwargs ) -> GuildWidget: """|coro| Modifies the guild widget for the guild. @@ -1065,7 +1049,7 @@ async def modify_widget( data = await self._http.patch( f"guilds/{self.id}/widget", data=kwargs, - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) return GuildWidget.from_dict(construct_client_dict(self._client, data)) @@ -1091,8 +1075,7 @@ async def vanity_url(self) -> Invite: return Invite.from_dict(construct_client_dict(self._client, data)) async def get_widget_image( - self, - style: Optional[str] = "shield" + self, style: Optional[str] = "shield" ) -> str: # TODO Replace str with ImageURL object """|coro| Returns a PNG image widget for the guild. @@ -1143,11 +1126,11 @@ async def get_welcome_screen(self) -> WelcomeScreen: ) async def modify_welcome_screen( - self, - enabled: Optional[bool] = None, - welcome_channels: Optional[List[WelcomeScreenChannel]] = None, - description: Optional[str] = None, - reason: Optional[str] = None + self, + enabled: Optional[bool] = None, + welcome_channels: Optional[List[WelcomeScreenChannel]] = None, + description: Optional[str] = None, + reason: Optional[str] = None, ) -> WelcomeScreen: """|coro| Modifies the guild's Welcome Screen. @@ -1176,19 +1159,19 @@ async def modify_welcome_screen( data={ "enabled": enabled, "welcome_channels": welcome_channels, - "description": description + "description": description, }, - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) return WelcomeScreen.from_dict( construct_client_dict(self._client, data) ) async def modify_current_user_voice_state( - self, - channel_id: Snowflake, - suppress: Optional[bool] = None, - request_to_speak_timestamp: Optional[Timestamp] = None + self, + channel_id: Snowflake, + suppress: Optional[bool] = None, + request_to_speak_timestamp: Optional[Timestamp] = None, ): """|coro| Updates the current user's voice state. @@ -1217,15 +1200,12 @@ async def modify_current_user_voice_state( data={ "channel_id": channel_id, "suppress": suppress, - "request_to_speak_timestamp": request_to_speak_timestamp - } + "request_to_speak_timestamp": request_to_speak_timestamp, + }, ) async def modify_user_voice_state( - self, - user: User, - channel_id: Snowflake, - suppress: Optional[bool] = None + self, user: User, channel_id: Snowflake, suppress: Optional[bool] = None ): """|coro| Updates another user's voice state. @@ -1252,10 +1232,7 @@ async def modify_user_voice_state( """ await self._http.patch( f"guilds/{self.id}/voice-states/{user.id}", - data={ - "channel_id": channel_id, - "suppress": suppress - } + data={"channel_id": channel_id, "suppress": suppress}, ) async def get_audit_log(self) -> AuditLog: @@ -1271,7 +1248,7 @@ async def get_audit_log(self) -> AuditLog: return AuditLog.from_dict( construct_client_dict( self._client, - await self._http.get(f"guilds/{self.id}/audit-logs") + await self._http.get(f"guilds/{self.id}/audit-logs"), ) ) @@ -1307,7 +1284,7 @@ async def get_emoji(self, id: Snowflake) -> Emoji: return Emoji.from_dict( construct_client_dict( self._client, - await self._http.get(f"guilds/{self.id}/emojis/{id}") + await self._http.get(f"guilds/{self.id}/emojis/{id}"), ) ) @@ -1317,7 +1294,7 @@ async def create_emoji( name: str, image: File, roles: List[Snowflake] = [], - reason: Optional[str] = None + reason: Optional[str] = None, ) -> Emoji: """|coro| Creates a new emoji for the guild. @@ -1344,24 +1321,18 @@ async def create_emoji( """ data = await self._http.post( f"guilds/{self.id}/emojis", - data={ - "name": name, - "image": image.uri, - "roles": roles - }, - headers=remove_none({"X-Audit-Log-Reason": reason}) - ) - return Emoji.from_dict( - construct_client_dict(self._client, data) + data={"name": name, "image": image.uri, "roles": roles}, + headers=remove_none({"X-Audit-Log-Reason": reason}), ) + return Emoji.from_dict(construct_client_dict(self._client, data)) async def edit_emoji( - self, - id: Snowflake, - *, - name: Optional[str] = None, - roles: Optional[List[Snowflake]] = None, - reason: Optional[str] = None + self, + id: Snowflake, + *, + name: Optional[str] = None, + roles: Optional[List[Snowflake]] = None, + reason: Optional[str] = None, ) -> Emoji: """|coro| Modifies the given emoji. @@ -1385,21 +1356,13 @@ async def edit_emoji( """ data = await self._http.patch( f"guilds/{self.id}/emojis/{id}", - data={ - "name": name, - "roles": roles - }, - headers=remove_none({"X-Audit-Log-Reason": reason}) - ) - return Emoji.from_dict( - construct_client_dict(self._client, data) + data={"name": name, "roles": roles}, + headers=remove_none({"X-Audit-Log-Reason": reason}), ) + return Emoji.from_dict(construct_client_dict(self._client, data)) async def delete_emoji( - self, - id: Snowflake, - *, - reason: Optional[str] = None + self, id: Snowflake, *, reason: Optional[str] = None ): """|coro| Deletes the given emoji. @@ -1414,7 +1377,7 @@ async def delete_emoji( """ await self._http.delete( f"guilds/{self.id}/emojis/{id}", - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) async def get_templates(self) -> AsyncGenerator[GuildTemplate, None]: @@ -1433,9 +1396,7 @@ async def get_templates(self) -> AsyncGenerator[GuildTemplate, None]: ) async def create_template( - self, - name: str, - description: Optional[str] = None + self, name: str, description: Optional[str] = None ) -> GuildTemplate: """|coro| Creates a new template for the guild. @@ -1455,19 +1416,13 @@ async def create_template( """ data = await self._http.post( f"guilds/{self.id}/templates", - data={ - "name": name, - "description": description - } + data={"name": name, "description": description}, ) return GuildTemplate.from_dict( construct_client_dict(self._client, data) ) - async def sync_template( - self, - template: GuildTemplate - ) -> GuildTemplate: + async def sync_template(self, template: GuildTemplate) -> GuildTemplate: """|coro| Syncs the given template. Requires the ``MANAGE_GUILD`` permission. @@ -1490,11 +1445,11 @@ async def sync_template( ) async def edit_template( - self, - template: GuildTemplate, - *, - name: Optional[str] = None, - description: Optional[str] = None + self, + template: GuildTemplate, + *, + name: Optional[str] = None, + description: Optional[str] = None, ) -> GuildTemplate: """|coro| Modifies the template's metadata. @@ -1518,19 +1473,13 @@ async def edit_template( """ data = await self._http.patch( f"guilds/{self.id}/templates/{template.code}", - data={ - "name": name, - "description": description - } + data={"name": name, "description": description}, ) return GuildTemplate.from_dict( construct_client_dict(self._client, data) ) - async def delete_template( - self, - template: GuildTemplate - ) -> GuildTemplate: + async def delete_template(self, template: GuildTemplate) -> GuildTemplate: """|coro| Deletes the given template. Requires the ``MANAGE_GUILD`` permission. @@ -1539,7 +1488,7 @@ async def delete_template( ---------- template : :class:`~pincer.objects.guild.template.GuildTemplate` The template to delete - + Returns ------- :class:`~pincer.objects.guild.template.GuildTemplate` @@ -1599,12 +1548,12 @@ async def get_sticker(self, _id: Snowflake) -> Sticker: return Sticker.from_dict(sticker) async def create_sticker( - self, - name: str, - tags: str, - file, - description: str = "", - reason: Optional[str] = None + self, + name: str, + tags: str, + file, + description: str = "", + reason: Optional[str] = None, ) -> Sticker: """NOT IMPLEMENTED: DOES NOT WORK""" raise NotImplementedError @@ -1638,7 +1587,6 @@ async def create_sticker( # # return Sticker.from_dict(sticker) - async def delete_sticker(self, _id: Snowflake): """|coro| Delete the given sticker. @@ -1666,7 +1614,6 @@ async def get_webhooks(self) -> AsyncGenerator[Webhook, None]: construct_client_dict(self._client, webhook_data) ) - @classmethod def from_dict(cls, data) -> Guild: """ diff --git a/pincer/objects/message/sticker.py b/pincer/objects/message/sticker.py index 6f565c81..eccffb34 100644 --- a/pincer/objects/message/sticker.py +++ b/pincer/objects/message/sticker.py @@ -28,6 +28,7 @@ class StickerType(IntEnum): GUILD: Sticker is a custom sticker from a discord server. """ + STANDARD = 1 GUILD = 2 @@ -44,6 +45,7 @@ class StickerFormatType(IntEnum): LOTTIE: Sticker is animated with with LOTTIE format. (vector based) """ + PNG = 1 APNG = 2 LOTTIE = 3 @@ -113,13 +115,12 @@ async def from_id(cls, _id: Snowflake) -> Sticker: sticker = await cls._http.get(f"stickers/{_id}") return cls.from_dict(sticker) - async def modify( - self, - name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[str] = None, - reason: Optional[str] = None + self, + name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[str] = None, + reason: Optional[str] = None, ) -> Sticker: """|coro| Modify the given sticker. @@ -146,14 +147,12 @@ async def modify( data=remove_none( {"name": name, "description": description, "tags": tags} ), - headers=remove_none({"X-Audit-Log-Reason": reason}) + headers=remove_none({"X-Audit-Log-Reason": reason}), ) return Sticker.from_dict(sticker) - - @dataclass(repr=False) class StickerItem(APIObject): """Represents the smallest amount of data required to render a sticker. From 87104fd1ae1399a2f536904e3580630dbb30b2ae Mon Sep 17 00:00:00 2001 From: endercheif Date: Sun, 5 Dec 2021 22:09:07 -0800 Subject: [PATCH 08/17] :zap: Yield instead of return --- pincer/objects/guild/guild.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 30d6aa2d..b52d72f4 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -3,9 +3,10 @@ from __future__ import annotations +from collections import AsyncIterator from dataclasses import dataclass, field from enum import IntEnum -from typing import AsyncGenerator, overload, TYPE_CHECKING, Generator +from typing import AsyncGenerator, overload, TYPE_CHECKING from .invite import Invite from .channel import Channel @@ -1502,9 +1503,9 @@ async def delete_template(self, template: GuildTemplate) -> GuildTemplate: ) @classmethod - async def sticker_packs(cls) -> Generator[StickerPack, None, None]: + async def sticker_packs(cls) -> AsyncIterator[StickerPack]: """|coro| - Returns the list of sticker packs available to Nitro subscribers. + Yields sticker packs available to Nitro subscribers. Yields ------ @@ -1512,11 +1513,12 @@ async def sticker_packs(cls) -> Generator[StickerPack, None, None]: a sticker pack """ packs = await cls._http.get("sticker-packs") - return (StickerPack.from_dict(pack) for pack in packs) + for pack in packs: + yield StickerPack.from_dict(pack) - async def list_stickers(self) -> Generator[Sticker, None, None]: + async def list_stickers(self) -> AsyncIterator[Sticker]: """|coro| - Returns an array of sticker objects for the current guild. + Yields sticker objects for the current guild. Includes ``user`` fields if the bot has the ``MANAGE_EMOJIS_AND_STICKERS`` permission. Yields @@ -1524,10 +1526,9 @@ async def list_stickers(self) -> Generator[Sticker, None, None]: :class:`~pincer.objects.message.sticker.Sticker` a sticker for the current guild """ - return ( - Sticker.from_dict(sticker) - for sticker in await self._http.get(f"guild/{self.id}/stickers") - ) + + for sticker in await self._http.get(f"guild/{self.id}/stickers"): + yield Sticker.from_dict(sticker) async def get_sticker(self, _id: Snowflake) -> Sticker: """|coro| From 5c2a3987f96aae1ebef673e9818b9e4dd8e43d20 Mon Sep 17 00:00:00 2001 From: endercheif Date: Sun, 5 Dec 2021 22:14:18 -0800 Subject: [PATCH 09/17] :art: Move `sticker_packs` to Client --- pincer/client.py | 18 ++++++++++++++++-- pincer/objects/guild/guild.py | 13 ------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/pincer/client.py b/pincer/client.py index 61c2e95e..8a4301bf 100644 --- a/pincer/client.py +++ b/pincer/client.py @@ -8,7 +8,8 @@ from collections import defaultdict from importlib import import_module from inspect import isasyncgenfunction -from typing import Any, Dict, List, Optional, Tuple, Union, overload +from typing import Any, Dict, List, Optional, Tuple, Union, overload, \ + AsyncIterator from typing import TYPE_CHECKING from . import __package__ @@ -22,7 +23,7 @@ from .middleware import middleware from .objects import ( Role, Channel, DefaultThrottleHandler, User, Guild, Intents, - GuildTemplate + GuildTemplate, StickerPack ) from .utils.conversion import construct_client_dict from .utils.event_mgr import EventMgr @@ -857,4 +858,17 @@ async def get_webhook( """ return await Webhook.from_id(self, id, token) + async def sticker_packs(self) -> AsyncIterator[StickerPack]: + """|coro| + Yields sticker packs available to Nitro subscribers. + + Yields + ------ + :class:`~pincer.objects.message.sticker.StickerPack` + a sticker pack + """ + packs = await self.http.get("sticker-packs") + for pack in packs: + yield StickerPack.from_dict(pack) + Bot = Client diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index b52d72f4..67b94061 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1502,19 +1502,6 @@ async def delete_template(self, template: GuildTemplate) -> GuildTemplate: construct_client_dict(self._client, data) ) - @classmethod - async def sticker_packs(cls) -> AsyncIterator[StickerPack]: - """|coro| - Yields sticker packs available to Nitro subscribers. - - Yields - ------ - :class:`~pincer.objects.message.sticker.StickerPack` - a sticker pack - """ - packs = await cls._http.get("sticker-packs") - for pack in packs: - yield StickerPack.from_dict(pack) async def list_stickers(self) -> AsyncIterator[Sticker]: """|coro| From ed23ca4792d9657e0c75247d7d00995d2fdfc156 Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Mon, 6 Dec 2021 21:48:19 -0800 Subject: [PATCH 10/17] :art: Apply suggestions from code review Co-authored-by: Lunarmagpie <65521138+Lunarmagpie@users.noreply.github.com> --- pincer/client.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pincer/client.py b/pincer/client.py index 8a4301bf..ae9f50f0 100644 --- a/pincer/client.py +++ b/pincer/client.py @@ -8,8 +8,9 @@ from collections import defaultdict from importlib import import_module from inspect import isasyncgenfunction -from typing import Any, Dict, List, Optional, Tuple, Union, overload, \ - AsyncIterator +from typing import ( + Any, Dict, List, Optional, Tuple, Union, overload, AsyncIterator +) from typing import TYPE_CHECKING from . import __package__ @@ -858,7 +859,7 @@ async def get_webhook( """ return await Webhook.from_id(self, id, token) - async def sticker_packs(self) -> AsyncIterator[StickerPack]: + async def sticker_packs(self) -> AsyncGenerator[StickerPack, None]: """|coro| Yields sticker packs available to Nitro subscribers. From 718860eefc1e584bd1374fd91353af2e852c111d Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Tue, 7 Dec 2021 12:37:44 -0800 Subject: [PATCH 11/17] :pencil2: Typo in pincer/objects/guild/guild.py Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/guild/guild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 67b94061..3a082859 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -538,7 +538,7 @@ async def kick(self, member_id: int, reason: Optional[str] = None): headers["X-Audit-Log-Reason"] = reason await self._http.delete( - f"/guilds/{self.id}/members/{member_id}", header=headers + f"/guilds/{self.id}/members/{member_id}", headers=headers ) async def get_roles(self) -> AsyncGenerator[Role, None]: From 997764052319c756d99362ea917ab21b8a48109e Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:10:29 -0800 Subject: [PATCH 12/17] :art: AsyncGenerator -> AsyncIterator Co-authored-by: trag1c <77130613+trag1c@users.noreply.github.com> --- pincer/objects/guild/guild.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 3a082859..d9aa359a 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -977,7 +977,7 @@ async def get_invites(self) -> AsyncGenerator[Invite, None]: construct_client_dict(self._client, invite_data) ) - async def get_integrations(self) -> AsyncGenerator[Integration, None]: + async def get_integrations(self) -> AsyncIterator[Integration]: """|coro| Returns an async generator of integrations for the guild. Requires the ``MANAGE_GUILD`` permission. @@ -1381,7 +1381,7 @@ async def delete_emoji( headers=remove_none({"X-Audit-Log-Reason": reason}), ) - async def get_templates(self) -> AsyncGenerator[GuildTemplate, None]: + async def get_templates(self) -> AsyncIterator[GuildTemplate]: """|coro| Returns an async generator of the guild templates. From d134077147197670b44469e8849ec68ebab63a11 Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:13:10 -0800 Subject: [PATCH 13/17] :memo: Spilt docstring to newline --- pincer/objects/guild/guild.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index d9aa359a..aad7622b 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1506,7 +1506,8 @@ async def delete_template(self, template: GuildTemplate) -> GuildTemplate: async def list_stickers(self) -> AsyncIterator[Sticker]: """|coro| Yields sticker objects for the current guild. - Includes ``user`` fields if the bot has the ``MANAGE_EMOJIS_AND_STICKERS`` permission. + Includes ``user`` fields if the bot has the + ``MANAGE_EMOJIS_AND_STICKERS`` permission. Yields ------ @@ -1520,7 +1521,8 @@ async def list_stickers(self) -> AsyncIterator[Sticker]: async def get_sticker(self, _id: Snowflake) -> Sticker: """|coro| Returns a sticker object for the current guild and sticker IDs. - Includes the ``user`` field if the bot has the ``MANAGE_EMOJIS_AND_STICKERS`` permission. + Includes the ``user`` field if the bot has the + ``MANAGE_EMOJIS_AND_STICKERS`` permission. Parameters ---------- From 82a6c40586373dc72d15f13459620035318a9c3b Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Tue, 7 Dec 2021 17:08:50 -0800 Subject: [PATCH 14/17] Update pincer/client.py Co-authored-by: Yohann Boniface --- pincer/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/client.py b/pincer/client.py index ae9f50f0..a48e6f24 100644 --- a/pincer/client.py +++ b/pincer/client.py @@ -859,7 +859,7 @@ async def get_webhook( """ return await Webhook.from_id(self, id, token) - async def sticker_packs(self) -> AsyncGenerator[StickerPack, None]: + async def sticker_packs(self) -> AsyncIterator[StickerPack]: """|coro| Yields sticker packs available to Nitro subscribers. From 51c45829ef69c0cef333073bbc7090cc92e78d94 Mon Sep 17 00:00:00 2001 From: Lunarmagpie Date: Tue, 7 Dec 2021 22:47:42 -0500 Subject: [PATCH 15/17] :sparkles: emoji file uploading --- pincer/objects/guild/guild.py | 83 ++++++++++++++++++++-------------- pincer/objects/message/file.py | 4 ++ 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 44a2c367..b52f8ac2 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -8,10 +8,12 @@ from enum import IntEnum from typing import AsyncGenerator, overload, TYPE_CHECKING +from aiohttp import FormData + from .invite import Invite from .channel import Channel from ..message.emoji import Emoji -from ..message.file import File +from ..message.file import File, create_form from ...exceptions import UnavailableGuildError from ...utils.api_object import APIObject from ...utils.conversion import construct_client_dict, remove_none @@ -1502,7 +1504,6 @@ async def delete_template(self, template: GuildTemplate) -> GuildTemplate: construct_client_dict(self._client, data) ) - async def list_stickers(self) -> AsyncIterator[Sticker]: """|coro| Yields sticker objects for the current guild. @@ -1541,41 +1542,53 @@ async def create_sticker( self, name: str, tags: str, - file, - description: str = "", + description: str, + file: File, reason: Optional[str] = None, ) -> Sticker: - """NOT IMPLEMENTED: DOES NOT WORK""" - raise NotImplementedError - # TODO: Fix this once File is fixed - # """|coro| - # Create a new sticker for the guild. - # Requires the ``MANAGE_EMOJIS_AND_STICKERS permission``. - # - # Parameters - # ---------- - # name : str - # name of the sticker (2-30 characters) - # tags : str - # autocomplete/suggestion tags for the sticker (max 200 characters) - # file : - # the sticker file to upload, must be a PNG, APNG, or Lottie JSON file, max 500 KB - # description : Optional[:class:`str`] - # description of the sticker (empty or 2-100 characters) |default| :data:`""` - # reason : Optional[:class:`str`] |default| :data:`None` - # reason for creating the sticker - # - # Returns - # ------- - # :class:`~pincer.objects.message.sticker.Sticker` - # the newly created sticker - # """ - # sticker = await self._http.post( - # f"guilds/{self.id}/stickers", - # headers=remove_none({"X-Audit-Log-Reason": reason}) - # ) - # - # return Sticker.from_dict(sticker) + """|coro| + Create a new sticker for the guild. + Requires the ``MANAGE_EMOJIS_AND_STICKERS permission``. + + Parameters + ---------- + name : str + name of the sticker (2-30 characters) + tags : str + autocomplete/suggestion tags for the sticker (max 200 characters) + file : :class:`~pincer.objects.message.file.File` + the sticker file to upload, must be a PNG, APNG, or Lottie JSON file, max 500 KB + description : str + description of the sticker (empty or 2-100 characters) |default| :data:`""` + reason : Optional[:class:`str`] |default| :data:`None` + reason for creating the sticker + + Returns + ------- + :class:`~pincer.objects.message.sticker.Sticker` + the newly created sticker + """ # noqa: E501 + + form = FormData() + form.add_field("name", name) + form.add_field("tags", tags) + form.add_field("description", description) + form.add_field( + "file", + file.content, + content_type=file.content_type + ) + + payload = form() + + sticker = await self._http.post( + f"guilds/{self.id}/stickers", + data=payload, + headers=remove_none({"X-Audit-Log-Reason": reason}), + content_type=payload.content_type + ) + + return Sticker.from_dict(sticker) async def delete_sticker(self, _id: Snowflake): """|coro| diff --git a/pincer/objects/message/file.py b/pincer/objects/message/file.py index cdc7e511..28d7cab4 100644 --- a/pincer/objects/message/file.py +++ b/pincer/objects/message/file.py @@ -201,3 +201,7 @@ def uri(self) -> str: encoded_bytes = b64encode(self.content).decode('ascii') return f"data:image/{self.image_format};base64,{encoded_bytes}" + + @property + def content_type(self): + return f"image/{self.image_format}" From 48c142a22ab60b17f179cf0822dae4acd0bc3711 Mon Sep 17 00:00:00 2001 From: Lunarmagpie Date: Tue, 7 Dec 2021 22:49:23 -0500 Subject: [PATCH 16/17] :art: remove unused imports --- pincer/objects/guild/guild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index b52f8ac2..8e11d6bb 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -13,7 +13,7 @@ from .invite import Invite from .channel import Channel from ..message.emoji import Emoji -from ..message.file import File, create_form +from ..message.file import File from ...exceptions import UnavailableGuildError from ...utils.api_object import APIObject from ...utils.conversion import construct_client_dict, remove_none From 3ed81a93847a76f0eee5b9c7bc3f7a9974bb59e7 Mon Sep 17 00:00:00 2001 From: Endercheif <45527309+Endercheif@users.noreply.github.com> Date: Thu, 9 Dec 2021 13:05:28 -0800 Subject: [PATCH 17/17] :bug: Missing await MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit oops. i forgor 💀 --- pincer/objects/message/sticker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pincer/objects/message/sticker.py b/pincer/objects/message/sticker.py index e2745459..56a3cf73 100644 --- a/pincer/objects/message/sticker.py +++ b/pincer/objects/message/sticker.py @@ -142,7 +142,7 @@ async def modify( :class:`~pincer.objects.message.sticker.Sticker` the modified sticker """ - sticker = self._http.patch( + sticker = await self._http.patch( f"guilds/{self.guild_id}/stickers/{self.id}", data=remove_none( {"name": name, "description": description, "tags": tags}