From d86e2d41ffa6f6065aab183b76e8b321d8b74cdf Mon Sep 17 00:00:00 2001 From: Cole <65095161+zeusec@users.noreply.github.com> Date: Thu, 28 May 2026 15:56:57 -0500 Subject: [PATCH 1/3] fix: allow ForumTag to be created without an emoji --- CHANGELOG.md | 2 ++ discord/channel.py | 23 ++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c63b835f8c..bcfc092593 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ These changes are available on the `master` branch, but have not yet been releas - Include `bypass_slowmode` in `Permissions.all`. ([#3231](https://github.com/Pycord-Development/pycord/pull/3231)) +- Allow `ForumTag` to be created without an emoji. + ([#3245](https://github.com/Pycord-Development/pycord/pull/3245)) ### Deprecated diff --git a/discord/channel.py b/discord/channel.py index 2a6d5182ac..e6253c8d5a 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -147,7 +147,7 @@ class ForumTag(Hashable): moderated: :class:`bool` Whether this tag can only be added or removed by a moderator with the :attr:`~Permissions.manage_threads` permission. - emoji: :class:`PartialEmoji` + emoji: Optional[:class:`PartialEmoji`] The emoji that is used to represent this tag. Note that if the emoji is a custom emoji, it will *not* have name information. """ @@ -155,19 +155,19 @@ class ForumTag(Hashable): __slots__ = ("name", "id", "moderated", "emoji") def __init__( - self, *, name: str, emoji: EmojiInputType, moderated: bool = False + self, *, name: str, emoji: EmojiInputType | None = None, moderated: bool = False ) -> None: self.name: str = name self.id: int = 0 self.moderated: bool = moderated - self.emoji: PartialEmoji + self.emoji: PartialEmoji | None = None if isinstance(emoji, _EmojiTag): self.emoji = emoji._to_partial() elif isinstance(emoji, str): self.emoji = PartialEmoji.from_str(emoji) - else: + elif emoji is not None: raise TypeError( - "emoji must be a GuildEmoji, PartialEmoji, or str and not" + "emoji must be a GuildEmoji, PartialEmoji, str, or None and not" f" {emoji.__class__!r}" ) @@ -189,14 +189,23 @@ def from_data(cls, *, state: ConnectionState, data: ForumTagPayload) -> ForumTag emoji_name = data["emoji_name"] or "" emoji_id = utils._get_as_snowflake(data, "emoji_id") or None - self.emoji = PartialEmoji.with_state(state=state, name=emoji_name, id=emoji_id) + if not emoji_name and not emoji_id: + self.emoji = None + else: + self.emoji = PartialEmoji.with_state( + state=state, name=emoji_name, id=emoji_id + ) return self def to_dict(self) -> dict[str, Any]: payload: dict[str, Any] = { "name": self.name, "moderated": self.moderated, - } | self.emoji._to_forum_reaction_payload() + } + if self.emoji is not None: + payload |= self.emoji._to_forum_reaction_payload() + else: + payload |= {"emoji_id": None, "emoji_name": None} if self.id: payload["id"] = self.id From 61006780095217f4dab4f963cc88c6bc30958a97 Mon Sep 17 00:00:00 2001 From: Cole <65095161+zeusec@users.noreply.github.com> Date: Fri, 29 May 2026 07:01:59 -0500 Subject: [PATCH 2/3] refactor: simplify ForumTag emoji handling per review --- discord/channel.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/discord/channel.py b/discord/channel.py index e6253c8d5a..7bce94777c 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -148,7 +148,7 @@ class ForumTag(Hashable): Whether this tag can only be added or removed by a moderator with the :attr:`~Permissions.manage_threads` permission. emoji: Optional[:class:`PartialEmoji`] - The emoji that is used to represent this tag. + The emoji that is used to represent this tag. Defaults to ``None``. Note that if the emoji is a custom emoji, it will *not* have name information. """ @@ -189,9 +189,8 @@ def from_data(cls, *, state: ConnectionState, data: ForumTagPayload) -> ForumTag emoji_name = data["emoji_name"] or "" emoji_id = utils._get_as_snowflake(data, "emoji_id") or None - if not emoji_name and not emoji_id: - self.emoji = None - else: + self.emoji = None + if emoji_name or emoji_id: self.emoji = PartialEmoji.with_state( state=state, name=emoji_name, id=emoji_id ) @@ -201,11 +200,13 @@ def to_dict(self) -> dict[str, Any]: payload: dict[str, Any] = { "name": self.name, "moderated": self.moderated, + "emoji_id": None, + "emoji_name": None, } if self.emoji is not None: - payload |= self.emoji._to_forum_reaction_payload() - else: - payload |= {"emoji_id": None, "emoji_name": None} + emoji = self.emoji._to_forum_reaction_payload() + payload["emoji_id"] = emoji["emoji_id"] + payload["emoji_name"] = emoji["emoji_name"] if self.id: payload["id"] = self.id From a632ab425687ea3a301cec79b01b820be29014ea Mon Sep 17 00:00:00 2001 From: Cole <65095161+zeusec@users.noreply.github.com> Date: Sun, 7 Jun 2026 12:04:30 -0500 Subject: [PATCH 3/3] refactor: use update for ForumTag emoji payload --- discord/channel.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/discord/channel.py b/discord/channel.py index 7bce94777c..7cb6fa2698 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -204,9 +204,7 @@ def to_dict(self) -> dict[str, Any]: "emoji_name": None, } if self.emoji is not None: - emoji = self.emoji._to_forum_reaction_payload() - payload["emoji_id"] = emoji["emoji_id"] - payload["emoji_name"] = emoji["emoji_name"] + payload.update(self.emoji._to_forum_reaction_payload()) if self.id: payload["id"] = self.id