From 35a51bd8be047cb8e26a6b39f3ea4e61e86dfa47 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Mon, 27 Dec 2021 16:57:45 +0100 Subject: [PATCH 01/21] chore: Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9c5d072..0afc78d 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,4 @@ cython_debug/ # Editors .vscode/ .idea/ +.nova/ From 13f91cd481ac99a04ed12486878237038425d210 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 12:08:50 +0100 Subject: [PATCH 02/21] feat: Added User and ClientUser models --- nextcord/models/user.py | 125 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 nextcord/models/user.py diff --git a/nextcord/models/user.py b/nextcord/models/user.py new file mode 100644 index 0000000..d387d13 --- /dev/null +++ b/nextcord/models/user.py @@ -0,0 +1,125 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from .client.state import State + from .snowflake import Snowflake + + +logger = getLogger(__name__) + + +PremiumType = Literal[0, 1, 2] + + +class BaseUser: + __slots__ = ( + "id", + "username", + "discriminator", + "_avatar", + "bot", + "system", + "_banner", + "_accent_color", + "_premium_type", + "_public_flags", + "_state", + ) + + if TYPE_CHECKING: + id: Snowflake + username: str + discriminator: str + _avatar: Optional[str] + + bot: bool + system: bool + _banner: Optional[str] + _accent_color: Optional[int] + _premium_type: Optional[PremiumType] + _public_flags: int + _state: State + + def __init__(self, *, state: State, data: dict): + self._state = state + self._update(data) + + def _update(self, data): + self.id = data["id"] + self.username = data["username"] + self.discriminator = data["discriminator"] + self._avatar = data["avatar"] + + self.bot = data.get("bot") + self.system = data.get("system") + self._banner = data.get("banner") + self._accent_color = data.get("accent_color") + self._public_flags = data.get("public_flags") + + +class ClientUser(BaseUser): + __slots__ = ("mfa_enabled", "locale", "verified", "email", "flags", "bio") + + if TYPE_CHECKING: + mfa_enabled: bool + locale: str + verified: bool + flags: int + bio: str + + def __init__(self, *, state: State, data: dict): + super().__init__(state=state, data=data) + + def _update(self, data): + super()._update(data) + self.mfa_enabled = data.get("mfa_enabled") + self.locale = data.get("locale") + self.verified = data.get("verified") + self.flags = data.get("flags") + self.bio = data.get("bio") + + async def edit(self, *, username: str = None, avatar: bytes = None): + payload = {} + if username is not None: + payload["username"] = username + + if avatar is not None: + payload["avatar"] = ... # TODO: convert bytes to base64 image format + + await self._state.http # TODO: HTTP not implemented yet + + async def get_guilds( + self, *, before: Snowflake = None, after: Snowflake = None, limit: int = None + ): + ... + + async def _get_guild_member(self, *, guild_id: Snowflake): + ... + + async def _leave_guild(self, *, guild_id: Snowflake): + ... + + async def _create_dm(self, *, recipient_id: Snowflake): + ... From adffec14a48e5b418b83e3f40e01ab9cd877851b Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 12:29:18 +0100 Subject: [PATCH 03/21] chore: Rename folders and added snowflake type --- nextcord/types/snowflake.py | 23 +++++++++++++++++++++++ nextcord/{models => types}/user.py | 0 2 files changed, 23 insertions(+) create mode 100644 nextcord/types/snowflake.py rename nextcord/{models => types}/user.py (100%) diff --git a/nextcord/types/snowflake.py b/nextcord/types/snowflake.py new file mode 100644 index 0000000..1e0b3ab --- /dev/null +++ b/nextcord/types/snowflake.py @@ -0,0 +1,23 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from typing import Union + +Snowflake = Union[str, int] diff --git a/nextcord/models/user.py b/nextcord/types/user.py similarity index 100% rename from nextcord/models/user.py rename to nextcord/types/user.py From 60ee0dfe76127692333b3b6af1db002cab67bd75 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 12:32:01 +0100 Subject: [PATCH 04/21] refactor: moved BaseUser in protocols --- nextcord/types/protocols/base_user.py | 76 +++++++++++++++++++++++++++ nextcord/types/user.py | 51 +----------------- 2 files changed, 78 insertions(+), 49 deletions(-) create mode 100644 nextcord/types/protocols/base_user.py diff --git a/nextcord/types/protocols/base_user.py b/nextcord/types/protocols/base_user.py new file mode 100644 index 0000000..07e1485 --- /dev/null +++ b/nextcord/types/protocols/base_user.py @@ -0,0 +1,76 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from .client.state import State + from .snowflake import Snowflake + + +logger = getLogger(__name__) + + +class BaseUser: + __slots__ = ( + "id", + "username", + "discriminator", + "_avatar", + "bot", + "system", + "_banner", + "_accent_color", + "_premium_type", + "_public_flags", + "_state", + ) + + if TYPE_CHECKING: + id: Snowflake + username: str + discriminator: str + _avatar: Optional[str] + + bot: bool + system: bool + _banner: Optional[str] + _accent_color: Optional[int] + _premium_type: Optional[PremiumType] + _public_flags: int + _state: State + + def __init__(self, *, state: State, data: dict): + self._state = state + self._update(data) + + def _update(self, data): + self.id = data["id"] + self.username = data["username"] + self.discriminator = data["discriminator"] + self._avatar = data["avatar"] + + self.bot = data.get("bot") + self.system = data.get("system") + self._banner = data.get("banner") + self._accent_color = data.get("accent_color") + self._public_flags = data.get("public_flags") diff --git a/nextcord/types/user.py b/nextcord/types/user.py index d387d13..6de0972 100644 --- a/nextcord/types/user.py +++ b/nextcord/types/user.py @@ -22,6 +22,8 @@ from logging import getLogger from typing import TYPE_CHECKING, Optional +from .protocols.base_user import BaseUser + if TYPE_CHECKING: from .client.state import State from .snowflake import Snowflake @@ -30,55 +32,6 @@ logger = getLogger(__name__) -PremiumType = Literal[0, 1, 2] - - -class BaseUser: - __slots__ = ( - "id", - "username", - "discriminator", - "_avatar", - "bot", - "system", - "_banner", - "_accent_color", - "_premium_type", - "_public_flags", - "_state", - ) - - if TYPE_CHECKING: - id: Snowflake - username: str - discriminator: str - _avatar: Optional[str] - - bot: bool - system: bool - _banner: Optional[str] - _accent_color: Optional[int] - _premium_type: Optional[PremiumType] - _public_flags: int - _state: State - - def __init__(self, *, state: State, data: dict): - self._state = state - self._update(data) - - def _update(self, data): - self.id = data["id"] - self.username = data["username"] - self.discriminator = data["discriminator"] - self._avatar = data["avatar"] - - self.bot = data.get("bot") - self.system = data.get("system") - self._banner = data.get("banner") - self._accent_color = data.get("accent_color") - self._public_flags = data.get("public_flags") - - class ClientUser(BaseUser): __slots__ = ("mfa_enabled", "locale", "verified", "email", "flags", "bio") From 36a0f4bcbb373f1fb5d3cf396995a571eb136fdb Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 14:04:25 +0100 Subject: [PATCH 05/21] fix: fixed relative imports --- nextcord/types/protocols/base_user.py | 6 +++--- nextcord/types/user.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nextcord/types/protocols/base_user.py b/nextcord/types/protocols/base_user.py index 07e1485..383759a 100644 --- a/nextcord/types/protocols/base_user.py +++ b/nextcord/types/protocols/base_user.py @@ -23,14 +23,14 @@ from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: - from .client.state import State - from .snowflake import Snowflake + from ...client.state import State + from ..snowflake import Snowflake logger = getLogger(__name__) -class BaseUser: +class UserProtocol: __slots__ = ( "id", "username", diff --git a/nextcord/types/user.py b/nextcord/types/user.py index 6de0972..819efad 100644 --- a/nextcord/types/user.py +++ b/nextcord/types/user.py @@ -22,17 +22,17 @@ from logging import getLogger from typing import TYPE_CHECKING, Optional -from .protocols.base_user import BaseUser +from .protocols.base_user import UserProtocol if TYPE_CHECKING: - from .client.state import State + from ..client.state import State from .snowflake import Snowflake logger = getLogger(__name__) -class ClientUser(BaseUser): +class ClientUser(UserProtocol): __slots__ = ("mfa_enabled", "locale", "verified", "email", "flags", "bio") if TYPE_CHECKING: From d6baf9cdfe9ebb374a49a3144b20f67fa076d973 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 17:15:58 +0100 Subject: [PATCH 06/21] feat: adding Messageable and Embed models --- nextcord/types/channel.py | 32 +++++++++++ nextcord/types/embed.py | 95 +++++++++++++++++++++++++++++++++ nextcord/types/protocols/abc.py | 80 +++++++++++++++++++++++++++ nextcord/types/snowflake.py | 1 + 4 files changed, 208 insertions(+) create mode 100644 nextcord/types/channel.py create mode 100644 nextcord/types/embed.py create mode 100644 nextcord/types/protocols/abc.py diff --git a/nextcord/types/channel.py b/nextcord/types/channel.py new file mode 100644 index 0000000..c7a4b5f --- /dev/null +++ b/nextcord/types/channel.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ..client.state import State + from .snowflake import Snowflake + + +class Channel: + def __init__(self, *, state: State, data: dict): + pass diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py new file mode 100644 index 0000000..20ef586 --- /dev/null +++ b/nextcord/types/embed.py @@ -0,0 +1,95 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from datetime import datetime + + +logger = getLogger(__name__) + + +(EmbedFooter, EmbedImage, EmbedThumbnail, EmbedVideo, EmbedProvider, EmbedAuthor) = None + + +class EmbedField: + def __init__(self, *, name: str, value: str, inline: bool = None): + self.name = str(name) + self.value = str(value) + self.inline = bool(inline) + + +class Embed: + def __init__( + self, + *, + title: Optional[str] = None, + description: Optional[str] = None, + url: Optional[str] = None, + timestamp: Optional[datetime] = None, + color: Optional[int] = None, + footer: Optional[EmbedFooter] = None, + image: Optional[EmbedImage] = None, + thumbnail: Optional[EmbedThumbnail] = None, + video: Optional[EmbedVideo] = None, + provider: Optional[EmbedProvider] = None, + author: Optional[EmbedAuthor] = None, + fields: Optional[list[EmbedField]] = [], + ): + self.title = str(title) if title is not None else None + self.description = str(description) if description is not None else None + self.url = str(url) if url is not None else None + self.color = int(color) if color is not None else None + self.timestamp = timestamp + # self.footer = footer + # self.image = image + # self.thumbnail = thumbnail + # self.video = video + # self.provider = provider + # self.author = author + self.fields = fields + + def add_field(self, *, name: str, value: str, inline: bool = None) -> None: + self.fields.append(EmbedField(name=name, value=value, inline=inline)) + + def insert_field( + self, index: int, *, name: str, value: str, inline: bool = None + ) -> None: + self.fields.insert(index, EmbedField(name=name, value=value, inline=inline)) + + def set_field( + self, index: int, *, name: str, value: str, inline: bool = None + ) -> None: + if len(self.fields) < index: + index = len(self.fields) + + self.fields[index] = EmbedField(name=name, value=value, inline=inline) + + def remove_field(self, *, index: int) -> None: + try: + del self.fields[index] + except IndexError: + pass + + def clear_fields(self): + self.fields = [] diff --git a/nextcord/types/protocols/abc.py b/nextcord/types/protocols/abc.py new file mode 100644 index 0000000..9d4c89f --- /dev/null +++ b/nextcord/types/protocols/abc.py @@ -0,0 +1,80 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING + +from ...exceptions import InvalidArgument + +if TYPE_CHECKING: + ... + + +logger = getLogger(__name__) + +Embed = None # TODO: DEFINE +AllowedMentions = None # TODO: DEFINE +MessageReference = None # TODO: DEFINE +MessageComponent = None # TODO: DEFINE +File = None # TODO: DEFINE +PartialAttachment = None # TODO: DEFINE +Sticker = None # TODO: DEFINE + + +class Messageable: + async def send( + self, + content: str = None, + *, + tts: bool = None, + embed: Embed = None, + embeds: list[Embed] = None, + allowed_mentions: AllowedMentions = None, + message_reference: MessageReference = None, + components: list[MessageComponent] = None, + stickers: list[Sticker] = None, + file: File = None, + files: list[File] = None, + payload_json: str = None, + attachments: list[PartialAttachment] = None, + ): + state = self._state + + if embed is not None and embeds is not None: + raise InvalidArgument("You cannot pass both embed and embeds parameters") + elif embed is not None: + embeds = [embed] + + if embeds is not None: + ... # Convert embed objects to json + + if file is not None and files is not None: + raise InvalidArgument("You cannot pass both file and files parameters") + elif file is not None: + files = [file] + + if stickers is not None: + sticker_ids = [sticker.id for sticker in stickers] + + # + # + + await state.http, sticker_ids # ... diff --git a/nextcord/types/snowflake.py b/nextcord/types/snowflake.py index 1e0b3ab..82cd7ba 100644 --- a/nextcord/types/snowflake.py +++ b/nextcord/types/snowflake.py @@ -21,3 +21,4 @@ from typing import Union Snowflake = Union[str, int] +SnowflakeArray = list[Snowflake] From d5f74040dc45fc4052269a866393b56fc4501b81 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 19:08:10 +0100 Subject: [PATCH 07/21] refactor: renamed embed functions --- nextcord/types/embed.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index 20ef586..682add1 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -61,24 +61,27 @@ def __init__( self.url = str(url) if url is not None else None self.color = int(color) if color is not None else None self.timestamp = timestamp - # self.footer = footer - # self.image = image - # self.thumbnail = thumbnail - # self.video = video - # self.provider = provider - # self.author = author - self.fields = fields - def add_field(self, *, name: str, value: str, inline: bool = None) -> None: - self.fields.append(EmbedField(name=name, value=value, inline=inline)) + self.footer = footer if isinstance(footer, EmbedFooter) else None + self.image = image if isinstance(image, EmbedImage) else None + self.thumbnail = thumbnail if isinstance(thumbnail, EmbedThumbnail) else None + self.video = video if isinstance(video, EmbedVideo) else None + self.provider = provider if isinstance(provider, EmbedProvider) else None + self.author = author if isinstance(author, EmbedAuthor) else None + self.fields = fields if isinstance(fields, list) else None - def insert_field( - self, index: int, *, name: str, value: str, inline: bool = None + def add_field( + self, name: str, value: str, *, inline: bool = None, position: int = None ) -> None: - self.fields.insert(index, EmbedField(name=name, value=value, inline=inline)) - - def set_field( - self, index: int, *, name: str, value: str, inline: bool = None + if position is not None: + self.fields.insert( + position, EmbedField(name=name, value=value, inline=inline) + ) + else: + self.fields.append(EmbedField(name=name, value=value, inline=inline)) + + def edit_field( + self, index: int, name: str, value: str, *, inline: bool = None ) -> None: if len(self.fields) < index: index = len(self.fields) @@ -90,6 +93,3 @@ def remove_field(self, *, index: int) -> None: del self.fields[index] except IndexError: pass - - def clear_fields(self): - self.fields = [] From 1c0f1eb134ffc56ca17da613aee675f5966be239 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 19:08:35 +0100 Subject: [PATCH 08/21] feat: added InvalidArgument exception --- nextcord/exceptions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nextcord/exceptions.py b/nextcord/exceptions.py index 3b0e43b..1b429bf 100644 --- a/nextcord/exceptions.py +++ b/nextcord/exceptions.py @@ -25,3 +25,7 @@ def __init__(self) -> None: "You have been banned by Cloudflare. " "See https://discord.dev/topics/rate-limits#invalid-request-limit-aka-cloudflare-bans" ) + + +class InvalidArgument(NextcordException): + ... From a3663cc1f37789bd00680c8678d7baafcbf954dc Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 28 Dec 2021 20:11:42 +0100 Subject: [PATCH 09/21] feat: Added Embed class and Embed* classes --- nextcord/types/embed.py | 66 +++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index 682add1..9be923f 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -19,6 +19,7 @@ """ from __future__ import annotations +from dataclasses import dataclass from logging import getLogger from typing import TYPE_CHECKING, Optional @@ -29,11 +30,52 @@ logger = getLogger(__name__) -(EmbedFooter, EmbedImage, EmbedThumbnail, EmbedVideo, EmbedProvider, EmbedAuthor) = None +@dataclass(frozen=True) +class EmbedFile: + url: str + proxy_url: Optional[str] = None + height: Optional[int] = None + width: Optional[int] = None + + +@dataclass(frozen=True) +class EmbedThumbnail(EmbedFile): + ... + + +@dataclass(frozen=True) +class EmbedVideo(EmbedFile): + url: Optional[str] = None + + +@dataclass(frozen=True) +class EmbedImage(EmbedFile): + ... + + +@dataclass(frozen=True) +class EmbedProvider: + name: Optional[str] = None + url: Optional[str] = None + + +@dataclass(frozen=True) +class EmbedAuthor: + name: str + url: Optional[str] = None + icon_url: Optional[str] = None + proxy_icon_url: Optional[str] = None + + +@dataclass(frozen=True) +class EmbedFooter: + text: str + icon_url: Optional[str] = None + proxy_icon_url: Optional[str] = None class EmbedField: - def __init__(self, *, name: str, value: str, inline: bool = None): + def __init__(self, name: str, value: str, *, inline: bool = None): self.name = str(name) self.value = str(value) self.inline = bool(inline) @@ -68,25 +110,25 @@ def __init__( self.video = video if isinstance(video, EmbedVideo) else None self.provider = provider if isinstance(provider, EmbedProvider) else None self.author = author if isinstance(author, EmbedAuthor) else None - self.fields = fields if isinstance(fields, list) else None + self.fields = fields if isinstance(fields, list) else [] def add_field( self, name: str, value: str, *, inline: bool = None, position: int = None ) -> None: if position is not None: - self.fields.insert( - position, EmbedField(name=name, value=value, inline=inline) - ) + self.fields.insert(position, EmbedField(name, value, inline=inline)) else: - self.fields.append(EmbedField(name=name, value=value, inline=inline)) + self.fields.append(EmbedField(name, value, inline=inline)) def edit_field( - self, index: int, name: str, value: str, *, inline: bool = None + self, index: int, name: str = None, value: str = None, *, inline: bool = None ) -> None: - if len(self.fields) < index: - index = len(self.fields) - - self.fields[index] = EmbedField(name=name, value=value, inline=inline) + if name is not None: + self.fields[index].name = name + if value is not None: + self.fields[index].value = value + if inline is not None: + self.fields[index].inline = inline def remove_field(self, *, index: int) -> None: try: From 9a1d3ab8607948f1c28409bf70fc220f7eef75b7 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Wed, 29 Dec 2021 18:41:49 +0100 Subject: [PATCH 10/21] feat: switched video and provider to properties, added [from/to]_dict methods --- nextcord/types/embed.py | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index 9be923f..02e7342 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -82,6 +82,21 @@ def __init__(self, name: str, value: str, *, inline: bool = None): class Embed: + __slots__ = ( + "title", + "description", + "url", + "timestamp", + "color", + "footer", + "image", + "thumbnail", + "author", + "fields", + "provider", + "video", + ) + def __init__( self, *, @@ -93,8 +108,6 @@ def __init__( footer: Optional[EmbedFooter] = None, image: Optional[EmbedImage] = None, thumbnail: Optional[EmbedThumbnail] = None, - video: Optional[EmbedVideo] = None, - provider: Optional[EmbedProvider] = None, author: Optional[EmbedAuthor] = None, fields: Optional[list[EmbedField]] = [], ): @@ -107,8 +120,6 @@ def __init__( self.footer = footer if isinstance(footer, EmbedFooter) else None self.image = image if isinstance(image, EmbedImage) else None self.thumbnail = thumbnail if isinstance(thumbnail, EmbedThumbnail) else None - self.video = video if isinstance(video, EmbedVideo) else None - self.provider = provider if isinstance(provider, EmbedProvider) else None self.author = author if isinstance(author, EmbedAuthor) else None self.fields = fields if isinstance(fields, list) else [] @@ -135,3 +146,28 @@ def remove_field(self, *, index: int) -> None: del self.fields[index] except IndexError: pass + + @property + def video(self): + return self._video + + @property + def provider(self): + return self._provider + + def from_dict(self, data: dict): + for key, value in data.items(): + if key in ["video", "provider"]: + setattr(self, "_" + key, value) + elif key in self.__slots__: + setattr(self, key, value) + else: + continue # TODO: Unknown key, should it raise an error? + + def to_dict(self): + data = {} + for key in self.__slots__: + if key in ["video", "provider"]: + data[key] = getattr(self, "_" + key) + else: + data[key] = getattr(self, key) From 1accd2af49e6a0fd4da61b39729ef99947d54a70 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Mon, 3 Jan 2022 19:39:01 +0100 Subject: [PATCH 11/21] feat: added allowed_mentions, modified embed, started work on channel and abc.Messageable --- nextcord/types/allowed_mentions.py | 78 ++++++++++++++++++++++++++++++ nextcord/types/channel.py | 3 +- nextcord/types/embed.py | 14 ++++-- nextcord/types/protocols/abc.py | 21 ++++---- 4 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 nextcord/types/allowed_mentions.py diff --git a/nextcord/types/allowed_mentions.py b/nextcord/types/allowed_mentions.py new file mode 100644 index 0000000..dc630be --- /dev/null +++ b/nextcord/types/allowed_mentions.py @@ -0,0 +1,78 @@ +""" +The MIT License (MIT) +Copyright (c) 2021-present vcokltfre & tag-epic +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING, Union + +if TYPE_CHECKING: + ... + + +Role, User = None # TODO: DEFINE and import + +logger = getLogger(__name__) + + +class AllowedMentions: + def __init__( + self, + *, + everyone: bool = False, + roles: Union[bool, list[Role], Role] = False, + users: Union[bool, User, list[User]] = True, + replied_user: bool = None, + ): + self.everyone = everyone + self.roles = roles + self.users = users + self.replied_user = replied_user + + def to_dict(self): + allowed = {"parse": []} + if self.everyone: + allowed["parse"].append("everyone") + + if isinstance(self.roles, bool) and self.roles: + allowed["parse"].append("roles") + elif isinstance(self.roles, list): + allowed["roles"] = [r.id for r in self.roles] + elif isinstance(self.roles, Role): + allowed["roles"] = [self.roles.id] + + if isinstance(self.users, bool) and self.roles: + allowed["parse"].append("users") + elif isinstance(self.users, list): + allowed["users"] = [u.id for u in self.roles] + elif isinstance(self.users, User): + allowed["users"] = [self.users.id] + + if self.replied_user: + allowed["replied_user"] = bool(self.replied_user) + + @classmethod + def none(cls): + return cls.__init__( + everyone=False, roles=False, users=False, replied_user=False + ) + + @classmethod + def all(cls): + return cls.__init__(everyone=True, roles=True, users=True, replied_user=True) diff --git a/nextcord/types/channel.py b/nextcord/types/channel.py index c7a4b5f..9b4a82a 100644 --- a/nextcord/types/channel.py +++ b/nextcord/types/channel.py @@ -24,7 +24,8 @@ if TYPE_CHECKING: from ..client.state import State - from .snowflake import Snowflake + +logger = getLogger(__name__) class Channel: diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index 02e7342..cc540c2 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -155,15 +155,19 @@ def video(self): def provider(self): return self._provider - def from_dict(self, data: dict): + @classmethod + def from_dict(cls, data: dict): + embed = cls.__init__() for key, value in data.items(): if key in ["video", "provider"]: - setattr(self, "_" + key, value) - elif key in self.__slots__: - setattr(self, key, value) + setattr(embed, "_" + key, value) + elif key in embed.__slots__: + setattr(embed, key, value) else: continue # TODO: Unknown key, should it raise an error? + return embed + def to_dict(self): data = {} for key in self.__slots__: @@ -171,3 +175,5 @@ def to_dict(self): data[key] = getattr(self, "_" + key) else: data[key] = getattr(self, key) + + return data diff --git a/nextcord/types/protocols/abc.py b/nextcord/types/protocols/abc.py index 9d4c89f..7077e7b 100644 --- a/nextcord/types/protocols/abc.py +++ b/nextcord/types/protocols/abc.py @@ -25,18 +25,19 @@ from ...exceptions import InvalidArgument if TYPE_CHECKING: - ... + from ..embed import Embed logger = getLogger(__name__) -Embed = None # TODO: DEFINE -AllowedMentions = None # TODO: DEFINE -MessageReference = None # TODO: DEFINE -MessageComponent = None # TODO: DEFINE -File = None # TODO: DEFINE -PartialAttachment = None # TODO: DEFINE -Sticker = None # TODO: DEFINE +( + AllowedMentions, + MessageReference, + MessageComponent, + File, + PartialAttachment, + Sticker, +) = None # TODO: DEFINE and import class Messageable: @@ -64,7 +65,7 @@ async def send( embeds = [embed] if embeds is not None: - ... # Convert embed objects to json + embeds = [emb.to_dict() for emb in embeds] if file is not None and files is not None: raise InvalidArgument("You cannot pass both file and files parameters") @@ -77,4 +78,4 @@ async def send( # # - await state.http, sticker_ids # ... + await state, sticker_ids # ... From 31e0af9d9b5f3081d13462e7067f0f93e14e904a Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Mon, 3 Jan 2022 19:41:57 +0100 Subject: [PATCH 12/21] refactor: linted --- nextcord/core/gateway/gateway.py | 2 +- nextcord/core/gateway/protocols/gateway.py | 8 ++++++-- nextcord/type_sheet.py | 7 +++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/nextcord/core/gateway/gateway.py b/nextcord/core/gateway/gateway.py index fd37a0e..fd789de 100644 --- a/nextcord/core/gateway/gateway.py +++ b/nextcord/core/gateway/gateway.py @@ -36,9 +36,9 @@ from typing import Any, Optional from nextcord.exceptions import NextcordException - from .protocols.shard import ShardProtocol from ...client.state import State + from .protocols.shard import ShardProtocol logger = getLogger(__name__) diff --git a/nextcord/core/gateway/protocols/gateway.py b/nextcord/core/gateway/protocols/gateway.py index 39b2273..77719fd 100644 --- a/nextcord/core/gateway/protocols/gateway.py +++ b/nextcord/core/gateway/protocols/gateway.py @@ -51,8 +51,12 @@ def should_reconnect(self, shard: ShardProtocol) -> bool: async def close(self) -> None: ... - def _shard_dispatch(self, event_name: str, shard: ShardProtocol, *args: Any) -> None: + def _shard_dispatch( + self, event_name: str, shard: ShardProtocol, *args: Any + ) -> None: ... - def _shard_raw_dispatch(self, opcode: int, shard: ShardProtocol, *args: Any) -> None: + def _shard_raw_dispatch( + self, opcode: int, shard: ShardProtocol, *args: Any + ) -> None: ... diff --git a/nextcord/type_sheet.py b/nextcord/type_sheet.py index e2f1cba..5f4cd7c 100644 --- a/nextcord/type_sheet.py +++ b/nextcord/type_sheet.py @@ -29,8 +29,8 @@ T = TypeVar("T") from .core.gateway.gateway import GatewayProtocol - from .core.protocols.http import BucketProtocol, HTTPClientProtocol from .core.gateway.protocols.shard import ShardProtocol + from .core.protocols.http import BucketProtocol, HTTPClientProtocol @dataclass @@ -49,5 +49,8 @@ def default(cls: Type[T]) -> T: from .core.http import HTTPClient as DefaultHTTPClient return cls( - http_client=DefaultHTTPClient, http_bucket=DefaultBucket, gateway=Gateway, shard=Shard + http_client=DefaultHTTPClient, + http_bucket=DefaultBucket, + gateway=Gateway, + shard=Shard, ) From 91c5386c368699a2f1039d66ed02106cbbc24ce7 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 4 Jan 2022 18:32:02 +0100 Subject: [PATCH 13/21] style: switched to comments for license --- nextcord/exceptions.py | 19 ++++++++++++++ nextcord/type_sheet.py | 37 +++++++++++++-------------- nextcord/types/allowed_mentions.py | 37 +++++++++++++-------------- nextcord/types/channel.py | 37 +++++++++++++-------------- nextcord/types/embed.py | 37 +++++++++++++-------------- nextcord/types/protocols/abc.py | 37 +++++++++++++-------------- nextcord/types/protocols/base_user.py | 37 +++++++++++++-------------- nextcord/types/snowflake.py | 36 ++++++++++++-------------- nextcord/types/user.py | 37 +++++++++++++-------------- nextcord/utils.py | 36 ++++++++++++-------------- 10 files changed, 179 insertions(+), 171 deletions(-) diff --git a/nextcord/exceptions.py b/nextcord/exceptions.py index 1b429bf..4e31da1 100644 --- a/nextcord/exceptions.py +++ b/nextcord/exceptions.py @@ -1,3 +1,22 @@ +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + class NextcordException(Exception): ... diff --git a/nextcord/type_sheet.py b/nextcord/type_sheet.py index 5f4cd7c..0e0e903 100644 --- a/nextcord/type_sheet.py +++ b/nextcord/type_sheet.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/nextcord/types/allowed_mentions.py b/nextcord/types/allowed_mentions.py index dc630be..685f508 100644 --- a/nextcord/types/allowed_mentions.py +++ b/nextcord/types/allowed_mentions.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from logging import getLogger diff --git a/nextcord/types/channel.py b/nextcord/types/channel.py index 9b4a82a..8ed69c0 100644 --- a/nextcord/types/channel.py +++ b/nextcord/types/channel.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from logging import getLogger diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index cc540c2..c207083 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from dataclasses import dataclass diff --git a/nextcord/types/protocols/abc.py b/nextcord/types/protocols/abc.py index 7077e7b..d9e25a3 100644 --- a/nextcord/types/protocols/abc.py +++ b/nextcord/types/protocols/abc.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from logging import getLogger diff --git a/nextcord/types/protocols/base_user.py b/nextcord/types/protocols/base_user.py index 383759a..2411292 100644 --- a/nextcord/types/protocols/base_user.py +++ b/nextcord/types/protocols/base_user.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from logging import getLogger diff --git a/nextcord/types/snowflake.py b/nextcord/types/snowflake.py index 82cd7ba..035b834 100644 --- a/nextcord/types/snowflake.py +++ b/nextcord/types/snowflake.py @@ -1,22 +1,20 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. from typing import Union diff --git a/nextcord/types/user.py b/nextcord/types/user.py index 819efad..a4ad648 100644 --- a/nextcord/types/user.py +++ b/nextcord/types/user.py @@ -1,22 +1,21 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + from __future__ import annotations from logging import getLogger diff --git a/nextcord/utils.py b/nextcord/utils.py index ef1cb0e..a2256cc 100644 --- a/nextcord/utils.py +++ b/nextcord/utils.py @@ -1,22 +1,20 @@ -""" -The MIT License (MIT) -Copyright (c) 2021-present vcokltfre & tag-epic -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -""" +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. __all__ = ("json",) From 9b2b62e199ffcecd58f151a34b9a79797835e89d Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Sat, 8 Jan 2022 14:21:33 +0100 Subject: [PATCH 14/21] revert: remove abc.py ; early WIP --- nextcord/types/protocols/abc.py | 80 --------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 nextcord/types/protocols/abc.py diff --git a/nextcord/types/protocols/abc.py b/nextcord/types/protocols/abc.py deleted file mode 100644 index d9e25a3..0000000 --- a/nextcord/types/protocols/abc.py +++ /dev/null @@ -1,80 +0,0 @@ -# The MIT License (MIT) -# Copyright (c) 2021-present vcokltfre & tag-epic -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -from __future__ import annotations - -from logging import getLogger -from typing import TYPE_CHECKING - -from ...exceptions import InvalidArgument - -if TYPE_CHECKING: - from ..embed import Embed - - -logger = getLogger(__name__) - -( - AllowedMentions, - MessageReference, - MessageComponent, - File, - PartialAttachment, - Sticker, -) = None # TODO: DEFINE and import - - -class Messageable: - async def send( - self, - content: str = None, - *, - tts: bool = None, - embed: Embed = None, - embeds: list[Embed] = None, - allowed_mentions: AllowedMentions = None, - message_reference: MessageReference = None, - components: list[MessageComponent] = None, - stickers: list[Sticker] = None, - file: File = None, - files: list[File] = None, - payload_json: str = None, - attachments: list[PartialAttachment] = None, - ): - state = self._state - - if embed is not None and embeds is not None: - raise InvalidArgument("You cannot pass both embed and embeds parameters") - elif embed is not None: - embeds = [embed] - - if embeds is not None: - embeds = [emb.to_dict() for emb in embeds] - - if file is not None and files is not None: - raise InvalidArgument("You cannot pass both file and files parameters") - elif file is not None: - files = [file] - - if stickers is not None: - sticker_ids = [sticker.id for sticker in stickers] - - # - # - - await state, sticker_ids # ... From 53484c4cb3d585c08b53779d471fb83ae4bdc3ba Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Sun, 9 Jan 2022 18:07:21 +0100 Subject: [PATCH 15/21] refactor/fix: moves code around and fixes typehinting --- nextcord/exceptions.py | 2 +- nextcord/types/channel.py | 2 +- nextcord/types/embed.py | 16 +++++- nextcord/types/protocols/abc.py | 80 +++++++++++++++++++++++++++ nextcord/types/protocols/base_user.py | 53 +++++++++++++++++- nextcord/types/user.py | 53 +----------------- 6 files changed, 149 insertions(+), 57 deletions(-) create mode 100644 nextcord/types/protocols/abc.py diff --git a/nextcord/exceptions.py b/nextcord/exceptions.py index 4e31da1..014134e 100644 --- a/nextcord/exceptions.py +++ b/nextcord/exceptions.py @@ -46,5 +46,5 @@ def __init__(self) -> None: ) -class InvalidArgument(NextcordException): +class ArgumentConflict(NextcordException): ... diff --git a/nextcord/types/channel.py b/nextcord/types/channel.py index 8ed69c0..93f22ef 100644 --- a/nextcord/types/channel.py +++ b/nextcord/types/channel.py @@ -28,5 +28,5 @@ class Channel: - def __init__(self, *, state: State, data: dict): + def __init__(self, state: State, data: dict): pass diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index c207083..da60d72 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -74,7 +74,7 @@ class EmbedFooter: class EmbedField: - def __init__(self, name: str, value: str, *, inline: bool = None): + def __init__(self, name: str, value: str, *, inline: Optional[bool] = None): self.name = str(name) self.value = str(value) self.inline = bool(inline) @@ -123,7 +123,12 @@ def __init__( self.fields = fields if isinstance(fields, list) else [] def add_field( - self, name: str, value: str, *, inline: bool = None, position: int = None + self, + name: str, + value: str, + *, + inline: Optional[bool] = None, + position: Optional[int] = None, ) -> None: if position is not None: self.fields.insert(position, EmbedField(name, value, inline=inline)) @@ -131,7 +136,12 @@ def add_field( self.fields.append(EmbedField(name, value, inline=inline)) def edit_field( - self, index: int, name: str = None, value: str = None, *, inline: bool = None + self, + index: Optional[int], + name: Optional[str] = None, + value: Optional[str] = None, + *, + inline: Optional[bool] = None, ) -> None: if name is not None: self.fields[index].name = name diff --git a/nextcord/types/protocols/abc.py b/nextcord/types/protocols/abc.py new file mode 100644 index 0000000..d9e25a3 --- /dev/null +++ b/nextcord/types/protocols/abc.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# Copyright (c) 2021-present vcokltfre & tag-epic +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +from __future__ import annotations + +from logging import getLogger +from typing import TYPE_CHECKING + +from ...exceptions import InvalidArgument + +if TYPE_CHECKING: + from ..embed import Embed + + +logger = getLogger(__name__) + +( + AllowedMentions, + MessageReference, + MessageComponent, + File, + PartialAttachment, + Sticker, +) = None # TODO: DEFINE and import + + +class Messageable: + async def send( + self, + content: str = None, + *, + tts: bool = None, + embed: Embed = None, + embeds: list[Embed] = None, + allowed_mentions: AllowedMentions = None, + message_reference: MessageReference = None, + components: list[MessageComponent] = None, + stickers: list[Sticker] = None, + file: File = None, + files: list[File] = None, + payload_json: str = None, + attachments: list[PartialAttachment] = None, + ): + state = self._state + + if embed is not None and embeds is not None: + raise InvalidArgument("You cannot pass both embed and embeds parameters") + elif embed is not None: + embeds = [embed] + + if embeds is not None: + embeds = [emb.to_dict() for emb in embeds] + + if file is not None and files is not None: + raise InvalidArgument("You cannot pass both file and files parameters") + elif file is not None: + files = [file] + + if stickers is not None: + sticker_ids = [sticker.id for sticker in stickers] + + # + # + + await state, sticker_ids # ... diff --git a/nextcord/types/protocols/base_user.py b/nextcord/types/protocols/base_user.py index 2411292..0a7dbc1 100644 --- a/nextcord/types/protocols/base_user.py +++ b/nextcord/types/protocols/base_user.py @@ -54,7 +54,6 @@ class UserProtocol: system: bool _banner: Optional[str] _accent_color: Optional[int] - _premium_type: Optional[PremiumType] _public_flags: int _state: State @@ -73,3 +72,55 @@ def _update(self, data): self._banner = data.get("banner") self._accent_color = data.get("accent_color") self._public_flags = data.get("public_flags") + + +class ClientUser(UserProtocol): + __slots__ = ("mfa_enabled", "locale", "verified", "email", "flags", "bio") + + if TYPE_CHECKING: + mfa_enabled: bool + locale: str + verified: bool + flags: int + bio: str + + def __init__(self, state: State, data: dict): + super().__init__(state=state, data=data) + + def _update(self, data): + super()._update(data) + self.mfa_enabled = data.get("mfa_enabled") + self.locale = data.get("locale") + self.verified = data.get("verified") + self.flags = data.get("flags") + self.bio = data.get("bio") + + async def edit( + self, *, username: Optional[str] = None, avatar: Optional[bytes] = None + ): + payload = {} + if username is not None: + payload["username"] = username + + if avatar is not None: + payload["avatar"] = ... # TODO: convert bytes to base64 image format + + await self._state.http # TODO: HTTP not implemented yet + + async def get_guilds( + self, + *, + before: Optional[Snowflake] = None, + after: Optional[Snowflake] = None, + limit: Optional[int] = None, + ): + ... + + async def _get_guild_member(self, *, guild_id: Snowflake): + ... + + async def _leave_guild(self, *, guild_id: Snowflake): + ... + + async def _create_dm(self, *, recipient_id: Snowflake): + ... diff --git a/nextcord/types/user.py b/nextcord/types/user.py index a4ad648..56fd39b 100644 --- a/nextcord/types/user.py +++ b/nextcord/types/user.py @@ -19,59 +19,10 @@ from __future__ import annotations from logging import getLogger -from typing import TYPE_CHECKING, Optional - -from .protocols.base_user import UserProtocol +from typing import TYPE_CHECKING if TYPE_CHECKING: - from ..client.state import State - from .snowflake import Snowflake + ... logger = getLogger(__name__) - - -class ClientUser(UserProtocol): - __slots__ = ("mfa_enabled", "locale", "verified", "email", "flags", "bio") - - if TYPE_CHECKING: - mfa_enabled: bool - locale: str - verified: bool - flags: int - bio: str - - def __init__(self, *, state: State, data: dict): - super().__init__(state=state, data=data) - - def _update(self, data): - super()._update(data) - self.mfa_enabled = data.get("mfa_enabled") - self.locale = data.get("locale") - self.verified = data.get("verified") - self.flags = data.get("flags") - self.bio = data.get("bio") - - async def edit(self, *, username: str = None, avatar: bytes = None): - payload = {} - if username is not None: - payload["username"] = username - - if avatar is not None: - payload["avatar"] = ... # TODO: convert bytes to base64 image format - - await self._state.http # TODO: HTTP not implemented yet - - async def get_guilds( - self, *, before: Snowflake = None, after: Snowflake = None, limit: int = None - ): - ... - - async def _get_guild_member(self, *, guild_id: Snowflake): - ... - - async def _leave_guild(self, *, guild_id: Snowflake): - ... - - async def _create_dm(self, *, recipient_id: Snowflake): - ... From 6d711aa6b8d94f836b54a3b67f3bd3aa0cfa9700 Mon Sep 17 00:00:00 2001 From: Gugu72 <60748483+Gugu7264@users.noreply.github.com> Date: Sun, 9 Jan 2022 18:17:54 +0100 Subject: [PATCH 16/21] Delete abc.py --- nextcord/types/protocols/abc.py | 80 --------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 nextcord/types/protocols/abc.py diff --git a/nextcord/types/protocols/abc.py b/nextcord/types/protocols/abc.py deleted file mode 100644 index d9e25a3..0000000 --- a/nextcord/types/protocols/abc.py +++ /dev/null @@ -1,80 +0,0 @@ -# The MIT License (MIT) -# Copyright (c) 2021-present vcokltfre & tag-epic -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -from __future__ import annotations - -from logging import getLogger -from typing import TYPE_CHECKING - -from ...exceptions import InvalidArgument - -if TYPE_CHECKING: - from ..embed import Embed - - -logger = getLogger(__name__) - -( - AllowedMentions, - MessageReference, - MessageComponent, - File, - PartialAttachment, - Sticker, -) = None # TODO: DEFINE and import - - -class Messageable: - async def send( - self, - content: str = None, - *, - tts: bool = None, - embed: Embed = None, - embeds: list[Embed] = None, - allowed_mentions: AllowedMentions = None, - message_reference: MessageReference = None, - components: list[MessageComponent] = None, - stickers: list[Sticker] = None, - file: File = None, - files: list[File] = None, - payload_json: str = None, - attachments: list[PartialAttachment] = None, - ): - state = self._state - - if embed is not None and embeds is not None: - raise InvalidArgument("You cannot pass both embed and embeds parameters") - elif embed is not None: - embeds = [embed] - - if embeds is not None: - embeds = [emb.to_dict() for emb in embeds] - - if file is not None and files is not None: - raise InvalidArgument("You cannot pass both file and files parameters") - elif file is not None: - files = [file] - - if stickers is not None: - sticker_ids = [sticker.id for sticker in stickers] - - # - # - - await state, sticker_ids # ... From 1cd594d8b048d157bb3d9d84d3e87e9538b2e8cf Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Wed, 19 Jan 2022 16:03:57 +0100 Subject: [PATCH 17/21] chore: subclass Protocol and use cls() --- nextcord/types/embed.py | 2 +- nextcord/types/protocols/base_user.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index da60d72..d13b68f 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -166,7 +166,7 @@ def provider(self): @classmethod def from_dict(cls, data: dict): - embed = cls.__init__() + embed = cls() for key, value in data.items(): if key in ["video", "provider"]: setattr(embed, "_" + key, value) diff --git a/nextcord/types/protocols/base_user.py b/nextcord/types/protocols/base_user.py index 0a7dbc1..8aaa749 100644 --- a/nextcord/types/protocols/base_user.py +++ b/nextcord/types/protocols/base_user.py @@ -19,7 +19,7 @@ from __future__ import annotations from logging import getLogger -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Protocol if TYPE_CHECKING: from ...client.state import State @@ -29,7 +29,7 @@ logger = getLogger(__name__) -class UserProtocol: +class UserProtocol(Protocol): __slots__ = ( "id", "username", @@ -95,9 +95,7 @@ def _update(self, data): self.flags = data.get("flags") self.bio = data.get("bio") - async def edit( - self, *, username: Optional[str] = None, avatar: Optional[bytes] = None - ): + async def edit(self, *, username: Optional[str] = None, avatar: Optional[bytes] = None): payload = {} if username is not None: payload["username"] = username From da41a2c487ce382372c01db9a013957ec48874f0 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Sat, 22 Jan 2022 10:27:05 +0100 Subject: [PATCH 18/21] chore: fix mypy errors --- nextcord/types/allowed_mentions.py | 24 ++++++++++++------------ nextcord/types/embed.py | 19 ++++++++++++------- nextcord/types/protocols/__init__.py | 0 nextcord/types/protocols/base_user.py | 6 +++--- 4 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 nextcord/types/protocols/__init__.py diff --git a/nextcord/types/allowed_mentions.py b/nextcord/types/allowed_mentions.py index 685f508..344242a 100644 --- a/nextcord/types/allowed_mentions.py +++ b/nextcord/types/allowed_mentions.py @@ -19,13 +19,13 @@ from __future__ import annotations from logging import getLogger -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Optional, Union if TYPE_CHECKING: - ... + from .snowflake import Snowflake -Role, User = None # TODO: DEFINE and import +Role, User = None, None # TODO: DEFINE and import logger = getLogger(__name__) @@ -37,15 +37,15 @@ def __init__( everyone: bool = False, roles: Union[bool, list[Role], Role] = False, users: Union[bool, User, list[User]] = True, - replied_user: bool = None, + replied_user: Optional[bool] = None, ): self.everyone = everyone self.roles = roles self.users = users self.replied_user = replied_user - def to_dict(self): - allowed = {"parse": []} + def to_dict(self) -> dict[str, Union[list[str], list[Snowflake], bool]]: + allowed: dict[str, Union[list[str], list[Snowflake], bool]] = {"parse": []} if self.everyone: allowed["parse"].append("everyone") @@ -66,12 +66,12 @@ def to_dict(self): if self.replied_user: allowed["replied_user"] = bool(self.replied_user) + return allowed + @classmethod - def none(cls): - return cls.__init__( - everyone=False, roles=False, users=False, replied_user=False - ) + def none(cls) -> AllowedMentions: + return cls(everyone=False, roles=False, users=False, replied_user=False) @classmethod - def all(cls): - return cls.__init__(everyone=True, roles=True, users=True, replied_user=True) + def all(cls) -> AllowedMentions: + return cls(everyone=True, roles=True, users=True, replied_user=True) diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index d13b68f..623be5e 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -20,7 +20,7 @@ from dataclasses import dataclass from logging import getLogger -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Union if TYPE_CHECKING: from datetime import datetime @@ -81,6 +81,7 @@ def __init__(self, name: str, value: str, *, inline: Optional[bool] = None): class Embed: + _special = ["provider", "video"] __slots__ = ( "title", "description", @@ -96,6 +97,10 @@ class Embed: "video", ) + if TYPE_CHECKING: + _video: EmbedVideo + _provider: EmbedProvider + def __init__( self, *, @@ -137,7 +142,7 @@ def add_field( def edit_field( self, - index: Optional[int], + index: int, name: Optional[str] = None, value: Optional[str] = None, *, @@ -157,18 +162,18 @@ def remove_field(self, *, index: int) -> None: pass @property - def video(self): + def video(self) -> Optional[EmbedVideo]: return self._video @property - def provider(self): + def provider(self) -> Optional[EmbedProvider]: return self._provider @classmethod def from_dict(cls, data: dict): embed = cls() for key, value in data.items(): - if key in ["video", "provider"]: + if key in cls._special: setattr(embed, "_" + key, value) elif key in embed.__slots__: setattr(embed, key, value) @@ -177,10 +182,10 @@ def from_dict(cls, data: dict): return embed - def to_dict(self): + def to_dict(self) -> dict[str, Union[EmbedFile, EmbedProvider, EmbedAuthor, EmbedFooter, EmbedField]]: data = {} for key in self.__slots__: - if key in ["video", "provider"]: + if key in cls._special: data[key] = getattr(self, "_" + key) else: data[key] = getattr(self, key) diff --git a/nextcord/types/protocols/__init__.py b/nextcord/types/protocols/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nextcord/types/protocols/base_user.py b/nextcord/types/protocols/base_user.py index 8aaa749..86b5b9c 100644 --- a/nextcord/types/protocols/base_user.py +++ b/nextcord/types/protocols/base_user.py @@ -61,7 +61,7 @@ def __init__(self, *, state: State, data: dict): self._state = state self._update(data) - def _update(self, data): + def _update(self, data: dict) -> None: self.id = data["id"] self.username = data["username"] self.discriminator = data["discriminator"] @@ -87,7 +87,7 @@ class ClientUser(UserProtocol): def __init__(self, state: State, data: dict): super().__init__(state=state, data=data) - def _update(self, data): + def _update(self, data: dict): super()._update(data) self.mfa_enabled = data.get("mfa_enabled") self.locale = data.get("locale") @@ -95,7 +95,7 @@ def _update(self, data): self.flags = data.get("flags") self.bio = data.get("bio") - async def edit(self, *, username: Optional[str] = None, avatar: Optional[bytes] = None): + async def edit(self, *, username: Optional[str] = None, avatar: Optional[bytes] = None) -> None: payload = {} if username is not None: payload["username"] = username From 3bb752b81e95a156f6e1f59bb78cd8ab4b06faf6 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 25 Jan 2022 13:25:33 +0100 Subject: [PATCH 19/21] fix: from_dict and to_dict now working almost entirely --- nextcord/types/embed.py | 48 ++++++++++++++++++++++++++++++----------- tests/embed.py | 14 ++++++++++++ 2 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 tests/embed.py diff --git a/nextcord/types/embed.py b/nextcord/types/embed.py index 623be5e..7b26037 100644 --- a/nextcord/types/embed.py +++ b/nextcord/types/embed.py @@ -18,13 +18,14 @@ from __future__ import annotations -from dataclasses import dataclass +import typing +from dataclasses import asdict, dataclass, is_dataclass +from datetime import datetime from logging import getLogger from typing import TYPE_CHECKING, Optional, Union if TYPE_CHECKING: - from datetime import datetime - + ... logger = getLogger(__name__) @@ -81,7 +82,7 @@ def __init__(self, name: str, value: str, *, inline: Optional[bool] = None): class Embed: - _special = ["provider", "video"] + _special = {"provider": EmbedProvider, "video": EmbedVideo} __slots__ = ( "title", "description", @@ -93,8 +94,8 @@ class Embed: "thumbnail", "author", "fields", - "provider", - "video", + "_provider", + "_video", ) if TYPE_CHECKING: @@ -127,6 +128,9 @@ def __init__( self.author = author if isinstance(author, EmbedAuthor) else None self.fields = fields if isinstance(fields, list) else [] + self._provider = None + self._video = None + def add_field( self, name: str, @@ -172,22 +176,42 @@ def provider(self) -> Optional[EmbedProvider]: @classmethod def from_dict(cls, data: dict): embed = cls() + typehints = typing.get_type_hints(cls.__init__) for key, value in data.items(): + if key in typehints: + constr = typing.get_args(typehints[key])[0] + elif key in cls._special: + constr = cls._special[key] + else: + continue # Invalid key, not implemented + + if value is None: + val = None + elif isinstance(value, dict): + val = constr(**value) + else: + val = constr(value) + if key in cls._special: - setattr(embed, "_" + key, value) + setattr(embed, "_" + key, val) elif key in embed.__slots__: - setattr(embed, key, value) + setattr(embed, key, val) else: continue # TODO: Unknown key, should it raise an error? return embed - def to_dict(self) -> dict[str, Union[EmbedFile, EmbedProvider, EmbedAuthor, EmbedFooter, EmbedField]]: + def to_dict(self) -> dict[str, Union[str, dict[str, str]]]: data = {} for key in self.__slots__: - if key in cls._special: - data[key] = getattr(self, "_" + key) + key = key.lstrip("_") + if key in self._special: + val = getattr(self, "_" + key) else: - data[key] = getattr(self, key) + val = getattr(self, key) + if is_dataclass(val): + val = asdict(val) + + data[key] = val return data diff --git a/tests/embed.py b/tests/embed.py new file mode 100644 index 0000000..b03794c --- /dev/null +++ b/tests/embed.py @@ -0,0 +1,14 @@ +from nextcord.types.embed import Embed, EmbedFooter, EmbedProvider + +embed = Embed( + title="The title", description="The description", footer=EmbedFooter(text="hey", icon_url="https://discord.com/") +) +embed._provider = EmbedProvider(name="Discord", url="https://discord.com/") + +data = embed.to_dict() +print(data) +embed2 = Embed.from_dict(data) +data2 = embed2.to_dict() + +print(data2) +assert data == data2 From f66da5fc356d8fb84f9eb9fb998729509883cdb7 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 25 Jan 2022 13:28:14 +0100 Subject: [PATCH 20/21] chore: change test --- tests/embed.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/embed.py b/tests/embed.py index b03794c..addb787 100644 --- a/tests/embed.py +++ b/tests/embed.py @@ -8,6 +8,11 @@ data = embed.to_dict() print(data) embed2 = Embed.from_dict(data) +print(embed2, dir(embed2)) +for a in dir(embed2): + if not a.startswith("__"): + print(a, getattr(embed2, a)) + data2 = embed2.to_dict() print(data2) From cf51ca226dbd2369c8cc9d336bb6a5535e8140f6 Mon Sep 17 00:00:00 2001 From: Gugu7264 Date: Tue, 25 Jan 2022 13:37:44 +0100 Subject: [PATCH 21/21] refactor: rename SnowflakeArray to SnowflakeList --- nextcord/types/snowflake.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nextcord/types/snowflake.py b/nextcord/types/snowflake.py index 035b834..d6e182e 100644 --- a/nextcord/types/snowflake.py +++ b/nextcord/types/snowflake.py @@ -16,7 +16,5 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -from typing import Union - -Snowflake = Union[str, int] -SnowflakeArray = list[Snowflake] +Snowflake = int +SnowflakeList = list[Snowflake]