Source code for discord.channel.category

from __future__ import annotations

from typing import TYPE_CHECKING, Any, overload

from typing_extensions import override

if TYPE_CHECKING:
    from collections.abc import Mapping

    from ..app.state import ConnectionState
    from ..guild import Guild
    from ..member import Member
    from ..permissions import PermissionOverwrite
    from ..role import Role
    from . import ForumChannel, StageChannel, TextChannel, VoiceChannel

from ..enums import ChannelType, try_enum
from ..flags import ChannelFlags
from ..types.channel import CategoryChannel as CategoryChannelPayload
from ..utils.private import copy_doc
from .base import GuildChannel, GuildTopLevelChannel


def comparator(channel: GuildChannel):
    # Sorts channels so voice channels (VoiceChannel, StageChannel) appear below non-voice channels
    return isinstance(channel, (VoiceChannel, StageChannel)), (channel.position or -1)


[docs] class CategoryChannel(GuildTopLevelChannel[CategoryChannelPayload]): """Represents a Discord channel category. These are useful to group channels to logical compartments. .. container:: operations .. describe:: x == y Checks if two channels are equal. .. describe:: x != y Checks if two channels are not equal. .. describe:: hash(x) Returns the category's hash. .. describe:: str(x) Returns the category's name. Attributes ---------- name: str The category name. guild: Guild The guild the category belongs to. id: int The category channel ID. position: int The position in the category list. This is a number that starts at 0. e.g. the top category is position 0. flags: ChannelFlags Extra features of the channel. .. versionadded:: 2.0 """ __slots__: tuple[str, ...] = () @override def __repr__(self) -> str: return f"<CategoryChannel id={self.id} name={self.name!r} position={self.position}>" @property @override def _sorting_bucket(self) -> int: return ChannelType.category.value @property def type(self) -> ChannelType: """The channel's Discord type.""" return try_enum(ChannelType, self._type)
[docs] @copy_doc(GuildChannel.clone) async def clone(self, *, name: str | None = None, reason: str | None = None) -> CategoryChannel: return await self._clone_impl({}, name=name, reason=reason)
@overload async def edit( self, *, name: str = ..., position: int = ..., overwrites: Mapping[Role | Member, PermissionOverwrite] = ..., reason: str | None = ..., ) -> CategoryChannel | None: ... @overload async def edit(self) -> CategoryChannel | None: ...
[docs] async def edit(self, *, reason=None, **options): """|coro| Edits the channel. You must have the :attr:`~Permissions.manage_channels` permission to use this. .. versionchanged:: 1.3 The ``overwrites`` keyword-only parameter was added. .. versionchanged:: 2.0 Edits are no longer in-place, the newly edited channel is returned instead. Parameters ---------- name: :class:`str` The new category's name. position: :class:`int` The new category's position. reason: Optional[:class:`str`] The reason for editing this category. Shows up on the audit log. overwrites: Dict[Union[:class:`Role`, :class:`Member`, :class:`~discord.abc.Snowflake`], :class:`PermissionOverwrite`] The overwrites to apply to channel permissions. Useful for creating secret channels. Returns ------- Optional[:class:`.CategoryChannel`] The newly edited category channel. If the edit was only positional then ``None`` is returned instead. Raises ------ InvalidArgument If position is less than 0 or greater than the number of categories. Forbidden You do not have permissions to edit the category. HTTPException Editing the category failed. """ payload = await self._edit(options, reason=reason) if payload is not None: # the payload will always be the proper channel payload return await self.__class__._from_data(data=payload, state=self._state, guild=self.guild) # type: ignore
[docs] @copy_doc(GuildTopLevelChannel.move) async def move(self, **kwargs): kwargs.pop("category", None) await super().move(**kwargs)
@property def channels(self) -> list[GuildChannelType]: """Returns the channels that are under this category. These are sorted by the official Discord UI, which places voice channels below the text channels. """ ret = [c for c in self.guild.channels if c.category_id == self.id] ret.sort(key=comparator) return ret @property def text_channels(self) -> list[TextChannel]: """Returns the text channels that are under this category.""" ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, TextChannel)] ret.sort(key=lambda c: (c.position or -1, c.id)) return ret @property def voice_channels(self) -> list[VoiceChannel]: """Returns the voice channels that are under this category.""" ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, VoiceChannel)] ret.sort(key=lambda c: (c.position or -1, c.id)) return ret @property def stage_channels(self) -> list[StageChannel]: """Returns the stage channels that are under this category. .. versionadded:: 1.7 """ ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, StageChannel)] ret.sort(key=lambda c: (c.position or -1, c.id)) return ret @property def forum_channels(self) -> list[ForumChannel]: """Returns the forum channels that are under this category. .. versionadded:: 2.0 """ ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, ForumChannel)] ret.sort(key=lambda c: (c.position or -1, c.id)) return ret
[docs] async def create_text_channel(self, name: str, **options: Any) -> TextChannel: """|coro| A shortcut method to :meth:`Guild.create_text_channel` to create a :class:`TextChannel` in the category. Returns ------- :class:`TextChannel` The channel that was just created. """ return await self.guild.create_text_channel(name, category=self, **options)
[docs] async def create_voice_channel(self, name: str, **options: Any) -> VoiceChannel: """|coro| A shortcut method to :meth:`Guild.create_voice_channel` to create a :class:`VoiceChannel` in the category. Returns ------- :class:`VoiceChannel` The channel that was just created. """ return await self.guild.create_voice_channel(name, category=self, **options)
[docs] async def create_stage_channel(self, name: str, **options: Any) -> StageChannel: """|coro| A shortcut method to :meth:`Guild.create_stage_channel` to create a :class:`StageChannel` in the category. .. versionadded:: 1.7 Returns ------- :class:`StageChannel` The channel that was just created. """ return await self.guild.create_stage_channel(name, category=self, **options)
[docs] async def create_forum_channel(self, name: str, **options: Any) -> ForumChannel: """|coro| A shortcut method to :meth:`Guild.create_forum_channel` to create a :class:`ForumChannel` in the category. .. versionadded:: 2.0 Returns ------- :class:`ForumChannel` The channel that was just created. """ return await self.guild.create_forum_channel(name, category=self, **options)