pythondiscorddiscord.pybots

How to use extensions/cogs in discord.py


This is the code I run to start the bot

# bot.py
import discord
from discord import app_commands
from discord.ext import commands, tasks
from itertools import cycle
import humanize
import random

bot = commands.Bot(command_prefix="?", intents=discord.Intents.all())

bot_status = cycle(["Wow.", "Isn't. This.", "Cool?"])


@tasks.loop(seconds=10)
async def change_status():
    await bot.change_presence(activity=discord.Game(next(bot_status)))


@bot.event
async def on_ready():
    try:
        await bot.tree.sync()

        print(f'Synced')
    except Exception as e:
        print(e)
    print("Ready")
    change_status.start()


def calculate_result(number):
    if "M" in number.upper():
        power = number.upper()
        tp = int(power.replace("M", ""))
        calc = 20000 + tp * 10
        return humanize.intword(calc)
    elif "B" in number.upper():
        power = number.upper()
        tp = int(power.replace("B", ""))
        calc = 60000 + tp * 60
        return humanize.intword(calc)
    elif "T" in number.upper():
        power = number.upper()
        tp = int(power.replace("T", ""))
        calc = 140000 + tp * 600
        return humanize.intword(calc)
    else:
        return None


def number_conversion(durability):
    if "K" in durability.upper():
        power = durability.upper()
        dura = int(power.replace("K", ""))
        return dura * 1000
    elif "M" in durability.upper():
        power = durability.upper()
        dura = int(power.replace("M", ""))
        return dura * 1000000
    elif "B" in durability.upper():
        power = durability.upper()
        dura = int(power.replace("B", ""))
        return dura * 1000000000
    elif "T" in durability.upper():
        power = durability.upper()
        dura = int(power.replace("T", ""))
        return dura * 1000000000000
    else:
        return None


@bot.tree.command(name='sync', description='Owner only')
async def sync(interaction: discord.Interaction):
    await bot.tree.sync()
    await interaction.response.send_message('Command tree synced.')


@bot.command()
async def update_commands(ctx):
    await bot.update_commands()


@bot.tree.command(name="hitcost")
@app_commands.describe(dura="The durability power of the person you wish to put a hit on")
async def calculate_command(interaction: discord.Interaction, dura: str):
    result = calculate_result(dura)
    if result is not None:
        embed = discord.Embed(color=00000, title="Hit Cost")
        embed.add_field(name=f"Cost for {dura.upper()}", value=f"{result}")
        await interaction.response.send_message(embed=embed)
    else:
        await interaction.response.send_message("Invalid Power Level. Please use M, B, or T.", ephemeral=True)


bot.run("TOKEN")

Now I tried to move the commands / command function in another .py file (commands.py) using cogs and extensions (I tried both since I don't know which works better for what I'm trying). So that I can run bot.py with the command things moved to command.py (which I don't run) and it still works. But no matter how I try it doesn't work (probably because I can't use cogs/extensions). Can someone please give me an example code of how it would work so I can understand? would be appreciated


Solution

  • Cogs are a pretty nifty way to organize your bot's commands and stuff. Cogs derive from the commands.Cog class found in the commands ext and are usually placed in separate files and loaded as extensions.

    A basic Cog example for discord.py

    cog_example_ext.py

    from discord import app_commands
    from discord.ext import commands
    
    # all cogs inherit from this base class
    class ExampleCog(commands.Cog):
        def __init__(self, bot):
            self.bot = bot # adding a bot attribute for easier access
    
        # adding a command to the cog
        @commands.command(name="ping")
        async def pingcmd(self, ctx):
            """the best command in existence"""
            await ctx.send(ctx.author.mention)
        
        # adding a slash command to the cog (make sure to sync this!)
        @app_commands.command(name="ping")
        async def slash_pingcmd(self, interaction):
            """the second best command in existence"""
            await interaction.response.send_message(interaction.user.mention)
    
        # adding an event listener to the cog
        @commands.Cog.listener()
        async def on_message(self, message):
            if message.guild and message.guild.me.guild_permissions.ban_members:
                await message.author.ban(reason="no speek") # very good reason
    
    # usually you’d use cogs in extensions
    # you would then define a global async function named 'setup', and it would take 'bot' as its only parameter
    async def setup(bot):
        # finally, adding the cog to the bot
        await bot.add_cog(ExampleCog(bot=bot))
    

    main.py

    import discord
    from discord.ext import commands
    
    TOKEN = "your token"
    
    class ExampleBot(commands.Bot):
        def __init__(self):
            # initialize our bot instance, make sure to pass your intents!
            # for this example, we'll just have everything enabled
            super().__init__(
                command_prefix="!",
                intents=discord.Intents.all()
            )
        
        # the method to override in order to run whatever you need before your bot starts
        async def setup_hook(self):
            await self.load_extension("cog_example_ext")
    
    ExampleBot().run(TOKEN)
    

    References: