Creating Command Groups#

Command groups are a method of grouping commands to reduce the top-level clutter that could occur if your bot had a large number of commands. For example, say you had three commands: setprefix, setchannel, setrole. You can see how, if your bot had a lot of configurable features, it could result in unnecessary clutter due to many similarly named commands.

Command groups are the solution to this problem, it allows you to have a single top-level command - set - which has multiple subcommands that allow the user to set multiple bot configuration values. For example, the previously mentioned commands would be changed into the following command tree:

set
├─ prefix
├─ channel
├─ role

These commands would be invoked using the names set prefix, set channel and set role respectfully.

Command Group Support#

Both prefix and slash commands support command groups, subgroups, and subcommands. However, for prefix commands, a given command group can have an arbitrary number of levels subgroups and subcommands, whereas for slash commands you can only go a maximum of three levels deep:

group -> subgroup -> subcommand for slash commands

or

group -> subgroup -> subgroup -> ... -> subcommand for prefix commands.

Relevant API References:

Lightbulb requires you to create a function for each command group and subgroup, but you should note that due to a discord limitation, this function will not be run for slash commands as the root group/subgroup cannot be invoked for slash commands.

Creating a Command Group#

For this section we will be using prefix commands as an example, slash commands work in exactly the same way.

You define a command group exactly the same way that you would a normal command, however instead of providing lightbulb.PrefixCommand to the lightbulb.decorators.implements decorator, we will instead be providing lightbulb.PrefixCommandGroup.

A basic example can be seen below:

import lightbulb

bot = lightbulb.BotApp(..., prefix="!")

@bot.command
@lightbulb.command("foo", "test group")
@lightbulb.implements(lightbulb.PrefixCommandGroup)
async def foo(ctx: lightbulb.Context) -> None:
    await ctx.respond("invoked foo")

This command would be invoked like a normal prefix command and behaves like a normal prefix command - !foo.

Adding Subcommands#

To add a subcommand to a given command group or subgroup you have to provide a subcommand class to the lightbulb.decorators.implements decorator. In this case, that would be the class lightbulb.PrefixSubCommand. Note that this only creates the command, we still need to link it back to the group that it belongs to. To do this we use the lightbulb.commands.base.CommandLike.child decorator as seen below.

import lightbulb

bot = lightbulb.BotApp(..., prefix="!")

@bot.command
@lightbulb.command("foo", "test group")
@lightbulb.implements(lightbulb.PrefixCommandGroup)
async def foo(ctx: lightbulb.Context) -> None:
    await ctx.respond("invoked foo")

@foo.child
@lightbulb.command("bar", "test subcommand")
@lightbulb.implements(lightbulb.PrefixSubCommand)
async def bar(ctx: lightbulb.Context) -> None:
    await ctx.respond("invoked foo bar")

The subcommand bar would be invoked by first invoking its parent foo, and then separating the invocation of bar using a space - !foo bar.

Adding Subgroups#

Adding subgroups to command groups (or other subgroups) is done exactly the same way that you would add a subcommand to a given group. Similarly, adding subcommands to subgroups is identical to the method used to add subcommands to a top-level command group.

See below for an example:

import lightbulb

bot = lightbulb.BotApp(..., prefix="!")

@bot.command
@lightbulb.command("foo", "test group")
@lightbulb.implements(lightbulb.PrefixCommandGroup)
async def foo(ctx: lightbulb.Context) -> None:
    await ctx.respond("invoked foo")

@foo.child
@lightbulb.command("bar", "test subgroup")
@lightbulb.implements(lightbulb.PrefixSubGroup)
async def bar(ctx: lightbulb.Context) -> None:
    await ctx.respond("invoked foo bar")

@bar.child
@lightbulb.command("baz", "test subcommand")
@lightbulb.implements(lightbulb.PrefixSubGroup)
async def baz(ctx: lightbulb.Context) -> None:
    await ctx.respond("invoked foo bar baz")

In the above example, the command foo would be invoked using !foo, the command bar would be invoked using !foo bar, and the command baz would be invoked using !foo bar baz.

Any command options for subcommands or subgroups must be provided after the full qualified name of the command or subcommand being invoked.

Extra Information#

By default, subcommands and subcommand groups will not inherit the checks from the parent group or subgroup that the command belongs to. This behaviour can be changed by providing the kwarg inherit_checks=True in the lightbulb.decorators.command decorator.