Last active
September 6, 2024 19:17
-
-
Save InterStella0/b78488fb28cadf279dfd3164b9f0cf96 to your computer and use it in GitHub Desktop.
Revisions
-
InterStella0 revised this gist
Jan 23, 2023 . 1 changed file with 15 additions and 15 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -249,7 +249,9 @@ bot = commands.Bot(command_prefix="uwu ", help_command=help_command, intents=int # Both are equivalent ``` #### Here's an example of what that looks like. ![img.png](https://user-images.githubusercontent.com/70153286/214119386-aec6c0d8-5dc5-4b46-883e-92d68f9d0c25.png) _Now, of course, this is done by default. I'm only showing you this as a demonstration. Don't scream at me_ Let's do the same thing with `MinimalHelpCommand` next. @@ -263,7 +265,7 @@ bot.help_command = commands.MinimalHelpCommand() ``` #### This is how that would look like: ![minhelpcommand.png](https://user-images.githubusercontent.com/70153286/214119201-5f301576-770c-45db-a8af-14bbee9623e4.png) ## <a name="start2"></a> Embed MinimalHelpCommand Now say, you want the content to be inside an embed. But you don't want to change the content of @@ -287,7 +289,7 @@ bot.help_command = MyNewHelp() ``` The resulting code will show that it have the content of `MinimalHelpCommand` but in an embed. ![embedminimalhelp.png](https://user-images.githubusercontent.com/70153286/214119099-ec94a584-2353-42a8-ac53-72192e02580a.png) ### How does this work? Looking over the `MinimalHelpCommand` source code, @@ -318,7 +320,7 @@ For more, [`Click here`](#utils) ## <a name="helping_flowchart"></a> HelpCommand Flowchart This is a bare minimum on what you should know on how a HelpCommand operate. As of discord version 1.* and 2.0. It remained the same flow. ![helpcommandflowchart.png](https://user-images.githubusercontent.com/70153286/214119519-5709c1cc-5aff-4249-b61f-381ad2c53840.png) Seems simple enough? Now let's see what happens if you override one of the methods. Here's an example code of how you @@ -342,7 +344,7 @@ bot.help_command = MyHelp() ``` #### Output ![hellohelpcommand.png](https://user-images.githubusercontent.com/70153286/214119950-836fc4fd-c409-4df5-aa3a-3106552d3e99.png) Keep in mind, using `HelpCommand` class will require overriding every `send_x_help` methods. For example, `<prefix>help jsk` is a command that should call `send_command_help` method. However, since `HelpCommand` is an empty class, it will not say @@ -403,7 +405,7 @@ bot.help_command = MyHelp() #### The result ![samplehelp.png](https://user-images.githubusercontent.com/70153286/214120054-9cdafc81-ec25-4285-be10-081c755e5e9c.png) **This looks pretty... terrible.** Those '|' are aliases of the command hence it appeared with a second command name. Let's make the signature prettier, and what if you wanna hide commands that you don't want to be shown @@ -441,7 +443,7 @@ bot.help_command = MyHelp() ``` #### The resulting output ![betterhelpcommand.png](https://user-images.githubusercontent.com/70153286/214120124-86ba271d-fb2e-4a01-a2f1-b4e4717540d3.png) This looks more readable than the other one with a small modification to the code. While this should cover most of your needs, you may want to know more helpful @@ -494,7 +496,7 @@ bot.help_command = MyHelp() ``` #### What you get ![commandhelpcommand.png](https://user-images.githubusercontent.com/70153286/214120186-10149671-5def-4272-9d27-f5e3515e1590.png) As you can see, it is very easy to create `<prefix>help [argument]`. The class already handles the pain of checking whether the given argument is a command, a cog, or a group command. It's up to you on how you want to display it, whether it's through @@ -550,7 +552,8 @@ bot = commands.Bot(command_prefix="uwu ", help_command=help_object, intents=inte _Note: on Number 3, Cooldown has been updated on 2.0. Please check the code on your own instead._ #### The result ![cooldownhelp.png](https://user-images.githubusercontent.com/70153286/214120265-0ed098fa-3904-4513-ab3c-04485545f0bc.png) As you can see, the name of the help command is now `"hell"`, and you can also trigger the help command by `"help"`. It will also raise an [`OnCommandCooldown`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.CommandOnCooldown) @@ -581,7 +584,7 @@ bot.help_command = MyHelp() #### The output: ![errorhelp.png](https://user-images.githubusercontent.com/70153286/214120322-911e240c-33ed-4085-a03e-ddc168420fdb.png) ### How about a local error handler? @@ -614,7 +617,7 @@ stored in `error` variable, and show the message. #### Output: ![errorhandler.png](https://user-images.githubusercontent.com/70153286/214120371-62f9bfb7-31f2-40af-af1b-069458ae661c.png) To be fair, you should create a proper error handler through this official documentation. [Here](https://discordpy.readthedocs.io/en/stable/ext/commands/commands.html#ext-commands-error-handler). @@ -669,8 +672,7 @@ If you want a generic help command, here's an example of a help command written Here's the [code](https://mystb.in/HotmailRegionalCreatures) Here's how it looks like. ![help_simple](https://user-images.githubusercontent.com/70153286/214120453-8473f167-38ba-4355-9e3c-7e51c699841b.png) For my implementation, its a bit complex. I wrote a library for myself that I use in several bots. You can see the codes through [this](https://github.com/InterStella0/starlight-dpy#menu-help-command) repository. @@ -684,8 +686,6 @@ Now, of course, any question regarding `HelpCommand` should be asked in the [dis because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice enough to them. [defhelplink]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand [minhelplink]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand -
InterStella0 revised this gist
Dec 30, 2022 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -674,10 +674,11 @@ Here's how it looks like. For my implementation, its a bit complex. I wrote a library for myself that I use in several bots. You can see the codes through [this](https://github.com/InterStella0/starlight-dpy#menu-help-command) repository. Which you're free to use if you want a quick setup for your help command. Looks like this ![menuhelpdefault.png](https://i.imgur.com/cEBKl7J.png) Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice -
InterStella0 revised this gist
Dec 30, 2022 . 1 changed file with 8 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -671,6 +671,14 @@ Here's how it looks like. ![help_simple](https://api.interstella.online/files/0300a3d728e0865a6421f527ad38972b.png) For my implementation, its a bit complex. I wrote a library for myself that I use in several bots. You can see the codes through [this](https://github.com/InterStella0/starlight-dpy#menu-help-command) repository. Looks like this ![menu_help_default](https://api.interstella.online/files/1tJOrY-CFJFoohBzZwfjf_eQxo8eBomjI.png) Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice enough to them. -
InterStella0 revised this gist
Dec 27, 2022 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -655,7 +655,9 @@ async def setup(bot): ``` ### How does it work? 1. It instantiates the HelpCommand class. `help_command = MyHelp()` 2. It assigns the instance of `YourCog`(self) into `cog` attribute. When you assign a `Cog` on a HelpCommand, discord.py will automatically know that the HelpCommand belongs to that `Cog`. It was [stated here](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.cog). # <a name="the_end"></a> The end -
InterStella0 revised this gist
Sep 21, 2022 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -324,7 +324,7 @@ operate. As of discord version 1.* and 2.0. It remained the same flow. Seems simple enough? Now let's see what happens if you override one of the methods. Here's an example code of how you would do that. This override will say `"hello!"` when you type `<prefix>help` to demonstrate on what's going on. We'll use [`HelpCommand.get_destination()`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.get_destination) to get the [`abc.Messageable`](https://discordpy.readthedocs.io/en/stable/api.html#discord.abc.Messageable) instance for sending a message to the correct channel. #### Code Example ```py -
InterStella0 revised this gist
Sep 15, 2022 . 1 changed file with 112 additions and 360 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -16,11 +16,6 @@ This guide will walkthrough the ways to create a custom help command by subclass - [Command Attributes](#command_attrs) - [Error handling for HelpCommand](#error_handling) - [Setting Cog for HelpCommand](#cog) - [The end](#the_end) @@ -116,7 +111,11 @@ For people who remove the HelpCommand? There is no handling, you have to do it y For example ##### Bad way ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="!", help_command=None, intents=intents) @bot.command() async def help(ctx, argument=None): @@ -146,7 +145,10 @@ I'm only simplifying the code. Now for the subclassed HelpCommand code. #### Good way ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="!", intents=intents) class MyHelp(commands.HelpCommand): # !help @@ -177,13 +179,12 @@ help command and formatting. | Methods / Attributes | Usage | |--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [HelpCommand.filter_commands()][Hgetfilter] | Filter commands to only show commands that the user can run. This help hide any secret commands from the general user. | | [Context.clean_prefix][Hgetcleanprefix] | HelpCommand.clean_prefix was removed in version 2.0 of discord.py and replaced with `Context.clean_prefix`. This cleans your prefix from @everyone and @here as well as @mentions | | [HelpCommand.get_command_signature()][Hgetcommandsig] | Get the command signature and format them such as `command [argument]` for optional and `command <argument>` for required. | | [HelpCommand.prepare_help_command()][Hgetprepare] | Triggers before every `send_x_help` method are triggered, this work exactly like `command.before_invoke` | | [HelpCommand.get_bot_mapping()][Hgetbotmap] | Get all command that are available in the bot, sort them by Cogs and None for No Category as key in a dictionary. This method is triggered before HelpCommand.send_bot_help is triggered, and will get passed as the parameter. | | [HelpCommand.get_destination()][Hgetdestination] | Returns a Messageable on where the help command was invoked. | | [HelpCommand.command_callback][Hcommandcallback] | The method that handles all `help/help cog/ help command/ help group` and call which method appropriately. This is useful if you want to modify the behaviour of this. Though more knowledge is needed for you to do that. Most don't use this. | | [Context.send_help()][Csendhelp] | Calling `send_command_help` based on what the Context command object were. This is useful to be used when the user incorrectly invoke the command. Which you can call this method to show help quickly and efficiently. (Only works if you have HelpCommand configured) | All of this does not exist when you set `bot.help_command` to `None`. You miss out on this. @@ -193,12 +194,13 @@ All of this does not exist when you set `bot.help_command` to `None`. You miss o Since it's a class, most people would make it modular. They put it in a cog for example. There is a common code given in `discord.py` created by Vex. ```python from discord.ext import commands class MyHelpCommand(commands.MinimalHelpCommand): pass class MyCog(commands.Cog): def __init__(self, bot): self.bot = bot self._original_help_command = bot.help_command bot.help_command = MyHelpCommand() bot.help_command.cog = self @@ -230,32 +232,38 @@ There are a few types of HelpCommand classes that you can choose; 3. [`HelpCommand`][helplink] an empty class that is the base class for every HelpCommand you see. On its own, it will not do anything. By default, help command is using the class `DefaultHelpCommand`. This is stored in [`bot.help_command`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Bot.help_command). This attribute will **ONLY** accept instances that subclasses `HelpCommand`. Here is how you were to use the `DefaultHelpCommand` instance. ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) bot.help_command = commands.DefaultHelpCommand() # OR help_command = commands.DefaultHelpCommand() intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", help_command=help_command, intents=intents) # Both are equivalent ``` #### Here's an example of what that looks like. ![img.png](https://api.interstella.online/files/1f54f18049c21749d698a53d4ee51f67.png) _Now, of course, this is done by default. I'm only showing you this as a demonstration. Don't scream at me_ Let's do the same thing with `MinimalHelpCommand` next. ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) bot.help_command = commands.MinimalHelpCommand() ``` #### This is how that would look like: ![minhelpcommand.png](https://api.interstella.online/files/38c1093d90160ae088775f08271e1d10.png) ## <a name="start2"></a> Embed MinimalHelpCommand Now say, you want the content to be inside an embed. But you don't want to change the content of @@ -265,7 +273,8 @@ shows this; ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyNewHelp(commands.MinimalHelpCommand): async def send_pages(self): @@ -278,11 +287,11 @@ bot.help_command = MyNewHelp() ``` The resulting code will show that it have the content of `MinimalHelpCommand` but in an embed. ![embedminimalhelp.png](https://api.interstella.online/files/7249032df857067e629402f308f21db3.png) ### How does this work? Looking over the `MinimalHelpCommand` source code, every method that is responsible for `<prefix>help <argument>` will call [`MinimalHelpCommand.send_pages`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand.send_pages) when it is about to send the content. This makes it easy to just override `send_pages` without having to override any other method there are in `MinimalHelpCommand`. @@ -293,39 +302,36 @@ Here are a list of HelpCommand relevant methods, and it's responsibility. 1. [`HelpCommand.send_bot_help(mapping)`][sendbothelp] Gets called with `<prefix>help` 2. [`HelpCommand.send_command_help(command)`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.send_command_help) Gets called with `<prefix>help <command>` 3. [`HelpCommand.send_group_help(group)`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.send_group_help) Gets called with `<prefix>help <group>` 4. [`HelpCommand.send_cog_help(cog)`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.send_cog_help) Gets called with `<prefix>help <cog>` ## <a name="helping2"></a> Useful attributes 1. [`HelpCommand.context`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.context) the Context object in the help command. For more, [`Click here`](#utils) ## <a name="helping_flowchart"></a> HelpCommand Flowchart This is a bare minimum on what you should know on how a HelpCommand operate. As of discord version 1.* and 2.0. It remained the same flow. ![helpcommandflowchart.png](https://api.interstella.online/files/f163936e78b72859af8b90aa4e02bfb0.png) Seems simple enough? Now let's see what happens if you override one of the methods. Here's an example code of how you would do that. This override will say `"hello!"` when you type `<prefix>help` to demonstrate on what's going on. We'll use [`HelpCommand.get_destination()`(https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.get_destination) to get the [`abc.Messageable`](https://discordpy.readthedocs.io/en/stable/api.html#discord.abc.Messageable) instance for sending a message to the correct channel. #### Code Example ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyHelp(commands.HelpCommand): async def send_bot_help(self, mapping): @@ -336,7 +342,7 @@ bot.help_command = MyHelp() ``` #### Output ![hellohelpcommand.png](https://api.interstella.online/files/89ab6cfbc5a086c6f103bd47c3d6bca7.png) Keep in mind, using `HelpCommand` class will require overriding every `send_x_help` methods. For example, `<prefix>help jsk` is a command that should call `send_command_help` method. However, since `HelpCommand` is an empty class, it will not say @@ -349,9 +355,9 @@ as its parameter. `await` indicates that it should be an async function. ### What does this mean? * `Mapping[]` is a [`collections.abc.Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping), for simplicity’s sake, this usually refers to a dictionary since it's under `collections.abc.Mapping`. * `Optional[Cog]` is a [`Cog`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Cog) object that has a chance to be `None`. * `List[Command]` is a list of [`Command`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Command) objects. * `Mapping[Optional[Cog], List[Command]]` means it's a map object with `Optional[Cog]` as it's key and `List[Command]` as its value. @@ -366,7 +372,8 @@ form. ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyHelp(commands.HelpCommand): async def send_bot_help(self, mapping): @@ -390,35 +397,34 @@ bot.help_command = MyHelp() 4. If the list is empty, meaning, no commands is available in the cog, we don't need to show it, hence `if command_signatures:`. 5. `cog` has a chance to be `None`, this refers to No Category. We'll use [`getattr`](https://docs.python.org/3/library/functions.html#getattr) to avoid getting an error to get cog's name through [`Cog.qualified_name`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Cog.qualified_name). 6. Using [`str.join`](https://docs.python.org/3/library/stdtypes.html#str.join) each command will be displayed on a separate line. 7. Once all of this is finished, display it. #### The result ![samplehelp.png](https://api.interstella.online/files/9d68a4eebee8ed02ff68e7b7b2dfa025.png) **This looks pretty... terrible.** Those '|' are aliases of the command hence it appeared with a second command name. Let's make the signature prettier, and what if you wanna hide commands that you don't want to be shown on the help command? Such as "sync" command there, that's only for the developer not other people. We'll subclass `commands.MinimalHelpCommand` to use their `MinimalHelpCommand.get_command_signature`. It's actually more prettier than the default HelpCommand signature. We'll use [`HelpCommand.filter_commands`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.filter_commands), this method will filter commands by removing any commands that the user cannot use. It is a handy method to use. This works by checking if the [`Command.hidden`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Command.hidden) is set to True and, it will run [`Command.can_run`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Command.can_run) to see if it raise any errors. If there is any, it will be filtered. #### The Example ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyHelp(commands.MinimalHelpCommand): async def send_bot_help(self, mapping): embed = discord.Embed(title="Help") for cog, commands in mapping.items(): @@ -435,9 +441,10 @@ bot.help_command = MyHelp() ``` #### The resulting output ![betterhelpcommand.png](https://api.interstella.online/files/4f93ced5a00e006b143bf2a9dd75cbe8.png) This looks more readable than the other one with a small modification to the code. While this should cover most of your needs, you may want to know more helpful attribute that is available on `HelpCommand` in the official documentation. ## <a name="helping_guide2"></a> help [argument] command @@ -453,14 +460,14 @@ you have show is the attribute of the command. For example, this is your command code, your goal is you want to show the `help`,`aliases` and the `signature`. #### Command Code ```py @bot.command(help="Generic help command for command hello.", aliases=["h", "hellos", "hell", "hehe"]) async def hello(ctx, bot: discord.Member): pass ``` Then it's simple, you can display each of the attribute by [`Command.help`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Command.help) and [`Command.aliases`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Command.aliases). For the signature, instead of using the previous `get_command_signature`, we're going to subclass `MinimalHelpCommand`. @@ -469,7 +476,8 @@ For the signature, instead of using the previous `get_command_signature`, we're ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyHelp(commands.MinimalHelpCommand): async def send_command_help(self, command): @@ -486,24 +494,24 @@ bot.help_command = MyHelp() ``` #### What you get ![commandhelpcommand.png](https://api.interstella.online/files/03ce5349b8dc02203d17ca85712eaf8a.png) As you can see, it is very easy to create `<prefix>help [argument]`. The class already handles the pain of checking whether the given argument is a command, a cog, or a group command. It's up to you on how you want to display it, whether it's through a plain message, an embed or even using [`discord.ext.menus`](https://github.com/Rapptz/discord-ext-menus). ## <a name="command_attrs"></a> Command Attributes Let's say, someone is spamming your help command. For a normal command, all you have to do to combat this is using a [`cooldown`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.cooldown) decorator and slap that thing above the command declaration. Or, what about if you want an alias? Usually, you would put an aliases kwargs in the [`command`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Bot.command) decorator. However, HelpCommand is a bit special, It's a god damn class. You can't just put a decorator on it and expect it to work. That is when [`HelpCommand.command_attrs`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.command_attrs) come to the rescue. This attribute can be set during the HelpCommand declaration, or a direct attribute assignment. According to the documentation, it accepts exactly the same thing as a [`command`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Bot.command) decorator in a form of a dictionary. For example, we want to rename the help command as `"hell"` instead of `"help"` for whatever reason. We also want to make @@ -512,15 +520,15 @@ because help command messages are big, and we don't want people to spam those. S #### Example Code ```py import discord from discord.ext import commands intents = discord.Intents.all() attributes = { 'name': "hell", 'aliases': ["help", "helps"], 'cooldown': commands.CooldownMapping.from_cooldown(2, 5.0, commands.BucketType.user) } # During declaration help_object = commands.MinimalHelpCommand(command_attrs=attributes) @@ -529,23 +537,23 @@ help_object = commands.MinimalHelpCommand(command_attrs=attributes) help_object = commands.MinimalHelpCommand() help_object.command_attrs = attributes bot = commands.Bot(command_prefix="uwu ", help_command=help_object, intents=intents) ``` ### How does it work? 1. sets the name into `"hell"` is refers to here `'name': "hell"`. 2. sets the aliases by passing the list of `str` to the `aliases` key, which refers to here `'aliases': ["help", "helps"]`. 3. sets the cooldown through the `"cooldown"` key by passing in a `CooldownMapping` object. This object will make a cooldown with a rate of 2, per 5 with a bucket type [`BucketType.user`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.BucketType), which in simple terms, for every [`discord.User`](https://discordpy.readthedocs.io/en/stable/api.html#discord.User), they can call the command twice, every 5 seconds. 4. We're going to use `MinimalHelpCommand` as the `HelpCommand` object. _Note: on Number 3, Cooldown has been updated on 2.0. Please check the code on your own instead._ #### The result ![cooldownhelp.png](https://api.interstella.online/files/240bd5fb1ab76206b87bffa21dbf2dbb.png) As you can see, the name of the help command is now `"hell"`, and you can also trigger the help command by `"help"`. It will also raise an [`OnCommandCooldown`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.CommandOnCooldown) error if it was triggered 3 times in 5 seconds due to our `Cooldown` object. Of course, I didn't show that in the result, but you can try it yourself. You should handle the error in an error handler when an `OnCommandCooldown` is raised. @@ -558,7 +566,8 @@ be called. HelpCommand will not call `on_command_error` when it can't find an ex ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyHelp(commands.HelpCommand): async def send_error_message(self, error): @@ -572,18 +581,19 @@ bot.help_command = MyHelp() #### The output: ![errorhelp.png](https://api.interstella.online/files/5d4923d27b85752dd10db55471c0da00.png) ### How about a local error handler? Indeed, we have it. [`HelpCommand.on_help_command_error`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.on_help_command_error), this method is responsible for handling any error just like any other local error handler. #### Code ```py import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix="uwu ", intents=intents) class MyHelp(commands.HelpCommand): async def send_bot_help(self, mapping): @@ -604,20 +614,18 @@ stored in `error` variable, and show the message. #### Output: ![errorhandler.png](https://api.interstella.online/files/5413ab5d5e2f8251ecd998fda9058d38.png) To be fair, you should create a proper error handler through this official documentation. [Here](https://discordpy.readthedocs.io/en/stable/ext/commands/commands.html#ext-commands-error-handler). There is also a lovely example by `Mysty` on error handling in general. [Here](https://gist.github.com/EvieePy/7822af90858ef65012ea500bcecf1612). This example shows how to properly create a global error handler and local error handler. ## <a name="cog"></a> Setting Cog for HelpCommand ### Super easy lol It works just like setting a cog on a Command object, you basically have to assign a [`commands.Cog`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Cog) instance into [`HelpCommand.cog`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.cog). It is pretty common for discord.py users to put a HelpCommand into a cog/separate file since people want organization. ### Code Example This code example is if you're in a Cog file, which you have access to a Cog instance @@ -642,297 +650,41 @@ class YourCog(commands.Cog): bot.help_command = help_command async def setup(bot): await bot.add_cog(YourCog(bot)) ``` ### How does it work? 1. It instantiates the HelpCommand class. `help_command = MyHelp()` 2. It assigns the instance of `YourCog`(self) into `cog` attribute # <a name="the_end"></a> The end I hope that reading this walkthrough will assist you and give a better understanding on how to subclass [`HelpCommand`][helplink]. All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of creative things you can do to create a `HelpCommand`. If you want a generic help command, here's an example of a help command written by pikaninja Here's the [code](https://mystb.in/HotmailRegionalCreatures) Here's how it looks like. ![help_simple](https://api.interstella.online/files/0300a3d728e0865a6421f527ad38972b.png) Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice enough to them. If you're still confused about paginator, I've made a full walkthrough regarding menus and View pagination. [Click Here](https://gist.github.com/InterStella0/454cc51e05e60e63b81ea2e8490ef140) [defhelplink]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand [minhelplink]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand [helplink]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand [sendbothelp]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.send_bot_help [Hgetcommandsig]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.get_command_signature [Hgetbotmap]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.get_bot_mapping [Hgetdestination]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.get_destination [Hgetprepare]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.prepare_help_command [Hgetcleanprefix]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Context.clean_prefix [Hgetfilter]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.filter_commands [Csendhelp]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Context.send_help [Hcommandcallback]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.command_callback -
InterStella0 revised this gist
Aug 3, 2022 . 1 changed file with 9 additions and 9 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -303,7 +303,7 @@ Here are a list of HelpCommand relevant methods, and it's responsibility. ## <a name="helping2"></a> Useful attributes 1. [`HelpCommand.context`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.context) the Context object in the help command. 2. [`HelpCommand.clean_prefix`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.clean_prefix) a cleanup prefix version that remove any mentions. For more, [`Click here`](#utils) @@ -540,6 +540,7 @@ bot = commands.Bot(command_prefix="uwu ", help_command=help_object) they can call the command twice, every 5 seconds. 4. We're going to use `MinimalHelpCommand` as the `HelpCommand` object. _Note: on Number 3, Cooldown has been updated on 2.0. Please check the code on your own instead._ #### The result ![cooldownhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789471505145659412/unknown.png) @@ -722,11 +723,11 @@ With the introduction of Buttons in 2.0. We are able to use them as a replacemen can even re-use the code in `MenuPages` and recreate them for pagination. Similar to `MenuPages`, we have `View` that handles all the interaction with the user. This can be use in `Button`, `Select`. It is documented [here](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.ui.View). There are example usage for `View` written by Danny himself. This will help you understand how to use them, as I won't be explaining every niche things about them. The example is found [here](https://github.com/Rapptz/discord.py/blob/master/examples/views/tic_tac_toe.py) where he wrote a tictactoe game with [`View`](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.ui.View) and [`Button`](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.Button). In order to create a Pagination view, we will also subclass the `MenuPages` class to borrow the features that are available from them. They handle the pages for us, which is insanely useful thanks to Danny's way of coding. @@ -796,10 +797,10 @@ class MyMenuPages(ui.View, menus.MenuPages): 2. We won't call `super().start(...)` because those handles reactions, we're only borrowing the methods from them. 3. `timeout=60` kwargs is passed to `ui.View`, Not `menus.MenuPages`. To understand how this works, learn Method Resolution Order (MRO). As I won't be covering them here. 4. [`View.interaction_check`](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.ui.View.interaction_check) is for the check. You can check if the interaction is your author. Returns True will result in calling the Button callback. Raising an error or returning False will prevent them from being called. 5. [`ui.button`](https://discordpy.readthedocs.io/en/latest/interactions/api.html#discord.ui.button) basically is the button you're adding to `View`. 6. for `show_check_page`/`show_page` are explained in the `1.7.x` section. [Jump Here](#paginate_help_1_7) 7. [`message.delete(delay=0)`](https://discordpy.readthedocs.io/en/latest/api.html#discord.Message.delete) is a way to @@ -910,8 +911,7 @@ If you need an inspiration, this is my help command. I mean, nobody asked but ye ![helpEx](https://cdn.discordapp.com/attachments/784735050071408670/853268304565895188/unknown.png) Here's my code if you want to take a look. It's a bit complicated, but you only have to focus on the HelpCommand class [my help command](https://github.com/InterStella0/stella_bot/tree/master/cogs/helpful/help_command). If you want a more easier help command, here's an example of a help command written by pikaninja Here's the [code](https://mystb.in/EthicalBasketballPoliticians.python) Here's how it looks like. @@ -933,6 +933,6 @@ If you're still confused about paginator, I've made a full walkthrough regarding [Hgetbotmap]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.get_bot_mapping [Hgetdestination]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.get_destination [Hgetprepare]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.prepare_help_command [Hgetcleanprefix]: https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.HelpCommand.clean_prefix [Hgetfilter]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.filter_commands [Csendhelp]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Context.send_help -
InterStella0 revised this gist
Jun 27, 2022 . 1 changed file with 10 additions and 5 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -764,26 +764,31 @@ class MyMenuPages(ui.View, menus.MenuPages): return interaction.user == self.ctx.author @ui.button(emoji='<:before_fast_check:754948796139569224>', style=discord.ButtonStyle.blurple) async def first_page(self, interaction, button): await self.show_page(0) await interaction.response.defer() @ui.button(emoji='<:before_check:754948796487565332>', style=discord.ButtonStyle.blurple) async def before_page(self, interaction, button): await self.show_checked_page(self.current_page - 1) await interaction.response.defer() @ui.button(emoji='<:stop_check:754948796365930517>', style=discord.ButtonStyle.blurple) async def stop_page(self, interaction, button): await interaction.response.defer() self.stop() if self.delete_message_after: await self.message.delete(delay=0) @ui.button(emoji='<:next_check:754948796361736213>', style=discord.ButtonStyle.blurple) async def next_page(self, interaction, button): await self.show_checked_page(self.current_page + 1) await interaction.response.defer() @ui.button(emoji='<:next_fast_check:754948796391227442>', style=discord.ButtonStyle.blurple) async def last_page(self, interaction, button): await self.show_page(self._source.get_max_pages() - 1) await interaction.response.defer() ``` **Explanation** 1. `ui.View` contains all the handling of Button interaction. While, we also need partial use of `menus.MenuPages` where -
InterStella0 revised this gist
Mar 19, 2022 . 1 changed file with 7 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,6 +10,7 @@ This guide will walkthrough the ways to create a custom help command by subclass - [HelpCommand](#helping) - [Basic method to override](#helping1) - [Useful Attributes](#helping2) - [Flowchart](#helping_flowchart) - [help command](#helping_guide1) - [help \<argument>](#helping_guide2) - [Command Attributes](#command_attrs) @@ -307,6 +308,12 @@ Here are a list of HelpCommand relevant methods, and it's responsibility. For more, [`Click here`](#utils) ## <a name="helping_flowchart"></a> HelpCommand Flowchart This is a bare minimum on what you should know on how a HelpCommand operate. As of discord version 1.* and 2.0. It remained the same flow. ![helpcommandflowchart.png](https://cdn.discordapp.com/attachments/777501555687292928/954724489625747466/help_command_flowchart.png) Seems simple enough? Now let's see what happens if you override one of the methods. Here's an example code of how you would do that. This override will say `"hello!"` when you type `<prefix>help` to demonstrate on what's going on. -
InterStella0 revised this gist
Dec 11, 2021 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -654,6 +654,8 @@ if it won't ever reach 2.0"_. I will answer that by saying it is still useful fo can even use this for other pagination, not just for help command. Even with 2.0, you will be able to use this efficiently with buttons. I will show that later in the walkthrough. Another walkthrough I made regarding paginator, here I talk about it more in depth. [click here](https://gist.github.com/InterStella0/454cc51e05e60e63b81ea2e8490ef140) ### <a name="paginate_help_1_7"></a> Pagination for 1.7.x Now for the people who have never use ext-menus before, you may be asking me, _"Stella, what the hell is a MenuPages class"_. To explain, this class inherits Menu class which handles everything @@ -908,6 +910,8 @@ Now, of course, any question regarding `HelpCommand` should be asked in the [dis because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice enough to them. :D If you're still confused about paginator, I've made a full walkthrough regarding menus and View pagination. [Click Here](https://gist.github.com/InterStella0/454cc51e05e60e63b81ea2e8490ef140) [defhelplink]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand [minhelplink]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand -
InterStella0 revised this gist
Sep 4, 2021 . 1 changed file with 251 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,6 +15,11 @@ This guide will walkthrough the ways to create a custom help command by subclass - [Command Attributes](#command_attrs) - [Error handling for HelpCommand](#error_handling) - [Setting Cog for HelpCommand](#cog) - [Paginated Help Command](#paginate_help) - [Pagination for 1.7.x](#paginate_help_1_7) - [Pagination for 2.x](#paginate_help_2) - [ListPageSource class](#list_page_source) - [Integrating classes of pagination](#help_pagination_intergrate) - [The end](#the_end) @@ -636,6 +641,252 @@ def setup(bot): 1. It instantiates the HelpCommand class. `help_command = MyHelp()` 2. It assigns the instance of `YourCog`(self) into `cog` attribute # <a name="paginate_help"></a> Paginated Help Command Seems like there are a lot of request for this to be made, and my original plan was to wait for menus to be integrated with buttons. However, looking at the current event of where it seems like that won't happen. To clarify, I will not be walking through all of the specific feature that the classes I'm using in this tutorial. In this part, we will be using [discord-ext-menus](https://github.com/Rapptz/discord-ext-menus) to handle our pagination. This is an external library that Danny wrote that seems to never reached 2.0. You might be asking, _"why even bother using it if it won't ever reach 2.0"_. I will answer that by saying it is still useful for pagination use. You can even use this for other pagination, not just for help command. Even with 2.0, you will be able to use this efficiently with buttons. I will show that later in the walkthrough. ### <a name="paginate_help_1_7"></a> Pagination for 1.7.x Now for the people who have never use ext-menus before, you may be asking me, _"Stella, what the hell is a MenuPages class"_. To explain, this class inherits Menu class which handles everything such as waiting for user reactions, and adding reactions to your message. You can do fun things with Menu class such as a confirmation message with reactions which are shown [here](https://github.com/Rapptz/discord-ext-menus#getting-started). But for our use, we will use them as the button for the pagination. For MenuPages, this class is specifically for handling pages, when you click on a reaction, it will show you the next page. Now, here are the basic implementation for our use. **Code Example For MenuPages** ```python import discord from discord.ext import menus class MyMenuPages(menus.MenuPages, inherit_buttons=False): @menus.button("<:before_check:754948796487565332>", position=menus.First(1)) async def go_before(self, payload): """Goes to the previous page.""" await self.show_checked_page(self.current_page - 1) @menus.button("<:next_check:754948796361736213>", position=menus.Last(0)) async def go_after(self, payload): """Goes to the next page.""" await self.show_checked_page(self.current_page + 1) @menus.button("<:before_fast_check:754948796139569224>", position=menus.First(0)) async def go_first(self, payload): """Goes to the first page.""" await self.show_page(0) @menus.button("<:next_fast_check:754948796391227442>", position=menus.Last(1)) async def go_last(self, payload): """Goes to the last page.""" await self.show_page(self._source.get_max_pages() - 1) @menus.button("<:stop_check:754948796365930517>", position=menus.First(2)) async def go_stop(self, payload): """Remove this message.""" self.stop() ``` **Explanation** 1. `inherit_buttons` kwargs is set to False, this is to remove all default `menus.button` to set it your own. 2. `MenuPages.show_page` is to show the page at a position that you gave, in this case, `0`. 3. `MenuPages.show_checked_page` is to show a page, similar to `show_page`, but this will check if the position exist. `IndexError` error are ignored when it is raised. 4. `First`/`Last` class is an anchor during adding reaction. For example, when given as `First(0)`, `Last(0)`, `First(1)` `First(2)`, `Last(1)`. Regardless of order, `First(0)` reaction will be added first, followed by `First(1)`, `First(2)`. After that, `Last(0)` and `Last(1)` are added. There are also `Position`, but I don't use them here. 5. `MenuPages.stop()` will end the menu session, you can set them to delete the message by `delete_message_after` or `clear_reactions_after` to clear the reactions after the menu session ended. You will need to create `ListPageSource` class to use with this class. [Jump Here](#list_page_source) ### <a name="paginate_help_2"></a> Pagination for 2.x With the introduction of Buttons in 2.0. We are able to use them as a replacement of `MenuPages`. In fact, we can even re-use the code in `MenuPages` and recreate them for pagination. Similar to `MenuPages`, we have `View` that handles all the interaction with the user. This can be use in `Button`, `Select`. It is documented [here](https://discordpy.readthedocs.io/en/master/api.html#discord.ui.View). There are example usage for `View` written by Danny himself. This will help you understand how to use them, as I won't be explaining every niche things about them. The example is found [here](https://github.com/Rapptz/discord.py/blob/master/examples/views/tic_tac_toe.py) where he wrote a tictactoe game with [`View`](https://discordpy.readthedocs.io/en/master/api.html#discord.ui.View) and [`Button`](https://discordpy.readthedocs.io/en/master/api.html#discord.Button). In order to create a Pagination view, we will also subclass the `MenuPages` class to borrow the features that are available from them. They handle the pages for us, which is insanely useful thanks to Danny's way of coding. **Example Code for View Button** ```py import discord from discord import ui from discord.ext import menus class MyMenuPages(ui.View, menus.MenuPages): def __init__(self, source, *, delete_message_after=False): super().__init__(timeout=60) self._source = source self.current_page = 0 self.ctx = None self.message = None self.delete_message_after = delete_message_after async def start(self, ctx, *, channel=None, wait=False): # We wont be using wait/channel, you can implement them yourself. This is to match the MenuPages signature. await self._source._prepare_once() self.ctx = ctx self.message = await self.send_initial_message(ctx, ctx.channel) async def _get_kwargs_from_page(self, page): """This method calls ListPageSource.format_page class""" value = await super()._get_kwargs_from_page(page) if 'view' not in value: value.update({'view': self}) return value async def interaction_check(self, interaction): """Only allow the author that invoke the command to be able to use the interaction""" return interaction.user == self.ctx.author @ui.button(emoji='<:before_fast_check:754948796139569224>', style=discord.ButtonStyle.blurple) async def first_page(self, button, interaction): await self.show_page(0) @ui.button(emoji='<:before_check:754948796487565332>', style=discord.ButtonStyle.blurple) async def before_page(self, button, interaction): await self.show_checked_page(self.current_page - 1) @ui.button(emoji='<:stop_check:754948796365930517>', style=discord.ButtonStyle.blurple) async def stop_page(self, button, interaction): self.stop() if self.delete_message_after: await self.message.delete(delay=0) @ui.button(emoji='<:next_check:754948796361736213>', style=discord.ButtonStyle.blurple) async def next_page(self, button, interaction): await self.show_checked_page(self.current_page + 1) @ui.button(emoji='<:next_fast_check:754948796391227442>', style=discord.ButtonStyle.blurple) async def last_page(self, button, interaction): await self.show_page(self._source.get_max_pages() - 1) ``` **Explanation** 1. `ui.View` contains all the handling of Button interaction. While, we also need partial use of `menus.MenuPages` where it handles the core of pagination. This include calling `ListPageSource.format_page` which will be use. 2. We won't call `super().start(...)` because those handles reactions, we're only borrowing the methods from them. 3. `timeout=60` kwargs is passed to `ui.View`, Not `menus.MenuPages`. To understand how this works, learn Method Resolution Order (MRO). As I won't be covering them here. 4. [`View.interaction_check`](https://discordpy.readthedocs.io/en/master/api.html#discord.ui.View.interaction_check) is for the check. You can check if the interaction is your author. Returns True will result in calling the Button callback. Raising an error or returning False will prevent them from being called. 5. [`ui.button`](https://discordpy.readthedocs.io/en/master/api.html#discord.ui.button) basically is the button you're adding to `View`. 6. for `show_check_page`/`show_page` are explained in the `1.7.x` section. [Jump Here](#paginate_help_1_7) 7. [`message.delete(delay=0)`](https://discordpy.readthedocs.io/en/latest/api.html#discord.Message.delete) is a way to delete message without checking if they exist. When error, it silences them. You will need to create `ListPageSource` class to use with this class. [Jump Here](#list_page_source) ### <a name="list_page_source"></a> ListPageSource class As I stated before, `ListPageSource` are only from the external library `discord-ext-menus`. Make sure to install them. Now `MyMenuPages` are created for our use, lets create our `ListPageSource` now. To put it simply, `ListPageSource` is to format each page where `MyMenuPages` will call this class. There are also other types of class format. However, I will just use `ListPageSource` for simplicity sake. If you want to read more about `ListPageSource`, you can read them here. [Click Here](https://github.com/Rapptz/discord-ext-menus#pagination). Now this will be our basic implementation of `ListPageSource`. **Example Code For ListPageSource** ```py import discord from itertools import starmap from discord.ext import menus class HelpPageSource(menus.ListPageSource): def __init__(self, data, helpcommand): super().__init__(data, per_page=6) self.helpcommand = helpcommand def format_command_help(self, no, command): signature = self.helpcommand.get_command_signature(command) docs = self.helpcommand.get_command_brief(command) return f"{no}. {signature}\n{docs}" async def format_page(self, menu, entries): page = menu.current_page max_page = self.get_max_pages() starting_number = page * self.per_page + 1 iterator = starmap(self.format_command_help, enumerate(entries, start=starting_number)) page_content = "\n".join(iterator) embed = discord.Embed( title=f"Help Command[{page + 1}/{max_page}]", description=page_content, color=0xffcccb ) author = menu.ctx.author embed.set_footer(text=f"Requested by {author}", icon_url=author.avatar_url) # author.avatar in 2.0 return embed ``` **Explanation** 1. `per_page` kwargs is the amount of elements from `data` that will be passed to `ListPageSource.format_page` as `entries`. 2. `starting_number` is just the starting number for the list of 6 that will be shown. So for example, at page 1, it will be 1, at page 2, it will be 13 and page 3 would be 19. `menu.current_page` will start at 0, hence we add 1.` 3. [`itertools.starmap`](https://docs.python.org/3/library/itertools.html#itertools.starmap) works exactly like `map` but it unpacks the argument when calling a function, in this case, `HelpPageSource.format_command_help`. 4. We can get Context from `menu.ctx` attribute. 5. For `ListPageSource.format_page`, whatever you return from this method, will be shown as a single page. You can return a `discord.Embed`, a `str` or a `dict` that will be as kwargs for `message.edit`. The output of them are in the [Integrating class of pagination](#help_pagination_intergrate) section. ### <a name="help_pagination_intergrate"></a> Integrating classes of pagination Now we will be creating the HelpCommand that uses classes that we've made. This HelpCommand class will also be able to use the 2.0 button. Hence, why it's in its own section. **Example Code** ```py import discord from itertools import chain from discord.ext import commands class MyHelp(commands.MinimalHelpCommand): def get_command_brief(self, command): return command.short_doc or "Command is not documented." async def send_bot_help(self, mapping): all_commands = list(chain.from_iterable(mapping.values())) formatter = HelpPageSource(all_commands, self) menu = MyMenuPages(formatter, delete_message_after=True) await menu.start(self.context) bot = commands.Bot("uwu ", help_command=MyHelp()) ``` **Explanation** 1. [`itertools.chain.from_iterable`](https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable) flatten the result of `mapping.values()` into a single list. This is up to you on how you want to handle the command. I'm just making it flat to be as basic as possible. 2. `HelpPageSource` acts as the formatter, this class will be the one that gets the data and the one that shows each page to the user. 3. `MyMenuPages` depending on which class you're using, this will handle the `HelpPageSource` class. It will handle the buttons from the user, and determine whether to show the previous/next/forward/backward or stop. 4. [`Command.short_doc`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Command.short_doc) will show the value from `Command.brief` or if None, show the first sentence of `Command.help`. ### The Output for 1.7.x ![helpMenu](https://cdn.discordapp.com/attachments/652696440396840963/883637607882457099/unknown.png) ### The Output for 2.x ![helpMenu](https://cdn.discordapp.com/attachments/652696440396840963/883635346271764481/unknown.png) # <a name="the_end"></a> The end I hope that reading this walkthrough will assist you and give a better understanding on how to subclass [`HelpCommand`][helplink]. All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of -
InterStella0 revised this gist
Jun 30, 2021 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -506,7 +506,9 @@ attributes = { 'name': "hell", 'aliases': ["help", "helps"], 'cooldown': commands.Cooldown(2, 5.0, commands.BucketType.user) } # For 2.0, you would use CooldownMapping.from_cooldown(rate, per, type) # because Cooldown no longer have type as it's arguments. # During declaration help_object = commands.MinimalHelpCommand(command_attrs=attributes) -
InterStella0 revised this gist
Jun 27, 2021 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -647,7 +647,8 @@ HelpCommand class [my help command](https://github.com/InterStella0/stella_bot/b If you want a more easier help command, here's an example of a help command written by pikaninja Here's the [code](https://mystb.in/EthicalBasketballPoliticians.python) Here's how it looks like. ![help_simple](https://cdn.discordapp.com/attachments/652696440396840963/858616279715676180/unknown.png) Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server -
InterStella0 revised this gist
Jun 27, 2021 . 1 changed file with 5 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -645,6 +645,11 @@ If you need an inspiration, this is my help command. I mean, nobody asked but ye Here's my code if you want to take a look. It's a bit complicated, but you only have to focus on the HelpCommand class [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py). If you want a more easier help command, here's an example of a help command written by pikaninja Here's the [code](https://mystb.in/EthicalBasketballPoliticians.python) Here's how it looks like ![help_simple](https://cdn.discordapp.com/attachments/652696440396840963/858616279715676180/unknown.png) Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice enough to them. :D -
InterStella0 revised this gist
Jun 15, 2021 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -547,7 +547,7 @@ bot = commands.Bot(command_prefix="uwu ") class MyHelp(commands.HelpCommand): async def send_error_message(self, error): embed = discord.Embed(title="Error", description=error) channel = self.get_destination() await channel.send(embed=embed) @@ -639,10 +639,10 @@ I hope that reading this walkthrough will assist you and give a better understan All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of creative things you can do to create a `HelpCommand`. If you need an inspiration, this is my help command. I mean, nobody asked but yeah here it is. ![helpEx](https://cdn.discordapp.com/attachments/784735050071408670/853268304565895188/unknown.png) Here's my code if you want to take a look. It's a bit complicated, but you only have to focus on the HelpCommand class [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server -
InterStella0 revised this gist
Jun 12, 2021 . 1 changed file with 3 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -639,6 +639,9 @@ I hope that reading this walkthrough will assist you and give a better understan All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of creative things you can do to create a `HelpCommand`. If you need an inspiration, this is my help command. ![helpEx](https://cdn.discordapp.com/attachments/784735050071408670/853268304565895188/unknown.png) Here's my code if you want to take a look. It's a bit complicated, but you only have ot focus on the HelpCommand class [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py). -
InterStella0 revised this gist
May 29, 2021 . 1 changed file with 2 additions and 4 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -639,10 +639,8 @@ I hope that reading this walkthrough will assist you and give a better understan All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of creative things you can do to create a `HelpCommand`. Here's my code if you want to take a look. It's a bit complicated, but you only have ot focus on the HelpCommand class [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice -
InterStella0 revised this gist
May 7, 2021 . 1 changed file with 69 additions and 21 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,12 +1,24 @@ # A basic walkthrough guide on subclassing HelpCommand This guide will walkthrough the ways to create a custom help command by subclassing HelpCommand. ## Table Content - [Brief explanation of subclassing](#brief) - [Why subclassing is better](#why) - [Getting started](#start) - [Types of HelpCommand class](#start1) - [Embed MinimalHelpCommand](#start2) - [HelpCommand](#helping) - [Basic method to override](#helping1) - [Useful Attributes](#helping2) - [help command](#helping_guide1) - [help \<argument>](#helping_guide2) - [Command Attributes](#command_attrs) - [Error handling for HelpCommand](#error_handling) - [Setting Cog for HelpCommand](#cog) - [The end](#the_end) ## <a name="brief"></a> Brief explanation of subclassing In simple terms, a subclass is a way to inherit a class behaviour/attributes from another class. Here's how you would subclass a class in Python. ```py @@ -54,9 +66,6 @@ Make sure to look and practice more into subclassing classes to understand fully HelpCommand. ## <a name="why"></a> Why subclassing HelpCommand is better Firstly, let me show you the wrong way of creating a help command. #### One of the most incorrect ways of to create a help command. @@ -163,7 +172,7 @@ help command and formatting. |--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [HelpCommand.filter_commands()][Hgetfilter] | Filter commands to only show commands that the user can run. This help hide any secret commands from the general user. | | [HelpCommand.clean_prefix][Hgetcleanprefix] | Get a clean prefix that escape mentions and format them in a readable way such as `@Name` instead of `<@id>` format. **Works up to version 1.7.1.** | | Context.clean_prefix | HelpCommand.clean_prefix was removed in version 2.0 of discord.py and replaced with `Context.clean_prefix` | | [HelpCommand.get_command_signature()][Hgetcommandsig] | Get the command signature and format them such as `command [argument]` for optional and `command <argument>` for required. | | [HelpCommand.prepare_help_command()][Hgetprepare] | Triggers before every `send_x_help` method are triggered, this work exactly like `command.before_invoke` | | [HelpCommand.get_bot_mapping()][Hgetbotmap] | Get all command that are available in the bot, sort them by Cogs and None for No Category as key in a dictionary. This method is triggered before HelpCommand.send_bot_help is triggered, and will get passed as the parameter. | @@ -208,7 +217,7 @@ to the bot so that you will always have a backup `HelpCommand` ready while you'r ## <a name="start"></a>Getting started With that out of the way, let's get started. For subclassing HelpCommand, first, you would need to know the types of `HelpCommand`. Where each class has their own usage. ### <a name="start1"></a> Types of HelpCommand class There are a few types of HelpCommand classes that you can choose; 1. [`DefaultHelpCommand`][defhelplink] a help command that is given by default. 2. [`MinimalHelpCommand`][minhelplink] a slightly better help command. @@ -242,7 +251,7 @@ bot.help_command = commands.MinimalHelpCommand() ![minhelpcommand.png](https://cdn.discordapp.com/attachments/784735050071408670/787571374742962228/unknown.png) ## <a name="start2"></a> Embed MinimalHelpCommand Now say, you want the content to be inside an embed. But you don't want to change the content of `DefaultHelpCommand`/`MinimalHelpCommand` since you want a simple HelpCommand with minimal work. There is a short code from `?tag embed help example` by `gogert` in [discord.py](https://discord.gg/dpy) server, a sample code you can follow @@ -271,8 +280,8 @@ Every method that is responsible for `<prefix>help <argument>` will call [`Minim when it is about to send the content. This makes it easy to just override `send_pages` without having to override any other method there are in `MinimalHelpCommand`. # <a name="helping"></a> HelpCommand ## <a name="helping1"></a> Basic methods to override If you want to use `HelpCommand` class, we need to understand the basic of subclassing HelpCommand. Here are a list of HelpCommand relevant methods, and it's responsibility. @@ -285,7 +294,7 @@ Here are a list of HelpCommand relevant methods, and it's responsibility. 4. [`HelpCommand.send_cog_help(cog)`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.send_cog_help) Gets called with `<prefix>help <cog>` ## <a name="helping2"></a> Useful attributes 1. [`HelpCommand.context`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.context) the Context object in the help command. 2. [`HelpCommand.clean_prefix`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.clean_prefix) @@ -321,7 +330,7 @@ Keep in mind, using `HelpCommand` class will require overriding every `send_x_he a command that should call `send_command_help` method. However, since `HelpCommand` is an empty class, it will not say anything. ## <a name="helping_guide1"></a> help command Let's work our way to create a `<prefix> help`. Given the documentation, [`await send_bot_help(mapping)`][sendbothelp] method receives `mapping(Mapping[Optional[Cog], List[Command]])` as its parameter. `await` indicates that it should be an async function. @@ -419,7 +428,7 @@ bot.help_command = MyHelp() This looks more readable than the other one. While this should cover most of your needs, you may want to know more helpful attribute that is available on `HelpCommand` in the official documentation. ## <a name="helping_guide2"></a> help [argument] command Now that the hard part is done, let's take a look at `<prefix>help [argument]`. The method responsible for this is as follows; 1. `send_command_help` @@ -471,7 +480,7 @@ As you can see, it is very easy to create `<prefix>help [argument]`. The class a the given argument is a command, a cog, or a group command. It's up to you on how you want to display it, whether it's through a plain message, an embed or even using [`discord.ext.menus`](https://github.com/Rapptz/discord-ext-menus). ## <a name="command_attrs"></a> Command Attributes Let's say, someone is spamming your help command. For a normal command, all you have to do to combat this is using a [`cooldown`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.cooldown) decorator and slap that thing above the command declaration. Or, what about if you want an alias? Usually, you would put an @@ -525,7 +534,7 @@ will also raise an [`OnCommandCooldown`](https://discordpy.readthedocs.io/en/lat error if it was triggered 3 times in 5 seconds due to our `Cooldown` object. Of course, I didn't show that in the result, but you can try it yourself. You should handle the error in an error handler when an `OnCommandCooldown` is raised. ## <a name="error_handling"></a> Error handling for HelpCommand ### Basic error message override What happens when `<prefix>help command` fails to get a command/cog/group? Simple, `HelpCommand.send_error_message` will be called. HelpCommand will not call `on_command_error` when it can't find an existing command. It will also give you an @@ -586,7 +595,46 @@ To be fair, you should create a proper error handler through this official docum There is also a lovely example by `Mysty` on error handling in general. [Here](https://gist.github.com/EvieePy/7822af90858ef65012ea500bcecf1612). This example shows how to properly create a global error handler and local error handler. ## <a name="cog"></a> Setting Cog for HelpCommand ### Super easy lol It works just like setting a cog on a Command object, you basically have to assign a [`commands.Cog`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Cog) instance into [`HelpCommand.cog`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.cog). It is pretty common for discord.py users to put a HelpCommand into a cog/separate file since people want organization. ### Code Example This code example is if you're in a Cog file, which you have access to a Cog instance ```python from discord.ext import commands # Unimportant part class MyHelp(commands.HelpCommand): async def send_bot_help(self, mapping): channel = self.get_destination() await channel.send("hey") class YourCog(commands.Cog): def __init__(self, bot): self.bot = bot # Focus here # Setting the cog for the help help_command = MyHelp() help_command.cog = self # Instance of YourCog class bot.help_command = help_command def setup(bot): bot.add_cog(YourCog(bot)) ``` ### How does it work? 1. It instantiates the HelpCommand class. `help_command = MyHelp()` 2. It assigns the instance of `YourCog`(self) into `cog` attribute # <a name="the_end"></a> The end I hope that reading this walkthrough will assist you and give a better understanding on how to subclass [`HelpCommand`][helplink]. All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of creative things you can do to create a `HelpCommand`. -
InterStella0 revised this gist
Apr 24, 2021 . 1 changed file with 3 additions and 2 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -162,7 +162,8 @@ help command and formatting. | Methods / Attributes | Usage | |--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [HelpCommand.filter_commands()][Hgetfilter] | Filter commands to only show commands that the user can run. This help hide any secret commands from the general user. | | [HelpCommand.clean_prefix][Hgetcleanprefix] | Get a clean prefix that escape mentions and format them in a readable way such as `@Name` instead of `<@id>` format. **Works up to version 1.7.1.** | | Context.clean_prefix | HelpCommand.clean_prefix was removed in 2.0 and replaced with `Context.clean_prefix` | | [HelpCommand.get_command_signature()][Hgetcommandsig] | Get the command signature and format them such as `command [argument]` for optional and `command <argument>` for required. | | [HelpCommand.prepare_help_command()][Hgetprepare] | Triggers before every `send_x_help` method are triggered, this work exactly like `command.before_invoke` | | [HelpCommand.get_bot_mapping()][Hgetbotmap] | Get all command that are available in the bot, sort them by Cogs and None for No Category as key in a dictionary. This method is triggered before HelpCommand.send_bot_help is triggered, and will get passed as the parameter. | @@ -593,7 +594,7 @@ creative things you can do to create a `HelpCommand`. #### Here is how my help command looks like as an inspiration. ![myhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789480296055177226/unknown.png) Here's my code if you want to take a look. [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py#L130-L261). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -125,7 +125,7 @@ async def help(ctx, argument=None): await ctx.send("Invalid command or cog") ``` This is an ok implementation and all, but you have to handle more than this. I'm only simplifying the code. Now for the subclassed HelpCommand code. @@ -152,8 +152,8 @@ class MyHelp(commands.HelpCommand): bot.help_command = MyHelp() ``` Not only does HelpCommand looks better, it is also much more readable compared to the `bad way`. Oh, did I mention that HelpCommand also handles invalid arguments for you? Yeah. It does. #### <a name="utils"></a> 2. Utilities HelpCommand contains a bunch of useful methods you can use in order to assist you in creating your -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 7 additions and 4 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -81,7 +81,8 @@ discord.py. #### 1. Command handling specifically for HelpCommand Missing out on command handling that are specifically for HelpCommand. For instance, say my prefix is `!`. Command handling such as `!help` `!help <command>` @@ -90,10 +91,12 @@ For instance, say my prefix is `!`.Command handling such as `!help <cog>` For a HelpCommand, all of these are handled in the background, including showing appropriate error when `command`/`group`/`cog` are an invalid argument that were given. You can also show custom error when an invalid argument are given. For people who remove the HelpCommand? There is no handling, you have to do it yourself. For example ##### Bad way -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -83,10 +83,14 @@ Missing out on command handling that are specifically for HelpCommand. For instance, say my prefix is `!`.Command handling such as `!help` `!help <command>` `!help <group>` `!help <cog>` All of these are handled in the background, including showing appropriate error when `command`/`group`/`cog` are an invalid argument that were given. You can also show custom error when an invalid argument are given. -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -129,7 +129,7 @@ bot = commands.Bot(command_prefix="!") class MyHelp(commands.HelpCommand): # !help async def send_bot_help(self, mapping): await self.context.send("This is help") # !help <command> async def send_command_help(self, command): -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -184,14 +184,14 @@ class MyCog(commands.Cog): self.bot.help_command = self._original_help_command ``` #### What does this mean? Well, first we have a `HelpCommand` made there called `MyHelpCommand`. When MyCog class is loaded, `bot.help_command` is stored into `self._original_help_command`. This preserve the old help command that was attached to the bot, and then it is assigned to a new `HelpCommand` that you've made. `cog_unload` is triggered when the cog is unloaded, which assign `bot.help_command` to the original help command. #### What good does this give? For example, you have a custom help command that is currently attached to `bot.help_command`. But you want to develop a new help command or modify the existing without killing the bot. So you can just unload the cog, which will assign the old help command to the bot so that you will always have a backup `HelpCommand` ready while you're modifying and testing your custom help. -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,9 +3,9 @@ This guide will walkthrough the ways to create a custom help command by subclass ## Brief explanation of subclassing [`Skip to 'Why subclassing is better'`](#why) [`Skip to 'Getting started'`](#start) In simple terms, a subclass is a way to inherit a class behaviour/attributes from another class. Here's how you would subclass a class in Python. @@ -54,7 +54,7 @@ Make sure to look and practice more into subclassing classes to understand fully HelpCommand. ## <a name="why"></a> Why subclassing HelpCommand is better [`Skip to 'Getting started'`](#start) Firstly, let me show you the wrong way of creating a help command. -
InterStella0 revised this gist
Apr 7, 2021 . 1 changed file with 159 additions and 5 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,7 +3,9 @@ This guide will walkthrough the ways to create a custom help command by subclass ## Brief explanation of subclassing [`Skip to 'Why subclassing is better'`](#start) [`Skip to 'Getting started'`](#why) In simple terms, a subclass is a way to inherit a class behaviour/attributes from another class. Here's how you would subclass a class in Python. @@ -51,6 +53,150 @@ it will have everything that class `A` have, but with an additional attribute/me Make sure to look and practice more into subclassing classes to understand fully on what it is before diving into subclassing HelpCommand. ## <a name="why"></a> Why subclassing HelpCommand is better [`Skip to 'Getting started'`](#why) Firstly, let me show you the wrong way of creating a help command. #### One of the most incorrect ways of to create a help command. ```python bot = commands.Bot(command_prefix="uwu ", help_command=None) # OR bot.help_command = None # OR bot.remove_command("help") @bot.command() async def help(ctx): ... ``` This is directly from YouTube, which are known to have bad tutorials for discord.py. ### Why are these bad? #### 1. Command handling specifically for HelpCommand Missing out on command handling that are specifically for HelpCommand. For instance, say my prefix is `!`.Command handling such as `!help` `!help <command>` `!help <group>` `!help <cog>` All of these are handled in the background, including showing appropriate error when `command`/`group`/`cog` are an invalid argument that were given. You can also show custom error when an invalid argument are given. For example ##### Bad way ```py bot = commands.Bot(command_prefix="!", help_command=None) @bot.command() async def help(ctx, argument=None): # !help if argument is None: await ctx.send("This is help") elif argument in bot.all_commands: command = bot.get_command(argument) if isinstance(command, commands.Group): # !help <group> await ctx.send("This is help group") else: # !help <command> await ctx.send("This is help command") elif argument in bot.cogs: # !help <cog> cog = bot.get_cog(argument) await ctx.send("This is help cog") else: await ctx.send("Invalid command or cog") ``` This is an ok implementation an all, but you have to handle more than this. I'm only simplifying the code. Now for the subclassed HelpCommand code. #### Good way ```py bot = commands.Bot(command_prefix="!") class MyHelp(commands.HelpCommand): # !help async def send_bot_help(self, mapping): await self.context.send("This is help") # !help <command> async def send_command_help(self, command): await self.context.send("This is help command") # !help <group> async def send_group_help(self, group): await self.context.send("This is help group") # !help <cog> async def send_cog_help(self, cog): await self.context.send("This is help cog") bot.help_command = MyHelp() ``` Not only does HelpCommand looks better, it is also much readable compared to the `bad way`. Did I mention that HelpCommand also handles invalid arguments for you? Yeah. #### <a name="utils"></a> 2. Utilities HelpCommand contains a bunch of useful methods you can use in order to assist you in creating your help command and formatting. | Methods / Attributes | Usage | |--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [HelpCommand.filter_commands()][Hgetfilter] | Filter commands to only show commands that the user can run. This help hide any secret commands from the general user. | | [HelpCommand.clean_prefix][Hgetcleanprefix] | Get a clean prefix that escape mentions and format them in a readable way such as `@Name` instead of `<@id>` format. | | [HelpCommand.get_command_signature()][Hgetcommandsig] | Get the command signature and format them such as `command [argument]` for optional and `command <argument>` for required. | | [HelpCommand.prepare_help_command()][Hgetprepare] | Triggers before every `send_x_help` method are triggered, this work exactly like `command.before_invoke` | | [HelpCommand.get_bot_mapping()][Hgetbotmap] | Get all command that are available in the bot, sort them by Cogs and None for No Category as key in a dictionary. This method is triggered before HelpCommand.send_bot_help is triggered, and will get passed as the parameter. | | [HelpCommand.get_destination()][Hgetdestination] | Returns a Messageable on where the help command was invoked. | | `HelpCommand.command_callback` | The method that handles all `help/help cog/ help command/ help group` and call which method appropriately. This is useful if you want to modify the behavour of this. Though more knowledge is needed for you to do that. Most don't use this. | | [Context.send_help()][Csendhelp] | Calling `send_command_help` based on what the Context command object were. This is useful to be used when the user incorrectly invoke the command. Which you can call this method to show help quickly and efficiently. (Only works if you have HelpCommand configured) | All of this does not exist when you set `bot.help_command` to `None`. You miss out on this. ### 3. Modular/Dynamic Since it's a class, most people would make it modular. They put it in a cog for example. There is a common code given in `discord.py` created by Vex. ```python class MyHelpCommand(commands.MinimalHelpCommand): def get_command_signature(self, command): return '{0.clean_prefix}{1.qualified_name} {1.signature}'.format(self, command) class MyCog(commands.Cog): def __init__(self, bot): self._original_help_command = bot.help_command bot.help_command = MyHelpCommand() bot.help_command.cog = self def cog_unload(self): self.bot.help_command = self._original_help_command ``` ####What does this mean? Well, first we have a `HelpCommand` made there called `MyHelpCommand`. When MyCog class is loaded, `bot.help_command` is stored into `self._original_help_command`. This preserve the old help command that was attached to the bot, and then it is assigned to a new `HelpCommand` that you've made. `cog_unload` is triggered when the cog is unloaded, which assign `bot.help_command` to the original help command. ####What good does this give? For example, you have a custom help command that is currently attached to `bot.help_command`. But you want to develop a new help command or modify the existing without killing the bot. So you can just unload the cog, which will assign the old help command to the bot so that you will always have a backup `HelpCommand` ready while you're modifying and testing your custom help. ## <a name="start"></a>Getting started With that out of the way, let's get started. For subclassing HelpCommand, first, you would need to know the types of `HelpCommand`. Where each class has their own usage. @@ -112,7 +258,7 @@ The resulting code will show that it have the content of `MinimalHelpCommand` bu ![embedminimalhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/787574637117833236/unknown.png) ### How does this work? Looking over the `MinimalHelpCommand` source code, [here](https://github.com/Rapptz/discord.py/blob/master/discord/ext/commands/help.py#L1075-L1331). Every method that is responsible for `<prefix>help <argument>` will call [`MinimalHelpCommand.send_pages`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand.send_pages) when it is about to send the content. This makes it easy to just override `send_pages` without having to override any other method there are in `MinimalHelpCommand`. @@ -136,6 +282,8 @@ Here are a list of HelpCommand relevant methods, and it's responsibility. the Context object in the help command. 2. [`HelpCommand.clean_prefix`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.clean_prefix) a cleanup prefix version that remove any mentions. For more, [`Click here`](#utils) Seems simple enough? Now let's see what happens if you override one of the methods. Here's an example code of how you would do that. This override will say `"hello!"` when you type `<prefix>help` to demonstrate on what's going on. @@ -225,7 +373,7 @@ I agree, this does not look pretty. But this demonstrate how to create a help co it looks ugly, is that we're using [`HelpCommand.get_command_signature(command)`][Hgetcommandsig]. Let's override that method to make it a little more readable. We'll borrow codes from [`MinimalHelpCommand.get_command_signature`](https://github.com/Rapptz/discord.py/blob/v1.5.1/discord/ext/commands/help.py#L1144). Optionally, we can subclass `MinimalHelpCommand` instead of copying codes. I'm doing this as a demonstration of overriding other methods. @@ -438,7 +586,7 @@ creative things you can do to create a `HelpCommand`. #### Here is how my help command looks like as an inspiration. ![myhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789480296055177226/unknown.png) Here's my code if you want to take a look. [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py#L136-L248). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice @@ -449,4 +597,10 @@ enough to them. :D [minhelplink]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand [helplink]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand [sendbothelp]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.send_bot_help [Hgetcommandsig]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.get_command_signature [Hgetbotmap]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.get_bot_mapping [Hgetdestination]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.get_destination [Hgetprepare]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.prepare_help_command [Hgetcleanprefix]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.clean_prefix [Hgetfilter]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.filter_commands [Csendhelp]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Context.send_help -
InterStella0 revised this gist
Jan 23, 2021 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -112,7 +112,7 @@ The resulting code will show that it have the content of `MinimalHelpCommand` bu ![embedminimalhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/787574637117833236/unknown.png) ### How does this work? Looking over the `MinimalHelpCommand` source code, [here](https://github.com/Rapptz/discord.py/blob/master/discord/ext/commands/help.py#L1083-L1339). Every method that is responsible for `<prefix>help <argument>` will call [`MinimalHelpCommand.send_pages`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand.send_pages) when it is about to send the content. This makes it easy to just override `send_pages` without having to override any other method there are in `MinimalHelpCommand`. @@ -225,7 +225,7 @@ I agree, this does not look pretty. But this demonstrate how to create a help co it looks ugly, is that we're using [`HelpCommand.get_command_signature(command)`][Hgetcommandsig]. Let's override that method to make it a little more readable. We'll borrow codes from [`MinimalHelpCommand.get_command_signature`](https://github.com/Rapptz/discord.py/blob/v1.5.1/discord/ext/commands/help.py#L1144-L1145). Optionally, we can subclass `MinimalHelpCommand` instead of copying codes. I'm doing this as a demonstration of overriding other methods. -
InterStella0 revised this gist
Jan 8, 2021 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -438,7 +438,7 @@ creative things you can do to create a `HelpCommand`. #### Here is how my help command looks like as an inspiration. ![myhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789480296055177226/unknown.png) Here's my code if you want to take a look. [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice -
InterStella0 revised this gist
Dec 25, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -438,7 +438,7 @@ creative things you can do to create a `HelpCommand`. #### Here is how my help command looks like as an inspiration. ![myhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789480296055177226/unknown.png) Here's my code if you want to take a look. [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py#L131-L239). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice -
InterStella0 revised this gist
Dec 18, 2020 . 1 changed file with 86 additions and 16 deletions.There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -56,9 +56,10 @@ With that out of the way, let's get started. For subclassing HelpCommand, first, Where each class has their own usage. ### Types of HelpCommand class There are a few types of HelpCommand classes that you can choose; 1. [`DefaultHelpCommand`][defhelplink] a help command that is given by default. 2. [`MinimalHelpCommand`][minhelplink] a slightly better help command. 3. [`HelpCommand`][helplink] an empty class that is the base class for every HelpCommand you see. On its own, it will not do anything. By default, help command is using the class `DefaultHelpCommand`. This is stored in [`bot.help_command`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Bot.help_command). This attribute will **ONLY** accept instances that subclasses `HelpCommand`. Here is how you were to use the `DefaultHelpCommand` instance. @@ -74,7 +75,7 @@ bot = commands.Bot(command_prefix="uwu ", help_command=commands.DefaultHelpComma ``` #### Here's an example of what that looks like. ![img.png](https://media.discordapp.net/attachments/784735050071408670/787570202593460224/unknown.png) _Now, of course, this is done by default. I'm only showing you this as a demonstration. Don't scream at me_ Let's do the same thing with `MinimalHelpCommand` next. @@ -161,7 +162,8 @@ bot.help_command = MyHelp() ![hellohelpcommand.png](https://media.discordapp.net/attachments/784735050071408670/787584311221813248/unknown.png) Keep in mind, using `HelpCommand` class will require overriding every `send_x_help` methods. For example, `<prefix>help jsk` is a command that should call `send_command_help` method. However, since `HelpCommand` is an empty class, it will not say anything. ## help command Let's work our way to create a `<prefix> help`. @@ -171,16 +173,17 @@ as its parameter. `await` indicates that it should be an async function. * `Mapping[]` is a [`collections.abc.Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping), for simplicity’s sake, this usually refers to a dictionary since it's under `collections.abc.Mapping`. * `Optional[Cog]` is a [`Cog`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Cog) object that has a chance to be `None`. * `List[Command]` is a list of [`Command`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Command) objects. * `Mapping[Optional[Cog], List[Command]]` means it's a map object with `Optional[Cog]` as it's key and `List[Command]` as its value. _All of these are typehints in the `typing` module. You can learn more about it [here](https://docs.python.org/3/library/typing.html#module-typing)._ Now, for an example, we will use this `mapping` given in the parameter of `send_bot_help`. For each of the command, we'll use [`HelpCommand.get_command_signature(command)`][Hgetcommandsig] to get the command signature of a command in an `str` form. #### Example Code ```py @@ -203,11 +206,12 @@ class MyHelp(commands.HelpCommand): bot.help_command = MyHelp() ``` ### How does it work? 1. Create an embed. 2. Use dict.items() to get an iterable of `(Cog, list[Command])`. 3. Each element in `list[Command]`, we will call `self.get_command_signature(command)` to get the proper signature of the command. 4. If the list is empty, meaning, no commands is available in the cog, we don't need to show it, hence `if command_signatures:`. 5. `cog` has a chance to be `None`, this refers to No Category. We'll use [`getattr`](https://docs.python.org/3/library/functions.html#getattr) to avoid getting an error to get cog's name through [`Cog.qualified_name`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Cog.qualified_name). 6. Using [`str.join`](https://docs.python.org/3/library/stdtypes.html#str.join) each command will be displayed on a separate line. @@ -260,7 +264,8 @@ This looks more readable than the other one. While this should cover most of you attribute that is available on `HelpCommand` in the official documentation. ## help [argument] command Now that the hard part is done, let's take a look at `<prefix>help [argument]`. The method responsible for this is as follows; 1. `send_command_help` 2. `send_cog_help` 3. `send_group_help` @@ -308,7 +313,61 @@ bot.help_command = MyHelp() As you can see, it is very easy to create `<prefix>help [argument]`. The class already handles the pain of checking whether the given argument is a command, a cog, or a group command. It's up to you on how you want to display it, whether it's through a plain message, an embed or even using [`discord.ext.menus`](https://github.com/Rapptz/discord-ext-menus). ## Command Attributes Let's say, someone is spamming your help command. For a normal command, all you have to do to combat this is using a [`cooldown`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.cooldown) decorator and slap that thing above the command declaration. Or, what about if you want an alias? Usually, you would put an aliases kwargs in the [`command`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Bot.command) decorator. However, HelpCommand is a bit special, It's a god damn class. You can't just put a decorator on it and expect it to work. That is when [`HelpCommand.command_attrs`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.HelpCommand.command_attrs) come to the rescue. This attribute can be set during the HelpCommand declaration, or a direct attribute assignment. According to the documentation, it accepts exactly the same thing as a [`command`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Bot.command) decorator in a form of a dictionary. For example, we want to rename the help command as `"hell"` instead of `"help"` for whatever reason. We also want to make an alias for `"help"` so users can call the command with `"hell"` and `"help"`. Finally, we want to put a cooldown, because help command messages are big, and we don't want people to spam those. So, what would the code look like? #### Example Code ```py from discord.ext import commands attributes = { 'name': "hell", 'aliases': ["help", "helps"], 'cooldown': commands.Cooldown(2, 5.0, commands.BucketType.user) } # During declaration help_object = commands.MinimalHelpCommand(command_attrs=attributes) # OR through attribute assignment help_object = commands.MinimalHelpCommand() help_object.command_attrs = attributes bot = commands.Bot(command_prefix="uwu ", help_command=help_object) ``` ### How does it work? 1. sets the name into `"hell"` is refers to here `'name': "hell"`. 2. sets the aliases by passing the list of `str` to the `aliases` key, which refers to here `'aliases': ["help", "helps"]`. 3. sets the cooldown through the `"cooldown"` key by passing in a [`Cooldown`](https://github.com/Rapptz/discord.py/blob/v1.5.1/discord/ext/commands/cooldowns.py#L70-L134) object. This object will make a cooldown with a rate of 2, per 5 with a bucket type [`BucketType.user`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.discord.ext.commands.BucketType), which in simple terms, for every [`discord.User`](https://discordpy.readthedocs.io/en/latest/api.html#discord.User), they can call the command twice, every 5 seconds. 4. We're going to use `MinimalHelpCommand` as the `HelpCommand` object. #### The result ![cooldownhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789471505145659412/unknown.png) As you can see, the name of the help command is now `"hell"`, and you can also trigger the help command by `"help"`. It will also raise an [`OnCommandCooldown`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.CommandOnCooldown) error if it was triggered 3 times in 5 seconds due to our `Cooldown` object. Of course, I didn't show that in the result, but you can try it yourself. You should handle the error in an error handler when an `OnCommandCooldown` is raised. ## Error handling for HelpCommand ### Basic error message override @@ -370,10 +429,21 @@ stored in `error` variable, and show the message. To be fair, you should create a proper error handler through this official documentation. [Here](https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html#ext-commands-error-handler). There is also a lovely example by `Mysty` on error handling in general. [Here](https://gist.github.com/EvieePy/7822af90858ef65012ea500bcecf1612). This example shows how to properly create a global error handler and local error handler. ## The end I hope that reading this walkthrough will assist you and give a better understanding on how to subclass [`HelpCommand`][helplink]. All the example code given are to demonstrate the feature of `HelpCommand` and feel free to try it. There are lots of creative things you can do to create a `HelpCommand`. #### Here is how my help command looks like as an inspiration. ![myhelp.png](https://cdn.discordapp.com/attachments/784735050071408670/789480296055177226/unknown.png) Here's my code if you want to take a look. [my help command](https://github.com/InterStella0/stella_bot/blob/master/cogs/helpful.py#L136-L248). Now, of course, any question regarding `HelpCommand` should be asked in the [discord.py](https://discord.gg/dpy) server because I don't really check this gist as much, and because there is a lot of helpful discord.py helpers if you're nice enough to them. :D [defhelplink]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.DefaultHelpCommand [minhelplink]: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.MinimalHelpCommand
NewerOlder