Damn, your code is getting pretty messy now, huh? Wouldn't it be nice if you could organise your commands and listeners into separate files?
Well let me introduce you to Extensions
Extensions allow you to split your commands and listeners into separate files to allow you to better organise your project,
as well as that, they allow you to reload Extensions without having to shut down your bot.
Sounds pretty good right? Well, let's go over how you can use them:
# File: `main.py`importloggingimportnaff.constfromnaff.clientimportClientfromnaff.models.application_commandsimportslash_command,slash_optionfromnaff.models.commandimportprefixed_commandfromnaff.models.contextimportInteractionContextfromnaff.models.discord_objects.componentsimportButton,ActionRowfromnaff.models.enumsimportButtonStylesfromnaff.models.enumsimportIntentsfromnaff.models.eventsimportComponentfromnaff.models.listenerimportlistenlogging.basicConfig()cls_log=logging.getLogger(naff.const.logger_name)cls_log.setLevel(logging.DEBUG)bot=Client(intents=Intents.DEFAULT,sync_interactions=True,asyncio_debug=True)@listen()asyncdefon_ready():print("Ready")print(f"This bot is owned by {bot.owner}")@listen()asyncdefon_guild_create(event):print(f"guild created : {event.guild.name}")@listen()asyncdefon_message_create(event):print(f"message received: {event.message.content}")@listen()asyncdefon_component(event:Component):ctx=event.contextawaitctx.edit_origin("test")@prefixed_command()asyncdefmultiple_buttons(ctx):awaitctx.send("2 buttons in a row",components=[Button(ButtonStyles.BLURPLE,"A blurple button"),Button(ButtonStyles.RED,"A red button")],)@prefixed_command()asyncdefaction_rows(ctx):awaitctx.send("2 buttons in 2 rows, using nested lists",components=[[Button(ButtonStyles.BLURPLE,"A blurple button")],[Button(ButtonStyles.RED,"A red button")]],)@prefixed_command()asyncdefaction_rows_more(ctx):awaitctx.send("2 buttons in 2 rows, using explicit action_rows lists",components=[ActionRow(Button(ButtonStyles.BLURPLE,"A blurple button")),ActionRow(Button(ButtonStyles.RED,"A red button")),],)bot.start("Token")
# File: `main.py`importloggingimportnaff.constfromnaff.clientimportClientfromnaff.models.contextimportComponentContextfromnaff.models.enumsimportIntentsfromnaff.models.eventsimportComponentfromnaff.models.listenerimportlistenlogging.basicConfig()cls_log=logging.getLogger(naff.const.logger_name)cls_log.setLevel(logging.DEBUG)bot=Client(intents=Intents.DEFAULT,sync_interactions=True,asyncio_debug=True)@listen()asyncdefon_ready():print("Ready")print(f"This bot is owned by {bot.owner}")@listen()asyncdefon_guild_create(event):print(f"guild created : {event.guild.name}")@listen()asyncdefon_message_create(event):print(f"message received: {event.message.content}")@listen()asyncdefon_component(event:Component):ctx=event.contextawaitctx.edit_origin("test")bot.load_extension("test_components")bot.start("Token")
# File: `test_components.py`fromnaff.models.commandimportprefixed_commandfromnaff.models.discord_objects.componentsimportButton,ActionRowfromnaff.models.enumsimportButtonStylesfromnaff.models.extensionimportExtensionclassButtonExampleSkin(Extension):@prefixed_command()asyncdefblurple_button(self,ctx):awaitctx.send("hello there",components=Button(ButtonStyles.BLURPLE,"A blurple button"))@prefixed_command()asyncdefmultiple_buttons(self,ctx):awaitctx.send("2 buttons in a row",components=[Button(ButtonStyles.BLURPLE,"A blurple button"),Button(ButtonStyles.RED,"A red button")],)@prefixed_command()asyncdefaction_rows(self,ctx):awaitctx.send("2 buttons in 2 rows, using nested lists",components=[[Button(ButtonStyles.BLURPLE,"A blurple button")],[Button(ButtonStyles.RED,"A red button")]],)@prefixed_command()asyncdefaction_rows_more(self,ctx):awaitctx.send("2 buttons in 2 rows, using explicit action_rows lists",components=[ActionRow(Button(ButtonStyles.BLURPLE,"A blurple button")),ActionRow(Button(ButtonStyles.RED,"A red button")),],)defsetup(bot):ButtonExampleSkin(bot)
Extensions are effectively just another python file that contains a class that inherits from an object called Extension,
inside this extension, you can put whatever you would like. And upon loading, the contents are added to the bot.
1 2 3 4 5 6 7 8 910
fromnaffimportExtensionclassSomeClass(Extension):...defsetup(bot):# This is called by naff so it knows how to load the ExtensionSomeClass(bot)
As you can see, there's one extra bit, a function called setup, this function acts as an entry point for NAFF,
so it knows how to load the extension properly.
To load a extension, you simply add the following to your main script, just above bot.start:
Now, for the cool bit of Extensions, reloading. Extensions allow you to edit your code, and reload it, without restarting the bot.
To do this, simply run bot.reload_extension("Filename_here") and your new code will be used. Bare in mind any tasks your extension
is doing will be abruptly stopped.
You can pass keyword-arguments to the load_extension, unload_extension and reload_extension extension management methods.
Any arguments you pass to the setup or teardown methods, will also be passed to the Extension.drop method.
Here is a basic "Extension switching" example:
1 2 3 4 5 6 7 8 910111213141516171819202122232425
fromnaffimportExtensionclassSomeExtension(Extension):def__init__(self,bot,some_arg:int=0):...classAnotherExtension(Extension):def__init__(self,bot,another_arg:float=0.0):...defsetup(bot,default_extension:bool,**kwargs):# We don't care about other arguments here.ifdefault_extension:SomeExtension(bot,**kwargs)else:AnotherExtension(bot,**kwargs)...bot.load_extension("Filename_here",default_extension=False,another_arg=3.14)# ORbot.load_extension("Filename_here",default_extension=True,some_arg=555)