From 859c8d61546ced4a2f63a558700fdd195a1008b8 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:12:21 +0100 Subject: [PATCH 01/21] :sparkles: Add guild sheduled event enpoints --- pincer/objects/guild/__init__.py | 4 +- pincer/objects/guild/guild.py | 115 ++++++++++++++++++++++- pincer/objects/guild/scheduled_events.py | 20 ++++ 3 files changed, 136 insertions(+), 3 deletions(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index 3d1aaf7e..633ef06d 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -22,7 +22,7 @@ from .member import GuildMember, PartialGuildMember, BaseMember from .overwrite import Overwrite from .role import RoleTags, Role -from .scheduled_events import GuildScheduledEventEntityType, EventStatus, ScheduledEvent +from .scheduled_events import GuildScheduledEventEntityType, GuildScheduledEventUser, EventStatus, ScheduledEvent from .stage import PrivacyLevel, StageInstance from .template import GuildTemplate from .thread import ThreadMetadata, ThreadMember @@ -37,7 +37,7 @@ "ChannelMention", "ChannelType", "DefaultMessageNotificationLevel", "EventStatus", "ExplicitContentFilterLevel", "FollowedChannel", "Guild", "GuildFeature", "GuildMember", "GuildNSFWLevel", - "GuildScheduledEventEntityType", "GuildTemplate", "GuildWidget", "Invite", + "GuildScheduledEventEntityType", "GuildScheduledEventUser", "GuildTemplate", "GuildWidget", "Invite", "InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel", "Overwrite", "PartialGuildMember", "PremiumTier", "PrivacyLevel", "Role", "RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags", diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index b6a0f595..52cc9576 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -4,6 +4,7 @@ from __future__ import annotations from dataclasses import dataclass, field +from datetime import datetime from enum import IntEnum from typing import AsyncGenerator, overload, TYPE_CHECKING @@ -28,7 +29,7 @@ from .invite import Invite from .overwrite import Overwrite from .role import Role - from .scheduled_events import ScheduledEvent + from .scheduled_events import ScheduledEvent, GuildScheduledEventUser from .stage import StageInstance from .template import GuildTemplate from .welcome_screen import WelcomeScreen, WelcomeScreenChannel @@ -1962,6 +1963,118 @@ async def get_webhooks(self) -> AsyncGenerator[Webhook, None]: construct_client_dict(self._client, webhook_data) ) + async def get_scheduled_events( + self, with_user_count: bool = False + ) -> AsyncGenerator[ScheduledEvent, None]: + data = await self._http.get(f"guilds/{self.id}/scheduled-events?{with_user_count=!s}") + for event_data in data: + yield ScheduledEvent.from_dict( + construct_client_dict(self._client, event_data) + ) + + async def create_scheduled_event( + self, + name: str, + privacy_level: int, + entity_type: int, + scheduled_start_time: datetime, + scheduled_end_time: Optional[datetime] = None, + entity_metadata: Optional[str] = None, + channel_id: Optional[Snowflake] = None, + description: Optional[str] = None, + reason: Optional[str] = None, + ) -> ScheduledEvent: + if scheduled_start_time.timestamp() < datetime.now().timestamp(): + raise ValueError("An event cannot be created in the past") + + if scheduled_end_time is not None and scheduled_end_time.timestamp() < datetime.now().timestamp(): + raise ValueError("An event cannot start before it ends") + + data = await self._http.post( + f"guilds/{self.id}/scheduled-events", + data={ + "name": name, + "privacy_level": privacy_level, + "entity_type": entity_type, + "scheduled_start_time": scheduled_start_time.isoformat(), + "scheduled_end_time": scheduled_end_time.isoformat() if scheduled_end_time is not None else None, + "entity_metadata": entity_metadata, + "channel_id": channel_id, + "description": description, + }, + headers={"X-Audit-Log-Reason": reason}, + ) + return ScheduledEvent.from_dict( + construct_client_dict(self._client, data) + ) + + async def get_scheduled_event(self, _id: Snowflake, with_user_count: bool = False) -> ScheduledEvent: + data = await self._http.get(f"guilds/{self.id}/scheduled-events/{_id}?{with_user_count=!s}") + return ScheduledEvent.from_dict( + construct_client_dict(self._client, data) + ) + + async def modify_scheduled_event( + self, + _id: Snowflake, + name: Optional[str] = None, + entity_type: Optional[int] = None, + privacy_level: Optional[int] = None, + scheduled_start_time: Optional[datetime] = None, + scheduled_end_time: Optional[datetime] = None, + entity_metadata: Optional[str] = None, + channel_id: Optional[Snowflake] = None, + description: Optional[str] = None, + status: Optional[int] = None, + reason: Optional[str] = None, + ) -> ScheduledEvent: + if scheduled_start_time is not None and scheduled_start_time.timestamp() < datetime.now().timestamp(): + raise ValueError("An event cannot be created in the past") + + if scheduled_end_time is not None and scheduled_end_time.timestamp() < datetime.now().timestamp(): + raise ValueError("An event cannot start before it ends") + + kwargs: Dict[str, str] = remove_none({ + "name": name, + "privacy_level": privacy_level, + "entity_type": entity_type, + "scheduled_start_time": scheduled_start_time.isoformat() if scheduled_start_time is not None else None, + "scheduled_end_time": scheduled_end_time.isoformat() if scheduled_end_time is not None else None, + "entity_metadata": entity_metadata, + "channel_id": channel_id, + "description": description, + "status": status, + }) + + data = await self._http.patch( + f"guilds/{self.id}/scheduled-events/{_id}", + data=kwargs, + headers={"X-Audit-Log-Reason": reason}, + ) + return ScheduledEvent.from_dict( + construct_client_dict(self._client, data) + ) + + async def delete_scheduled_event(self, _id: Snowflake): + await self._http.delete(f"guilds/{self.id}/scheduled-events/{_id}") + + async def get_guild_scheduled_event_users( + self, + _id: Snowflake, + limit: int = 100, + with_member: bool = False, + before: Optional[Snowflake] = None, + after: Optional[Snowflake] = None, + ) -> AsyncGenerator[GuildScheduledEventUser, None]: + data = await self._http.get( + f"guilds/{self.id}/scheduled-events/{_id}/users?{limit=!s}&{with_member=!s}&{before=!s}&{after=!s}", + ) + + for user_data in data: + yield GuildScheduledEventUser.from_dict( + construct_client_dict(self._client, user_data) + ) + @classmethod def from_dict(cls, data) -> Guild: """ diff --git a/pincer/objects/guild/scheduled_events.py b/pincer/objects/guild/scheduled_events.py index 4f9f5eb2..aa35b4de 100644 --- a/pincer/objects/guild/scheduled_events.py +++ b/pincer/objects/guild/scheduled_events.py @@ -11,6 +11,7 @@ if TYPE_CHECKING: from ..guild.stage import PrivacyLevel + from ..guild.member import GuildMember from ..user.user import User from ...utils.snowflake import Snowflake from ...utils.timestamp import Timestamp @@ -112,3 +113,22 @@ class ScheduledEvent(APIObject): entity_metadata: APINullable[str] = MISSING creator: APINullable[User] = MISSING user_count: APINullable[int] = MISSING + + +@dataclass +class GuildScheduledEventUser(APIObject): + """ + Represents a user who has joined a scheduled event. + + Attributes + ---------- + guild_scheduled_event_id: :class:`int` + the scheduled event id which the user subscribed to + user : :class:`~pincer.objects.user.user.User` + user which subscribed to an event + member : :class:`~pincer.objects.guild.member.GuildMember` + guild member data for this user for the guild which this event belongs to, if any + """ + guild_scheduled_event_id: Snowflake + user: User + member: APINullable[GuildMember] = MISSING From c61bff377d8008099b4e5846192191f14227a108 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 17 Jan 2022 16:12:45 +0000 Subject: [PATCH 02/21] :art: Automatic sorting --- pincer/objects/guild/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index 633ef06d..30f85816 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -37,11 +37,12 @@ "ChannelMention", "ChannelType", "DefaultMessageNotificationLevel", "EventStatus", "ExplicitContentFilterLevel", "FollowedChannel", "Guild", "GuildFeature", "GuildMember", "GuildNSFWLevel", - "GuildScheduledEventEntityType", "GuildScheduledEventUser", "GuildTemplate", "GuildWidget", "Invite", - "InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel", - "Overwrite", "PartialGuildMember", "PremiumTier", "PrivacyLevel", "Role", - "RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags", - "TextChannel", "ThreadMember", "ThreadMetadata", "UnavailableGuild", - "VerificationLevel", "VoiceChannel", "Webhook", "WebhookType", - "WelcomeScreen", "WelcomeScreenChannel" + "GuildScheduledEventEntityType", "GuildScheduledEventUser", + "GuildTemplate", "GuildWidget", "Invite", "InviteStageInstance", + "InviteTargetType", "MFALevel", "NewsChannel", "Overwrite", + "PartialGuildMember", "PremiumTier", "PrivacyLevel", "Role", "RoleTags", + "ScheduledEvent", "StageInstance", "SystemChannelFlags", "TextChannel", + "ThreadMember", "ThreadMetadata", "UnavailableGuild", "VerificationLevel", + "VoiceChannel", "Webhook", "WebhookType", "WelcomeScreen", + "WelcomeScreenChannel" ) From 41b2a464344717c2505018b96b4b50155e87391d Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:21:57 +0100 Subject: [PATCH 03/21] :adhesive_bandage: Add imports --- pincer/objects/guild/guild.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 52cc9576..a35f032f 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -11,6 +11,7 @@ from aiohttp import FormData from .channel import Channel, Thread +from .scheduled_events import ScheduledEvent, GuildScheduledEventUser from ..message.file import File from ...exceptions import UnavailableGuildError from ...utils.api_object import APIObject @@ -2066,9 +2067,14 @@ async def get_guild_scheduled_event_users( before: Optional[Snowflake] = None, after: Optional[Snowflake] = None, ) -> AsyncGenerator[GuildScheduledEventUser, None]: - data = await self._http.get( - f"guilds/{self.id}/scheduled-events/{_id}/users?{limit=!s}&{with_member=!s}&{before=!s}&{after=!s}", - ) + url = f"guilds/{self.id}/scheduled-events/{_id}/users?{limit=!s}&{with_member=!s}" + + if before is not None: + url += f"&{before!s}" + if after is not None: + url += f"&{after!s}" + + data = await self._http.get(url) for user_data in data: yield GuildScheduledEventUser.from_dict( From 1bb9f4ffdf06a9bfaa2a0bbcf68cf794669c8e58 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:24:01 +0100 Subject: [PATCH 04/21] :adhesive_bandage: Small fix --- pincer/objects/guild/__init__.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index 30f85816..79256e3a 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -37,12 +37,11 @@ "ChannelMention", "ChannelType", "DefaultMessageNotificationLevel", "EventStatus", "ExplicitContentFilterLevel", "FollowedChannel", "Guild", "GuildFeature", "GuildMember", "GuildNSFWLevel", - "GuildScheduledEventEntityType", "GuildScheduledEventUser", - "GuildTemplate", "GuildWidget", "Invite", "InviteStageInstance", - "InviteTargetType", "MFALevel", "NewsChannel", "Overwrite", - "PartialGuildMember", "PremiumTier", "PrivacyLevel", "Role", "RoleTags", - "ScheduledEvent", "StageInstance", "SystemChannelFlags", "TextChannel", - "ThreadMember", "ThreadMetadata", "UnavailableGuild", "VerificationLevel", - "VoiceChannel", "Webhook", "WebhookType", "WelcomeScreen", - "WelcomeScreenChannel" + "GuildScheduledEventEntityType", "GuildScheduledEventUser", "GuildTemplate", "GuildWidget", "Invite", + "InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel", + "Overwrite", "PartialGuildMember", "Permissions", "PremiumTier", + "PrivacyLevel", "Role", "RoleTags", "ScheduledEvent", "StageInstance", + "SystemChannelFlags", "TextChannel", "ThreadMember", "ThreadMetadata", + "UnavailableGuild", "VerificationLevel", "VoiceChannel", "Webhook", + "WebhookType", "WelcomeScreen", "WelcomeScreenChannel" ) From 6d615f92c8329eaca80c47233855838e0a07fce4 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 17 Jan 2022 16:24:18 +0000 Subject: [PATCH 05/21] :art: Automatic sorting --- pincer/objects/guild/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index 79256e3a..949efbbc 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -37,11 +37,12 @@ "ChannelMention", "ChannelType", "DefaultMessageNotificationLevel", "EventStatus", "ExplicitContentFilterLevel", "FollowedChannel", "Guild", "GuildFeature", "GuildMember", "GuildNSFWLevel", - "GuildScheduledEventEntityType", "GuildScheduledEventUser", "GuildTemplate", "GuildWidget", "Invite", - "InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel", - "Overwrite", "PartialGuildMember", "Permissions", "PremiumTier", - "PrivacyLevel", "Role", "RoleTags", "ScheduledEvent", "StageInstance", - "SystemChannelFlags", "TextChannel", "ThreadMember", "ThreadMetadata", - "UnavailableGuild", "VerificationLevel", "VoiceChannel", "Webhook", - "WebhookType", "WelcomeScreen", "WelcomeScreenChannel" + "GuildScheduledEventEntityType", "GuildScheduledEventUser", + "GuildTemplate", "GuildWidget", "Invite", "InviteStageInstance", + "InviteTargetType", "MFALevel", "NewsChannel", "Overwrite", + "PartialGuildMember", "Permissions", "PremiumTier", "PrivacyLevel", "Role", + "RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags", + "TextChannel", "ThreadMember", "ThreadMetadata", "UnavailableGuild", + "VerificationLevel", "VoiceChannel", "Webhook", "WebhookType", + "WelcomeScreen", "WelcomeScreenChannel" ) From 714279b307c79eec6706c43eee9160dd7ca63fd2 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 17 Jan 2022 16:30:16 +0000 Subject: [PATCH 06/21] :art: Automatic sorting --- pincer/objects/guild/__init__.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index 27c15bad..d5c99210 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -44,12 +44,6 @@ "PrivacyLevel", "Role", "RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags", "TextChannel", "ThreadMember", "ThreadMetadata", "UnavailableGuild", "VerificationLevel", "VoiceChannel", "Webhook", - "WebhookType", "WelcomeScreen", "WelcomeScreenChannel" - "GuildScheduledEventEntityType", "GuildTemplate", "GuildWidget", "Invite", - "InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel", - "Overwrite", "PartialGuildMember", "Permissions", "PremiumTier", - "PrivacyLevel", "Role", "RoleTags", "ScheduledEvent", "StageInstance", - "SystemChannelFlags", "TextChannel", "ThreadMember", "ThreadMetadata", - "UnavailableGuild", "VerificationLevel", "VoiceChannel", "Webhook", - "WebhookType", "WelcomeScreen", "WelcomeScreenChannel" + "WebhookType", "WelcomeScreen", "WelcomeScreenChannel", + "WelcomeScreenChannelGuildScheduledEventEntityType" ) From b4c3475a3377116000fb515c488611b9306caf95 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:33:59 +0100 Subject: [PATCH 07/21] :art: Format with black --- pincer/objects/guild/guild.py | 172 +++++++++++++++++----------------- 1 file changed, 84 insertions(+), 88 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index a35f032f..bcd0cc71 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -498,13 +498,15 @@ async def modify_member( """ ... - async def modify_member(self, _id: int, reason=None, **kwargs) -> GuildMember: + async def modify_member( + self, _id: int, reason=None, **kwargs + ) -> GuildMember: if kwargs.get("communication_disabled_until") is MISSING: kwargs.pop("communication_disabled_until") data = await self._http.patch( f"guilds/{self.id}/members/{_id}", data=kwargs, - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) return GuildMember.from_dict(construct_client_dict(self._client, data)) @@ -521,7 +523,7 @@ async def create_channel( position: Optional[int] = None, permission_overwrites: Optional[List[Overwrite]] = None, parent_id: Optional[Snowflake] = None, - nsfw: Optional[bool] = None + nsfw: Optional[bool] = None, ) -> Channel: """|coro| Create a new channel object for the guild. @@ -560,23 +562,18 @@ async def create_channel( """ ... - async def create_channel( - self, - *, - reason: Optional[str] = None, - **kwargs - ): + async def create_channel(self, *, reason: Optional[str] = None, **kwargs): data = await self._http.post( f"guilds/{self.id}/channels", data=kwargs, - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) return Channel.from_dict(construct_client_dict(self._client, data)) async def modify_channel_positions( self, reason: Optional[str] = None, - *channel: Dict[str, Optional[Union[int, bool, Snowflake]]] + *channel: Dict[str, Optional[Union[int, bool, Snowflake]]], ): """|coro| Create a new channel object for the guild. @@ -595,11 +592,12 @@ async def modify_channel_positions( await self._http.patch( f"guilds/{self.id}/channels", data=channel, - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) - async def list_active_threads(self) -> Tuple[ - Generator[Thread], Generator[GuildMember]]: + async def list_active_threads( + self, + ) -> Tuple[Generator[Thread], Generator[GuildMember]]: """|coro| Returns all active threads in the guild, including public and private threads. @@ -623,9 +621,7 @@ async def list_active_threads(self) -> Tuple[ return threads, members async def list_guild_members( - self, - limit: int = 1, - after: int = 0 + self, limit: int = 1, after: int = 0 ) -> AsyncIterator[GuildMember]: """|coro| Returns a list of guild member objects that are members of the guild. @@ -644,11 +640,7 @@ async def list_guild_members( """ members = await self._http.get( - f"guilds/{self.id}/members", - params={ - "limit": limit, - "after": after - } + f"guilds/{self.id}/members", params={"limit": limit, "after": after} ) for member in members: @@ -657,9 +649,7 @@ async def list_guild_members( ) async def search_guild_members( - self, - query: str, - limit: Optional[int] = None + self, query: str, limit: Optional[int] = None ) -> AsyncIterator[GuildMember]: """|coro| Returns a list of guild member objects whose @@ -680,18 +670,18 @@ async def search_guild_members( data = await self._http.get( f"guilds/{self.id}/members/search", - params={ - "query": query, - "limit": limit - } + params={"query": query, "limit": limit}, ) for member in data: - yield GuildMember.from_dict(construct_client_dict(self._client, member)) + yield GuildMember.from_dict( + construct_client_dict(self._client, member) + ) @overload async def add_guild_member( - self, *, + self, + *, user_id: Snowflake, access_token: str, nick: Optional[str] = None, @@ -729,26 +719,21 @@ async def add_guild_member( If the user is in the guild """ - async def add_guild_member( - self, - user_id, - reason=None, - **kwargs - ): + async def add_guild_member(self, user_id, reason=None, **kwargs): data = await self._http.put( f"guilds/{self.id}/members/{user_id}", data=kwargs, - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) - return GuildMember.from_dict( - construct_client_dict(self._client, data) - ) if data else None + return ( + GuildMember.from_dict(construct_client_dict(self._client, data)) + if data + else None + ) async def modify_current_member( - self, - nick: str, - reason: Optional[str] = None + self, nick: str, reason: Optional[str] = None ) -> GuildMember: """|coro| Modifies the current member in a guild. @@ -767,15 +752,12 @@ async def modify_current_member( data = self._http.patch( f"guilds/{self.id}/members/@me", {"nick": nick}, - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) return GuildMember.from_dict(construct_client_dict(self._client, data)) async def add_guild_member_role( - self, - user_id: int, - role_id: int, - reason: Optional[str] = None + self, user_id: int, role_id: int, reason: Optional[str] = None ) -> None: """|coro| Adds a role to a guild member. @@ -791,14 +773,11 @@ async def add_guild_member_role( """ data = await self._http.put( f"guilds/{self.id}/{user_id}/roles/{role_id}", - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) async def remove_guild_member_role( - self, - user_id: int, - role_id: int, - reason: Optional[str] = None + self, user_id: int, role_id: int, reason: Optional[str] = None ): """|coro| Removes a role from a guild member. @@ -814,13 +793,11 @@ async def remove_guild_member_role( """ await self._http.delete( f"guilds/{self.id}/{user_id}/roles/{role_id}", - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) async def remove_guild_member( - self, - user_id: int, - reason: Optional[str] = None + self, user_id: int, reason: Optional[str] = None ): """|coro| Remove a member from a guild. @@ -834,7 +811,7 @@ async def remove_guild_member( """ await self._http.delete( f"guilds/{self.id}/members/{user_id}", - headers={"X-Audit-Log-Reason": reason} + headers={"X-Audit-Log-Reason": reason}, ) async def ban( @@ -1920,11 +1897,7 @@ async def create_sticker( 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 - ) + form.add_field("file", file.content, content_type=file.content_type) payload = form() @@ -1932,7 +1905,7 @@ async def create_sticker( f"guilds/{self.id}/stickers", data=payload, headers={"X-Audit-Log-Reason": reason}, - content_type=payload.content_type + content_type=payload.content_type, ) return Sticker.from_dict(sticker) @@ -1966,8 +1939,10 @@ async def get_webhooks(self) -> AsyncGenerator[Webhook, None]: async def get_scheduled_events( self, with_user_count: bool = False - ) -> AsyncGenerator[ScheduledEvent, None]: - data = await self._http.get(f"guilds/{self.id}/scheduled-events?{with_user_count=!s}") + ) -> AsyncGenerator[ScheduledEvent, None]: + data = await self._http.get( + f"guilds/{self.id}/scheduled-events?{with_user_count=!s}" + ) for event_data in data: yield ScheduledEvent.from_dict( construct_client_dict(self._client, event_data) @@ -1988,7 +1963,10 @@ async def create_scheduled_event( if scheduled_start_time.timestamp() < datetime.now().timestamp(): raise ValueError("An event cannot be created in the past") - if scheduled_end_time is not None and scheduled_end_time.timestamp() < datetime.now().timestamp(): + if ( + scheduled_end_time is not None + and scheduled_end_time.timestamp() < datetime.now().timestamp() + ): raise ValueError("An event cannot start before it ends") data = await self._http.post( @@ -1998,19 +1976,25 @@ async def create_scheduled_event( "privacy_level": privacy_level, "entity_type": entity_type, "scheduled_start_time": scheduled_start_time.isoformat(), - "scheduled_end_time": scheduled_end_time.isoformat() if scheduled_end_time is not None else None, + "scheduled_end_time": scheduled_end_time.isoformat() + if scheduled_end_time is not None + else None, "entity_metadata": entity_metadata, "channel_id": channel_id, "description": description, - }, + }, headers={"X-Audit-Log-Reason": reason}, - ) + ) return ScheduledEvent.from_dict( construct_client_dict(self._client, data) ) - async def get_scheduled_event(self, _id: Snowflake, with_user_count: bool = False) -> ScheduledEvent: - data = await self._http.get(f"guilds/{self.id}/scheduled-events/{_id}?{with_user_count=!s}") + async def get_scheduled_event( + self, _id: Snowflake, with_user_count: bool = False + ) -> ScheduledEvent: + data = await self._http.get( + f"guilds/{self.id}/scheduled-events/{_id}?{with_user_count=!s}" + ) return ScheduledEvent.from_dict( construct_client_dict(self._client, data) ) @@ -2029,29 +2013,41 @@ async def modify_scheduled_event( status: Optional[int] = None, reason: Optional[str] = None, ) -> ScheduledEvent: - if scheduled_start_time is not None and scheduled_start_time.timestamp() < datetime.now().timestamp(): + if ( + scheduled_start_time is not None + and scheduled_start_time.timestamp() < datetime.now().timestamp() + ): raise ValueError("An event cannot be created in the past") - if scheduled_end_time is not None and scheduled_end_time.timestamp() < datetime.now().timestamp(): + if ( + scheduled_end_time is not None + and scheduled_end_time.timestamp() < datetime.now().timestamp() + ): raise ValueError("An event cannot start before it ends") - kwargs: Dict[str, str] = remove_none({ - "name": name, - "privacy_level": privacy_level, - "entity_type": entity_type, - "scheduled_start_time": scheduled_start_time.isoformat() if scheduled_start_time is not None else None, - "scheduled_end_time": scheduled_end_time.isoformat() if scheduled_end_time is not None else None, - "entity_metadata": entity_metadata, - "channel_id": channel_id, - "description": description, - "status": status, - }) + kwargs: Dict[str, str] = remove_none( + { + "name": name, + "privacy_level": privacy_level, + "entity_type": entity_type, + "scheduled_start_time": scheduled_start_time.isoformat() + if scheduled_start_time is not None + else None, + "scheduled_end_time": scheduled_end_time.isoformat() + if scheduled_end_time is not None + else None, + "entity_metadata": entity_metadata, + "channel_id": channel_id, + "description": description, + "status": status, + } + ) data = await self._http.patch( f"guilds/{self.id}/scheduled-events/{_id}", data=kwargs, headers={"X-Audit-Log-Reason": reason}, - ) + ) return ScheduledEvent.from_dict( construct_client_dict(self._client, data) ) @@ -2066,7 +2062,7 @@ async def get_guild_scheduled_event_users( with_member: bool = False, before: Optional[Snowflake] = None, after: Optional[Snowflake] = None, - ) -> AsyncGenerator[GuildScheduledEventUser, None]: + ) -> AsyncGenerator[GuildScheduledEventUser, None]: url = f"guilds/{self.id}/scheduled-events/{_id}/users?{limit=!s}&{with_member=!s}" if before is not None: From 14e4be7a1d5cfb7ad48344dd53f02ee42a5f9cd8 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:34:31 +0100 Subject: [PATCH 08/21] :label: Fix types Co-authored-by: Yohann Boniface --- 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 72bfc25f..3d56ec01 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -2010,7 +2010,7 @@ async def modify_scheduled_event( construct_client_dict(self._client, data) ) - async def delete_scheduled_event(self, _id: Snowflake): + async def delete_scheduled_event(self, _id: Union[int, Snowflake]): await self._http.delete(f"guilds/{self.id}/scheduled-events/{_id}") async def get_guild_scheduled_event_users( From fdba57d84560a71d4a94e39f60f57b75b3d55177 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:36:49 +0100 Subject: [PATCH 09/21] :recycle: Code refactor --- pincer/objects/guild/guild.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index bcd0cc71..a5267e19 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -2013,17 +2013,13 @@ async def modify_scheduled_event( status: Optional[int] = None, reason: Optional[str] = None, ) -> ScheduledEvent: - if ( - scheduled_start_time is not None - and scheduled_start_time.timestamp() < datetime.now().timestamp() - ): - raise ValueError("An event cannot be created in the past") + if scheduled_start_time: + timestamp = scheduled_start_time.timestamp() + if timestamp < datetime.now().timestamp(): + raise ValueError("An event cannot be created in the past") - if ( - scheduled_end_time is not None - and scheduled_end_time.timestamp() < datetime.now().timestamp() - ): - raise ValueError("An event cannot start before it ends") + if scheduled_end_time and timestamp > scheduled_end_time.timestamp(): + raise ValueError("An event cannot start before it ends") kwargs: Dict[str, str] = remove_none( { From 970bf75351c99c918693ed590167bb047b0167cd Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:41:13 +0100 Subject: [PATCH 10/21] :recycle: Code refactor --- pincer/objects/guild/guild.py | 208 +++++++++++++++------------------- 1 file changed, 90 insertions(+), 118 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index a5267e19..6648399c 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -15,7 +15,6 @@ 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 ...utils.types import MISSING if TYPE_CHECKING: @@ -107,7 +106,7 @@ class ExplicitContentFilterLevel(IntEnum): class MFALevel(IntEnum): - """Represents the multi factor authentication level of a guild. + """Represents the multi-factor authentication level of a guild. Attributes ---------- NONE: @@ -416,7 +415,12 @@ class Guild(APIObject): welcome_screen: APINullable[WelcomeScreen] = MISSING @classmethod - async def from_id(cls, client: Client, _id: Union[int, Snowflake]) -> Guild: + async def from_id( + cls, + client: Client, + _id: Union[int, Snowflake], + with_counts: bool = False, + ) -> Guild: """ Parameters ---------- @@ -429,15 +433,18 @@ async def from_id(cls, client: Client, _id: Union[int, Snowflake]) -> Guild: :class:`~pincer.objects.guild.guild.Guild` The new guild object. """ - data = await client.http.get(f"/guilds/{_id}") + data = await client.http.get( + f"/guilds/{_id}", + # Yarl don't support boolean params + params={"with_counts": "true" if with_counts else None}, + ) channel_data = await client.http.get(f"/guilds/{_id}/channels") data["channels"]: List[Channel] = [ - Channel.from_dict(construct_client_dict(client, i)) - for i in (channel_data or []) + Channel.from_dict(i) for i in (channel_data or []) ] - return Guild.from_dict(construct_client_dict(client, data)) + return Guild.from_dict(data) async def get_member(self, _id: int) -> GuildMember: """|coro| @@ -508,7 +515,7 @@ async def modify_member( data=kwargs, headers={"X-Audit-Log-Reason": reason}, ) - return GuildMember.from_dict(construct_client_dict(self._client, data)) + return GuildMember.from_dict(data) @overload async def create_channel( @@ -568,7 +575,7 @@ async def create_channel(self, *, reason: Optional[str] = None, **kwargs): data=kwargs, headers={"X-Audit-Log-Reason": reason}, ) - return Channel.from_dict(construct_client_dict(self._client, data)) + return Channel.from_dict(data) async def modify_channel_positions( self, @@ -609,14 +616,8 @@ async def list_active_threads( """ data = await self._http.get(f"guilds/{self.id}/threads/active") - threads = ( - Channel.from_dict(construct_client_dict(self._client, channel)) - for channel in data["threads"] - ) - members = ( - GuildMember.from_dict(construct_client_dict(self._client, member)) - for member in data["members"] - ) + threads = (Channel.from_dict(channel) for channel in data["threads"]) + members = (GuildMember.from_dict(member) for member in data["members"]) return threads, members @@ -644,9 +645,7 @@ async def list_guild_members( ) for member in members: - yield GuildMember.from_dict( - construct_client_dict(self._client, member) - ) + yield GuildMember.from_dict(member) async def search_guild_members( self, query: str, limit: Optional[int] = None @@ -674,9 +673,7 @@ async def search_guild_members( ) for member in data: - yield GuildMember.from_dict( - construct_client_dict(self._client, member) - ) + yield GuildMember.from_dict(member) @overload async def add_guild_member( @@ -726,11 +723,7 @@ async def add_guild_member(self, user_id, reason=None, **kwargs): headers={"X-Audit-Log-Reason": reason}, ) - return ( - GuildMember.from_dict(construct_client_dict(self._client, data)) - if data - else None - ) + return GuildMember.from_dict(data) if data else None async def modify_current_member( self, nick: str, reason: Optional[str] = None @@ -754,7 +747,7 @@ async def modify_current_member( {"nick": nick}, headers={"X-Audit-Log-Reason": reason}, ) - return GuildMember.from_dict(construct_client_dict(self._client, data)) + return GuildMember.from_dict(data) async def add_guild_member_role( self, user_id: int, role_id: int, reason: Optional[str] = None @@ -875,7 +868,7 @@ async def get_roles(self) -> AsyncGenerator[Role, None]: """ data = await self._http.get(f"guilds/{self.id}/roles") for role_data in data: - yield Role.from_dict(construct_client_dict(self._client, role_data)) + yield Role.from_dict(role_data) @overload async def create_role( @@ -927,13 +920,10 @@ async def create_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={"X-Audit-Log-Reason": reason}, - ), + await self._http.post( + f"guilds/{self.id}/roles", + data=kwargs, + headers={"X-Audit-Log-Reason": reason}, ) ) @@ -966,7 +956,7 @@ async def edit_role_position( headers={"X-Audit-Log-Reason": reason}, ) for role_data in data: - yield Role.from_dict(construct_client_dict(self._client, role_data)) + yield Role.from_dict(role_data) @overload async def edit_role( @@ -1022,13 +1012,10 @@ async def edit_role( self, id: Snowflake, reason: Optional[str] = None, **kwargs ) -> Role: return Role.from_dict( - construct_client_dict( - self._client, - await self._http.patch( - f"guilds/{self.id}/roles/{id}", - data=kwargs, - headers={"X-Audit-Log-Reason": reason}, - ), + await self._http.patch( + f"guilds/{self.id}/roles/{id}", + data=kwargs, + headers={"X-Audit-Log-Reason": reason}, ) ) @@ -1060,7 +1047,7 @@ async def get_bans(self) -> AsyncGenerator[Ban, None]: """ data = await self._http.get(f"guilds/{self.id}/bans") for ban_data in data: - yield Ban.from_dict(construct_client_dict(self._client, ban_data)) + yield Ban.from_dict(ban_data) async def get_ban(self, id: Snowflake) -> Ban: """|coro| @@ -1077,10 +1064,7 @@ async def get_ban(self, id: Snowflake) -> Ban: The Ban object. """ return Ban.from_dict( - construct_client_dict( - self._client, - await self._http.get(f"guilds/{self.id}/bans/{id}"), - ) + await self._http.get(f"guilds/{self.id}/bans/{id}") ) async def unban(self, id: Snowflake, reason: Optional[str] = None): @@ -1185,7 +1169,7 @@ async def edit( async def edit(self, **kwargs) -> Guild: g = await self._http.patch(f"guilds/{self.id}", data=kwargs) - return Guild.from_dict(construct_client_dict(self._client, g)) + return Guild.from_dict(g) async def preview(self) -> GuildPreview: """|coro| @@ -1281,9 +1265,7 @@ 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(voice_region_data) async def get_invites(self) -> AsyncGenerator[Invite, None]: """|coro| @@ -1297,9 +1279,24 @@ 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(invite_data) + + async def get_invite(self, code: str) -> Invite: + """|coro| + Returns an Invite object for the given invite code. + + Parameters + ---------- + code : :class:`str` + The invite code to get the invite for. + + Returns + ------- + :class:`~pincer.objects.guild.invite.Invite` + The invite object. + """ + data = await self._http.get(f"invite/{code}") + return Invite.from_dict(data) async def get_integrations(self) -> AsyncIterator[Integration]: """|coro| @@ -1313,9 +1310,7 @@ async def get_integrations(self) -> AsyncIterator[Integration]: """ 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(integration_data) async def delete_integration( self, integration: Integration, reason: Optional[str] = None @@ -1336,6 +1331,18 @@ async def delete_integration( headers={"X-Audit-Log-Reason": reason}, ) + async def delete_invite(self, code: str): + """|coro| + Deletes an invite. + Requires the ``MANAGE_GUILD`` intent. + + Parameters + ---------- + code : :class:`str` + The code of the invite to delete. + """ + await self._http.delete(f"guilds/{self.id}/invites/{code}") + async def get_widget_settings(self) -> GuildWidget: """|coro| Returns the guild widget settings. @@ -1347,9 +1354,7 @@ async def get_widget_settings(self) -> GuildWidget: The guild widget settings. """ return GuildWidget.from_dict( - construct_client_dict( - self._client, await self._http.get(f"guilds/{self.id}/widget") - ) + await self._http.get(f"guilds/{self.id}/widget") ) async def modify_widget( @@ -1376,7 +1381,7 @@ async def modify_widget( data=kwargs, headers={"X-Audit-Log-Reason": reason}, ) - return GuildWidget.from_dict(construct_client_dict(self._client, data)) + return GuildWidget.from_dict(data) async def get_widget(self) -> Dict[str, JSONSerializable]: """|coro| @@ -1397,7 +1402,7 @@ async def vanity_url(self) -> Invite: The vanity url for the guild. """ data = await self._http.get(f"guilds/{self.id}/vanity-url") - return Invite.from_dict(construct_client_dict(self._client, data)) + return Invite.from_dict(data) async def get_widget_image( self, style: Optional[str] = "shield" @@ -1446,9 +1451,7 @@ 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(data) async def modify_welcome_screen( self, @@ -1488,9 +1491,7 @@ async def modify_welcome_screen( }, headers={"X-Audit-Log-Reason": reason}, ) - return WelcomeScreen.from_dict( - construct_client_dict(self._client, data) - ) + return WelcomeScreen.from_dict(data) async def modify_current_user_voice_state( self, @@ -1571,10 +1572,7 @@ async def get_audit_log(self) -> AuditLog: The audit log object for the guild. """ 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") ) async def get_emojis(self) -> AsyncGenerator[Emoji, None]: @@ -1588,9 +1586,7 @@ async def get_emojis(self) -> AsyncGenerator[Emoji, None]: """ data = await self._http.get(f"guilds/{self.id}/emojis") for emoji_data in data: - yield Emoji.from_dict( - construct_client_dict(self._client, emoji_data) - ) + yield Emoji.from_dict(emoji_data) async def get_emoji(self, id: Snowflake) -> Emoji: """|coro| @@ -1607,10 +1603,7 @@ async def get_emoji(self, id: Snowflake) -> Emoji: The emoji object. """ 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}") ) async def create_emoji( @@ -1651,7 +1644,7 @@ async def create_emoji( data={"name": name, "image": image.uri, "roles": roles}, headers={"X-Audit-Log-Reason": reason}, ) - return Emoji.from_dict(construct_client_dict(self._client, data)) + return Emoji.from_dict(data) async def edit_emoji( self, @@ -1686,7 +1679,7 @@ async def edit_emoji( data={"name": name, "roles": roles}, headers={"X-Audit-Log-Reason": reason}, ) - return Emoji.from_dict(construct_client_dict(self._client, data)) + return Emoji.from_dict(data) async def delete_emoji( self, id: Snowflake, *, reason: Optional[str] = None @@ -1718,9 +1711,7 @@ async def get_templates(self) -> AsyncIterator[GuildTemplate]: """ data = await self._http.get(f"guilds/{self.id}/templates") for template_data in data: - yield GuildTemplate.from_dict( - construct_client_dict(self._client, template_data) - ) + yield GuildTemplate.from_dict(template_data) async def create_template( self, name: str, description: Optional[str] = None @@ -1745,9 +1736,7 @@ async def create_template( f"guilds/{self.id}/templates", data={"name": name, "description": description}, ) - return GuildTemplate.from_dict( - construct_client_dict(self._client, data) - ) + return GuildTemplate.from_dict(data) async def sync_template(self, template: GuildTemplate) -> GuildTemplate: """|coro| @@ -1767,9 +1756,7 @@ async def sync_template(self, template: GuildTemplate) -> GuildTemplate: data = await self._http.put( f"guilds/{self.id}/templates/{template.code}" ) - return GuildTemplate.from_dict( - construct_client_dict(self._client, data) - ) + return GuildTemplate.from_dict(data) async def edit_template( self, @@ -1802,9 +1789,7 @@ async def edit_template( f"guilds/{self.id}/templates/{template.code}", data={"name": name, "description": description}, ) - return GuildTemplate.from_dict( - construct_client_dict(self._client, data) - ) + return GuildTemplate.from_dict(data) async def delete_template(self, template: GuildTemplate) -> GuildTemplate: """|coro| @@ -1824,9 +1809,7 @@ async def delete_template(self, template: GuildTemplate) -> GuildTemplate: data = await self._http.delete( f"guilds/{self.id}/templates/{template.code}" ) - return GuildTemplate.from_dict( - construct_client_dict(self._client, data) - ) + return GuildTemplate.from_dict(data) async def list_stickers(self) -> AsyncIterator[Sticker]: """|coro| @@ -1933,9 +1916,7 @@ async def get_webhooks(self) -> AsyncGenerator[Webhook, None]: """ data = await self._http.get(f"guilds/{self.id}/webhooks") for webhook_data in data: - yield Webhook.from_dict( - construct_client_dict(self._client, webhook_data) - ) + yield Webhook.from_dict(webhook_data) async def get_scheduled_events( self, with_user_count: bool = False @@ -1944,9 +1925,7 @@ async def get_scheduled_events( f"guilds/{self.id}/scheduled-events?{with_user_count=!s}" ) for event_data in data: - yield ScheduledEvent.from_dict( - construct_client_dict(self._client, event_data) - ) + yield ScheduledEvent.from_dict(event_data) async def create_scheduled_event( self, @@ -1985,9 +1964,7 @@ async def create_scheduled_event( }, headers={"X-Audit-Log-Reason": reason}, ) - return ScheduledEvent.from_dict( - construct_client_dict(self._client, data) - ) + return ScheduledEvent.from_dict(data) async def get_scheduled_event( self, _id: Snowflake, with_user_count: bool = False @@ -1995,9 +1972,8 @@ async def get_scheduled_event( data = await self._http.get( f"guilds/{self.id}/scheduled-events/{_id}?{with_user_count=!s}" ) - return ScheduledEvent.from_dict( - construct_client_dict(self._client, data) - ) + return ScheduledEvent.from_dict(self._client, data) + async def modify_scheduled_event( self, @@ -2044,11 +2020,9 @@ async def modify_scheduled_event( data=kwargs, headers={"X-Audit-Log-Reason": reason}, ) - return ScheduledEvent.from_dict( - construct_client_dict(self._client, data) - ) + return ScheduledEvent.from_dict(self._client, data) - async def delete_scheduled_event(self, _id: Snowflake): + async def delete_scheduled_event(self, _id: Union[int, Snowflake]): await self._http.delete(f"guilds/{self.id}/scheduled-events/{_id}") async def get_guild_scheduled_event_users( @@ -2069,9 +2043,7 @@ async def get_guild_scheduled_event_users( data = await self._http.get(url) for user_data in data: - yield GuildScheduledEventUser.from_dict( - construct_client_dict(self._client, user_data) - ) + yield GuildScheduledEventUser.from_dict(self._client, user_data) @classmethod def from_dict(cls, data) -> Guild: From 8cdac5ead1bc3d7ee04c94a8639c0471beff7ea2 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:43:26 +0100 Subject: [PATCH 11/21] :adhesive_bandage: Fix import --- pincer/objects/guild/guild.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 6648399c..498c5a08 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -14,6 +14,7 @@ from .scheduled_events import ScheduledEvent, GuildScheduledEventUser from ..message.file import File from ...exceptions import UnavailableGuildError +from ...utils import remove_none from ...utils.api_object import APIObject from ...utils.types import MISSING From 0593f1a05df5367f5236e4dd38ead7d3c9c08974 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Mon, 17 Jan 2022 21:44:08 +0100 Subject: [PATCH 12/21] :recycle: Small refactors --- pincer/objects/guild/guild.py | 30 +++++++++++++++--------- pincer/objects/guild/scheduled_events.py | 16 ++++++------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 498c5a08..37a92a17 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1971,10 +1971,10 @@ async def get_scheduled_event( self, _id: Snowflake, with_user_count: bool = False ) -> ScheduledEvent: data = await self._http.get( - f"guilds/{self.id}/scheduled-events/{_id}?{with_user_count=!s}" + f"guilds/{self.id}/scheduled-events/{_id}", + params={"with_user_count": with_user_count}, ) - return ScheduledEvent.from_dict(self._client, data) - + return ScheduledEvent.from_dict(data) async def modify_scheduled_event( self, @@ -1995,7 +1995,10 @@ async def modify_scheduled_event( if timestamp < datetime.now().timestamp(): raise ValueError("An event cannot be created in the past") - if scheduled_end_time and timestamp > scheduled_end_time.timestamp(): + if ( + scheduled_end_time + and timestamp > scheduled_end_time.timestamp() + ): raise ValueError("An event cannot start before it ends") kwargs: Dict[str, str] = remove_none( @@ -2021,7 +2024,7 @@ async def modify_scheduled_event( data=kwargs, headers={"X-Audit-Log-Reason": reason}, ) - return ScheduledEvent.from_dict(self._client, data) + return ScheduledEvent.from_dict(data) async def delete_scheduled_event(self, _id: Union[int, Snowflake]): await self._http.delete(f"guilds/{self.id}/scheduled-events/{_id}") @@ -2034,17 +2037,22 @@ async def get_guild_scheduled_event_users( before: Optional[Snowflake] = None, after: Optional[Snowflake] = None, ) -> AsyncGenerator[GuildScheduledEventUser, None]: - url = f"guilds/{self.id}/scheduled-events/{_id}/users?{limit=!s}&{with_member=!s}" - + params = { + "limit": limit, + "with_member": with_member, + } if before is not None: - url += f"&{before!s}" + params.update({"before": before}) if after is not None: - url += f"&{after!s}" + params.update({"after": after}) - data = await self._http.get(url) + data = await self._http.get( + f"guilds/{self.id}/scheduled-events/{_id}/users?", + params=params, + ) for user_data in data: - yield GuildScheduledEventUser.from_dict(self._client, user_data) + yield GuildScheduledEventUser.from_dict(user_data) @classmethod def from_dict(cls, data) -> Guild: diff --git a/pincer/objects/guild/scheduled_events.py b/pincer/objects/guild/scheduled_events.py index aa35b4de..d4172875 100644 --- a/pincer/objects/guild/scheduled_events.py +++ b/pincer/objects/guild/scheduled_events.py @@ -78,22 +78,22 @@ class ScheduledEvent(APIObject): The status of the scheduled event. entity_type: :class:`~pincer.guild.schedule_events.GuildScheduledEventEntityType` The type of the scheduled event - channel_id: :class:`int` + channel_id: APINullable[:class:`int`] The channel id in which the scheduled event will be hosted, or null if scheduled entity type is EXTERNAL - creator_id: :class:`int` + creator_id: APINullable[:class:`int`] The user id of the creator of the scheduled event scheduled_end_time: str The time the scheduled event will end, required if entity_type is EXTERNAL - description: :class:`str` + description: APINullable[:class:`str`] The description of the scheduled event (0-1000 characters) - entity_id: :class:`int` + entity_id: APINullable[:class:`int`] The id of an entity associated with a guild scheduled event - entity_metadata: :class:`str` + entity_metadata: APINullable[:class:`str`] Additional metadata for the guild scheduled event - creator: :class:`~pincer.objects.user.user.User` + creator: APINullable[:class:`~pincer.objects.user.user.User`] The user who created the scheduled event - user_count: :class:`int` + user_count: APINullable[:class:`int`] The number of users who have joined the scheduled event """ id: Snowflake @@ -126,7 +126,7 @@ class GuildScheduledEventUser(APIObject): the scheduled event id which the user subscribed to user : :class:`~pincer.objects.user.user.User` user which subscribed to an event - member : :class:`~pincer.objects.guild.member.GuildMember` + member : APINullable[:class:`~pincer.objects.guild.member.GuildMember`] guild member data for this user for the guild which this event belongs to, if any """ guild_scheduled_event_id: Snowflake From bc79969c1468043800ef077f3891eb0c439b0e35 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Tue, 18 Jan 2022 13:57:27 +0100 Subject: [PATCH 13/21] :label: Fix types --- pincer/objects/guild/guild.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 37a92a17..84f19ca6 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1968,7 +1968,7 @@ async def create_scheduled_event( return ScheduledEvent.from_dict(data) async def get_scheduled_event( - self, _id: Snowflake, with_user_count: bool = False + self, _id: int, with_user_count: bool = False ) -> ScheduledEvent: data = await self._http.get( f"guilds/{self.id}/scheduled-events/{_id}", @@ -1978,14 +1978,14 @@ async def get_scheduled_event( async def modify_scheduled_event( self, - _id: Snowflake, + _id: int, name: Optional[str] = None, entity_type: Optional[int] = None, privacy_level: Optional[int] = None, scheduled_start_time: Optional[datetime] = None, scheduled_end_time: Optional[datetime] = None, entity_metadata: Optional[str] = None, - channel_id: Optional[Snowflake] = None, + channel_id: Optional[int] = None, description: Optional[str] = None, status: Optional[int] = None, reason: Optional[str] = None, @@ -2031,7 +2031,7 @@ async def delete_scheduled_event(self, _id: Union[int, Snowflake]): async def get_guild_scheduled_event_users( self, - _id: Snowflake, + _id: int, limit: int = 100, with_member: bool = False, before: Optional[Snowflake] = None, From 8145af6d11ee3ae0a44eddc2e39322751fd7a5d1 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Tue, 18 Jan 2022 14:14:09 +0100 Subject: [PATCH 14/21] :memo: Add docs --- pincer/objects/guild/guild.py | 133 +++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 84f19ca6..53331ca9 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1922,6 +1922,19 @@ async def get_webhooks(self) -> AsyncGenerator[Webhook, None]: async def get_scheduled_events( self, with_user_count: bool = False ) -> AsyncGenerator[ScheduledEvent, None]: + """ + Returns an async generator of the guild scheduled events. + + Parameters + ---------- + with_user_count : :class:`bool` + Whether to include the user count in the scheduled event. + + Yields + ------ + :class:`~pincer.objects.guild.scheduled_event.ScheduledEvent` + The scheduled event object. + """ data = await self._http.get( f"guilds/{self.id}/scheduled-events?{with_user_count=!s}" ) @@ -1936,10 +1949,39 @@ async def create_scheduled_event( scheduled_start_time: datetime, scheduled_end_time: Optional[datetime] = None, entity_metadata: Optional[str] = None, - channel_id: Optional[Snowflake] = None, + channel_id: Optional[int] = None, description: Optional[str] = None, reason: Optional[str] = None, ) -> ScheduledEvent: + """ + Create a new scheduled event for the guild. + + Parameters + ---------- + name : :class:`str` + The name of the scheduled event. + privacy_level : :class:`int` + The privacy level of the scheduled event. + entity_type : :class:`int` + The type of entity to be scheduled. + scheduled_start_time : :class:`datetime` + The scheduled start time of the event. + scheduled_end_time : Optional[:class:`datetime`] + The scheduled end time of the event. + entity_metadata : Optional[:class:`str`] + The metadata of the entity to be scheduled. + channel_id : Optional[:class:`int`] + The channel id of the channel to be scheduled. + description : Optional[:class:`str`] + The description of the scheduled event. + reason : Optional[:class:`str`] + The reason for creating the scheduled event. + + Returns + ------- + :class:`~pincer.objects.guild.scheduled_event.ScheduledEvent` + The newly created scheduled event. + """ if scheduled_start_time.timestamp() < datetime.now().timestamp(): raise ValueError("An event cannot be created in the past") @@ -1970,6 +2012,21 @@ async def create_scheduled_event( async def get_scheduled_event( self, _id: int, with_user_count: bool = False ) -> ScheduledEvent: + """ + Get a scheduled event by id. + + Parameters + ---------- + _id : :class:`int` + The id of the scheduled event. + with_user_count : :class:`bool` + Whether to include the user count in the scheduled event. + + Returns + ------- + :class:`~pincer.objects.guild.scheduled_event.ScheduledEvent` + The scheduled event object. + """ data = await self._http.get( f"guilds/{self.id}/scheduled-events/{_id}", params={"with_user_count": with_user_count}, @@ -1990,6 +2047,45 @@ async def modify_scheduled_event( status: Optional[int] = None, reason: Optional[str] = None, ) -> ScheduledEvent: + """ + Modify a scheduled event. + + Parameters + ---------- + _id : :class:`int` + The id of the scheduled event. + name : Optional[:class:`str`] + The name of the scheduled event. + entity_type : Optional[:class:`int`] + The type of entity to be scheduled. + privacy_level : Optional[:class:`int`] + The privacy level of the scheduled event. + scheduled_start_time : Optional[:class:`datetime`] + The scheduled start time of the event. + scheduled_end_time : Optional[:class:`datetime`] + The scheduled end time of the event. + entity_metadata : Optional[:class:`str`] + The metadata of the entity to be scheduled. + channel_id : Optional[:class:`int`] + The channel id of the channel to be scheduled. + description : Optional[:class:`str`] + The description of the scheduled event. + status : Optional[:class:`int`] + The status of the scheduled event. + reason : Optional[:class:`str`] + The reason for modifying the scheduled event. + + Raises + ------ + :class:`ValueError` + If the scheduled event is in the past, + or if the scheduled end time is before the scheduled start time. + + Returns + ------- + :class:`~pincer.objects.guild.scheduled_event.ScheduledEvent` + The scheduled event object. + """ if scheduled_start_time: timestamp = scheduled_start_time.timestamp() if timestamp < datetime.now().timestamp(): @@ -2026,7 +2122,15 @@ async def modify_scheduled_event( ) return ScheduledEvent.from_dict(data) - async def delete_scheduled_event(self, _id: Union[int, Snowflake]): + async def delete_scheduled_event(self, _id: int): + """ + Delete a scheduled event. + + Parameters + ---------- + _id : :class:`int` + The id of the scheduled event. + """ await self._http.delete(f"guilds/{self.id}/scheduled-events/{_id}") async def get_guild_scheduled_event_users( @@ -2034,9 +2138,30 @@ async def get_guild_scheduled_event_users( _id: int, limit: int = 100, with_member: bool = False, - before: Optional[Snowflake] = None, - after: Optional[Snowflake] = None, + before: Optional[int] = None, + after: Optional[int] = None, ) -> AsyncGenerator[GuildScheduledEventUser, None]: + """ + Get the users of a scheduled event. + + Parameters + ---------- + _id : :class:`int` + The id of the scheduled event. + limit : :class:`int` + The number of users to retrieve. + with_member : :class:`bool` + Whether to include the member object in the scheduled event user. + before : Optional[:class:`int`] + consider only users before given user id + after : Optional[:class:`int`] + consider only users after given user id + + Yields + ------ + :class:`~pincer.objects.guild.scheduled_event.GuildScheduledEventUser` + The scheduled event user object. + """ params = { "limit": limit, "with_member": with_member, From 3a3902534fbb507b82c87166eba99aa2f24e586b Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Tue, 18 Jan 2022 14:19:25 +0100 Subject: [PATCH 15/21] :fire: Remove inexistent class from all --- pincer/objects/guild/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index d5c99210..54106bd4 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -45,5 +45,4 @@ "SystemChannelFlags", "TextChannel", "ThreadMember", "ThreadMetadata", "UnavailableGuild", "VerificationLevel", "VoiceChannel", "Webhook", "WebhookType", "WelcomeScreen", "WelcomeScreenChannel", - "WelcomeScreenChannelGuildScheduledEventEntityType" ) From 8e43b6632ba0c93d5d0735d2b4ca1146f8f90c21 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 18 Jan 2022 13:19:42 +0000 Subject: [PATCH 16/21] :art: Automatic sorting --- pincer/objects/guild/__init__.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pincer/objects/guild/__init__.py b/pincer/objects/guild/__init__.py index 54106bd4..e16421fb 100644 --- a/pincer/objects/guild/__init__.py +++ b/pincer/objects/guild/__init__.py @@ -33,16 +33,17 @@ __all__ = ( - "AuditEntryInfo", "AuditLog", "AuditLogChange", "AuditLogEntry", - "AuditLogEvent", "Ban", "BaseMember", "CategoryChannel", "Channel", - "ChannelMention", "ChannelType", "DefaultMessageNotificationLevel", - "EventStatus", "ExplicitContentFilterLevel", "FollowedChannel", "Guild", - "GuildFeature", "GuildMember", "GuildNSFWLevel", - "GuildScheduledEventEntityType", "GuildTemplate", "GuildWidget", "Invite", - "InviteStageInstance", "InviteTargetType", "MFALevel", "NewsChannel", - "Overwrite", "PartialGuildMember", "Permissions", "PremiumTier", - "PrivacyLevel", "Role", "RoleTags", "ScheduledEvent", "StageInstance", - "SystemChannelFlags", "TextChannel", "ThreadMember", "ThreadMetadata", - "UnavailableGuild", "VerificationLevel", "VoiceChannel", "Webhook", - "WebhookType", "WelcomeScreen", "WelcomeScreenChannel", + "", "AuditEntryInfo", "AuditLog", "AuditLogChange", + "AuditLogEntry", "AuditLogEvent", "Ban", "BaseMember", "CategoryChannel", + "Channel", "ChannelMention", "ChannelType", + "DefaultMessageNotificationLevel", "EventStatus", + "ExplicitContentFilterLevel", "FollowedChannel", "Guild", "GuildFeature", + "GuildMember", "GuildNSFWLevel", "GuildScheduledEventEntityType", + "GuildTemplate", "GuildWidget", "Invite", "InviteStageInstance", + "InviteTargetType", "MFALevel", "NewsChannel", "Overwrite", + "PartialGuildMember", "Permissions", "PremiumTier", "PrivacyLevel", "Role", + "RoleTags", "ScheduledEvent", "StageInstance", "SystemChannelFlags", + "TextChannel", "ThreadMember", "ThreadMetadata", "UnavailableGuild", + "VerificationLevel", "VoiceChannel", "Webhook", "WebhookType", + "WelcomeScreen", "WelcomeScreenChannel" ) From 3ddb869792e37b9abb356d5e7a261c083630a285 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Wed, 19 Jan 2022 00:24:04 +0100 Subject: [PATCH 17/21] :recycle: Small refactors --- pincer/objects/guild/guild.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 53331ca9..d9809c54 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1936,7 +1936,8 @@ async def get_scheduled_events( The scheduled event object. """ data = await self._http.get( - f"guilds/{self.id}/scheduled-events?{with_user_count=!s}" + f"guilds/{self.id}/scheduled-events", + param={"with_user_count": with_user_count}, ) for event_data in data: yield ScheduledEvent.from_dict(event_data) @@ -1982,12 +1983,12 @@ async def create_scheduled_event( :class:`~pincer.objects.guild.scheduled_event.ScheduledEvent` The newly created scheduled event. """ - if scheduled_start_time.timestamp() < datetime.now().timestamp(): + if scheduled_start_time < datetime.now(): raise ValueError("An event cannot be created in the past") if ( - scheduled_end_time is not None - and scheduled_end_time.timestamp() < datetime.now().timestamp() + scheduled_end_time + and scheduled_end_time < scheduled_start_time ): raise ValueError("An event cannot start before it ends") @@ -2087,13 +2088,12 @@ async def modify_scheduled_event( The scheduled event object. """ if scheduled_start_time: - timestamp = scheduled_start_time.timestamp() - if timestamp < datetime.now().timestamp(): + if scheduled_start_time < datetime.now(): raise ValueError("An event cannot be created in the past") if ( scheduled_end_time - and timestamp > scheduled_end_time.timestamp() + and scheduled_end_time < scheduled_start_time ): raise ValueError("An event cannot start before it ends") @@ -2162,17 +2162,15 @@ async def get_guild_scheduled_event_users( :class:`~pincer.objects.guild.scheduled_event.GuildScheduledEventUser` The scheduled event user object. """ - params = { + params = remove_none({ "limit": limit, "with_member": with_member, - } - if before is not None: - params.update({"before": before}) - if after is not None: - params.update({"after": after}) + "before": before, + "after": after, + }) data = await self._http.get( - f"guilds/{self.id}/scheduled-events/{_id}/users?", + f"guilds/{self.id}/scheduled-events/{_id}/users", params=params, ) From a6cc30334b4ef1445944fa53644162da579a05d1 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Fri, 21 Jan 2022 19:12:29 +0100 Subject: [PATCH 18/21] :label: Update types 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 d9809c54..b0c5c608 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -2140,7 +2140,7 @@ async def get_guild_scheduled_event_users( with_member: bool = False, before: Optional[int] = None, after: Optional[int] = None, - ) -> AsyncGenerator[GuildScheduledEventUser, None]: + ) -> AsyncIterator[GuildScheduledEventUser]: """ Get the users of a scheduled event. From 4f09ed2d4c66caa63b9fbab1453a6f1eee0f74f7 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Fri, 21 Jan 2022 19:12:40 +0100 Subject: [PATCH 19/21] :label: Update types 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 b0c5c608..31066773 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1921,7 +1921,7 @@ async def get_webhooks(self) -> AsyncGenerator[Webhook, None]: async def get_scheduled_events( self, with_user_count: bool = False - ) -> AsyncGenerator[ScheduledEvent, None]: + ) -> AsyncIterator[ScheduledEvent]: """ Returns an async generator of the guild scheduled events. From f660124d7b7999ae1a83fd07a395ba4bdde24efa Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Fri, 21 Jan 2022 19:17:46 +0100 Subject: [PATCH 20/21] :memo: Add docs for raise --- pincer/objects/guild/guild.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 31066773..709041cd 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -1977,6 +1977,11 @@ async def create_scheduled_event( The description of the scheduled event. reason : Optional[:class:`str`] The reason for creating the scheduled event. + + Raises + ------ + ValueError: + If an event is created in the past or if an event ends before it starts Returns ------- From 0cc4469c6ea207c39420562b1077e79f48c75b70 Mon Sep 17 00:00:00 2001 From: beastmatser <79206232+beastmatser@users.noreply.github.com> Date: Fri, 21 Jan 2022 19:22:43 +0100 Subject: [PATCH 21/21] :bug: Fix improt --- pincer/objects/guild/guild.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pincer/objects/guild/guild.py b/pincer/objects/guild/guild.py index 12db6ca5..af46f40f 100644 --- a/pincer/objects/guild/guild.py +++ b/pincer/objects/guild/guild.py @@ -12,7 +12,7 @@ from .channel import Channel, Thread from .scheduled_events import ScheduledEvent, GuildScheduledEventUser -from .message.emoji import Emoji +from ..message.emoji import Emoji from ..message.file import File from ...exceptions import UnavailableGuildError from ...utils import remove_none @@ -31,7 +31,6 @@ from .invite import Invite from .overwrite import Overwrite from .role import Role - from .scheduled_events import ScheduledEvent, GuildScheduledEventUser from .stage import StageInstance from .template import GuildTemplate from .welcome_screen import WelcomeScreen, WelcomeScreenChannel