diff --git a/discord/ext/commands/converter.py b/discord/ext/commands/converter.py index 5e767c90c..47ce8cc87 100644 --- a/discord/ext/commands/converter.py +++ b/discord/ext/commands/converter.py @@ -35,7 +35,8 @@ from .view import StringView __all__ = [ 'Converter', 'MemberConverter', 'UserConverter', 'TextChannelConverter', 'InviteConverter', 'RoleConverter', 'GameConverter', 'ColourConverter', 'VoiceChannelConverter', - 'EmojiConverter', 'IDConverter', 'clean_content' ] + 'EmojiConverter','CategoryChannelConverter', 'IDConverter', + 'clean_content' ] def _get_from_guilds(bot, getter, argument): result = None @@ -242,6 +243,46 @@ class VoiceChannelConverter(IDConverter): return result +class CategoryChannelConverter(IDConverter): + """Converts to a :class:`CategoryChannel`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by name + """ + @asyncio.coroutine + def convert(self, ctx, argument): + bot = ctx.bot + + match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument) + result = None + guild = ctx.guild + + if match is None: + # not a mention + if guild: + result = discord.utils.get(guild.categories, name=argument) + else: + def check(c): + return isinstance(c, discord.CategoryChannel) and c.name == argument + result = discord.utils.find(check, bot.get_all_channels()) + else: + channel_id = int(match.group(1)) + if guild: + result = guild.get_channel(channel_id) + else: + result = _get_from_guilds(bot, 'get_channel', channel_id) + + if not isinstance(result, discord.CategoryChannel): + raise BadArgument('Channel "{}" not found.'.format(argument)) + + return result + class ColourConverter(Converter): """Converts to a :class:`Colour`. diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst index 61ed01516..9fae23557 100644 --- a/docs/ext/commands/api.rst +++ b/docs/ext/commands/api.rst @@ -152,6 +152,12 @@ Converters .. autoclass:: discord.ext.commands.TextChannelConverter :members: +.. autoclass:: discord.ext.commands.VoiceChannelConverter + :members: + +.. autoclass:: discord.ext.commands.CategoryChannelConverter + :members: + .. autoclass:: discord.ext.commands.InviteConverter :members: @@ -164,9 +170,6 @@ Converters .. autoclass:: discord.ext.commands.ColourConverter :members: -.. autoclass:: discord.ext.commands.VoiceChannelConverter - :members: - .. autoclass:: discord.ext.commands.EmojiConverter :members: diff --git a/docs/ext/commands/commands.rst b/docs/ext/commands/commands.rst index 83371adda..dc8d7e73e 100644 --- a/docs/ext/commands/commands.rst +++ b/docs/ext/commands/commands.rst @@ -305,6 +305,7 @@ A lot of discord models work out of the gate as a parameter: - :class:`User` - :class:`TextChannel` - :class:`VoiceChannel` +- :class:`CategoryChannel` - :class:`Role` - :class:`Invite` - :class:`Game` @@ -317,27 +318,29 @@ specify. Under the hood, these are implemented by the :ref:`ext_commands_adv_converters` interface. A table of the equivalent converter is given below: -+-----------------------+----------------------------------------------+ -| Discord Class | Converter | -+-----------------------+----------------------------------------------+ -| :class:`Member` | :class:`~ext.commands.MemberConverter` | -+-----------------------+----------------------------------------------+ -| :class:`User` | :class:`~ext.commands.UserConverter` | -+-----------------------+----------------------------------------------+ -| :class:`TextChannel` | :class:`~ext.commands.TextChannelConverter` | -+-----------------------+----------------------------------------------+ -| :class:`VoiceChannel` | :class:`~ext.commands.VoiceChannelConverter` | -+-----------------------+----------------------------------------------+ -| :class:`Role` | :class:`~ext.commands.RoleConverter` | -+-----------------------+----------------------------------------------+ -| :class:`Invite` | :class:`~ext.commands.InviteConverter` | -+-----------------------+----------------------------------------------+ -| :class:`Game` | :class:`~ext.commands.GameConverter` | -+-----------------------+----------------------------------------------+ -| :class:`Emoji` | :class:`~ext.commands.EmojiConverter` | -+-----------------------+----------------------------------------------+ -| :class:`Colour` | :class:`~ext.commands.ColourConverter` | -+-----------------------+----------------------------------------------+ ++-----------------------+-------------------------------------------------+ +| Discord Class | Converter | ++-----------------------+-------------------------------------------------+ +| :class:`Member` | :class:`~ext.commands.MemberConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`User` | :class:`~ext.commands.UserConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`TextChannel` | :class:`~ext.commands.TextChannelConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`VoiceChannel` | :class:`~ext.commands.VoiceChannelConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`VoiceChannel` | :class:`~ext.commands.CategoryChannelConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`Role` | :class:`~ext.commands.RoleConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`Invite` | :class:`~ext.commands.InviteConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`Game` | :class:`~ext.commands.GameConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`Emoji` | :class:`~ext.commands.EmojiConverter` | ++-----------------------+-------------------------------------------------+ +| :class:`Colour` | :class:`~ext.commands.ColourConverter` | ++-----------------------+-------------------------------------------------+ By providing the converter it allows us to use them as building blocks for another converter: