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 Client
.
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!
1) Component().load_from_scope()
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.
2) Component().make_loader()
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 /reload
path.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
declares
commands 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 |
|
With 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 print
to help debug their code. print
is one of the first things you learn to get information out to the console, but it is not a good method to use long term. print
doesn't have any built in way to filter information and there's no way to toggle all printing for a file or project. That's just a few reasonsing why logging
is better! So let's look at how to utilize this module better.
Firstly Hikari
preconfiures 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 root
logger 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!
Next Time
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 ↩