Tanjun and Hikari go through rapid development! With that come a lot of improvements even between articles. Here's a few quick tips that have changed that will streamline your code!
An Example Generic Plugin
Let's look at a simple Tanjun plugin outline. First we define a new component,
my_component on line 3. Line 5 we define a generic command handler called
my_cmd_handler. This handler accepts
ctx: tanjun.abc.Context, so that it can work as a callback for either a Slash command or a Message command. Line 8 starts the Slash command definition with
@my_component.with_command, this decorator is what connects your command to the
Component() that Tanjun later loads into the
Client. Line 14 begins a new Message command definition with the same
.with_command decorator. Lines 20 and 24 define the loader and unloader functions respectively. These functions contain the logic Tanjun uses to add and remove this component from the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
A simple plugin so far, right? Well let's look at some new ways we can make this more efficient!
Instead of adding
@component.with_command to every command definition, Tanjun provides a lovely
Component().load_from_scope() function. Not only does this reduce some code duplication, you can simplify it even further. Instead of setting up two individual commands we can stack them all on one:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
.load_from_scope() works on Slash/Message command groups as well. You just need to define your groups slightly differently. Normally when you define a command group, you have to warp it in a command function of its own. For a slash command that would look like the example below.
1 2 3
You would then use
@my_grp as a decorator to setup subcommands in your plugin.
.from_local_scope() provides a useful shorthand for this too! Just drop the additional
.as_message/slash_command on your command group and setup
.from_local_scope() like before:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
This code will now load not only your SlashCommandGroup with its proper subcommand setup, but it will also load the standalone
other_cmd separtely from the group and subcommand.
To define a plugin in Tanjun, you have to have a loader and unloader function. These two functions provide the logic for how Tanjun adds and removes your
Component from the
Client. In previous versions of Tanjun you would need to rewrite these two functions at the bottom of every plugin file. A recent release of Tanjun provides a new
Component().make_loader() method to do this for you! If your load/unload doesn't require any custom logic try it out! Also notice that we can chain the previous tip with this one:
Component().load_from_scope().make_loader(), and this is perfectly valid:
1 2 3 4 5 6 7 8 9 10 11 12
3) Stop Restarting your Bot, Write Load/Unload Command's
Restarting your bot every time you make a minor change to your code can be annoying. Restarting your bot can mean losing your in memory cache, a slow startup, or getting your Token throttled if you are just testing! Instead try writing some commands to load and unload plugins via Discord:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
This short 50 line plugin provides all the functionality you need to load, unload, and reload any plugins. Just run
/reloadpath.to.plugin` and just that plugin will be reloaded.
Note: This will not reload the plugins dependencies. If you change other files via pip or other non-component files, a restart will be required!
Note 2: Using this method will not cause newly created commands or renamed commands to appear! Tanjun only
declarescommands when the bot starts up.
4) Learn how Dependency Injection works
We already wrote a full post on Dependency Injection and how useful it can be in Tanjun. To give a tl;dr, DI allows you to dynamically add preconfigured objects to a callback via it's type:
1 2 3 4 5 6
tanjun.injected we are able to tell Tanjun we want the preconfigured
tanjun.Client. Tanjun then checks an internal list to see if any objects are registered for that type. By default Tanjun registers
tanjun.Client and a few others for you. We won't go too much deeper into DI here, but it is an essential concept to understand in Tanjun.
5) Please use Logging
A lot of beginners will end up using
logging is better! So let's look at how to utilize this module better.
logging for you! By default, running the following code in a Hikari file will be valid. Hikari will automatically add its specific formatting type and add color to your log!
info gets logged as yellow and
error gets logged as red, neat!
1 2 3 4 5 6 7
There's a few more things you can do to better use
logging too. One good habit is to use
logging.getLogger so you're not using your root logger. By default
import logging will climb up your python files to find a previous working logger. If you have not setup any other loggers, by default you will get the
hikari setup. You can avoid that with the single line below:
1 2 3 4 5 6 7
Lastly, log your exceptions!! The
logging plugin provides a way to log exceptions with the full traceback too:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
hikari.GatewayBot also provides a way to set a project wide LogLeve3. This provides a fast and easy way to toggle what information shows when your bot runs. Just passing in the LogLevel you need to see and Hikari will preconfigure the logs to only show that Level and below!
We took a break today to review a couple quick tips! Next time we will be diving back into more advanced topics. More about Yuyo, the hikari utility library made by FasterSpeeding, the wonderful owner of Tanjun. More about setting up Dependency Injection properly. Check back soon!
Resources & Links
hikari-tanjun Documentation tanjun.Component.load_from_scope, Faster Speeding, https://tanjun.cursed.solutions/master/tanjun.html#Component.load_from_scope ↩
hikari-tanjun Documentation tanjun.Component.make_loader, Faster Speeding, https://tanjun.cursed.solutions/master/tanjun.html#Component.make_loader ↩
hikari Documentation, Davfsa, https://www.hikari-py.dev/hikari/impl/bot.html#hikari.impl.bot.GatewayBot ↩