How to load commands from multiple files Python Bot below is my main.py and other python files with commands. Is this correct method or do i need to change anything? do i need to add token, prefix, bot = commands.Bot, bot.run(token) etc in all files.
main.py
token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
prefix = "?"
import discord
from discord.ext import commands
startup_extensions = ["second", "third"]
bot = commands.Bot(command_prefix=prefix)
bot.remove_command("help")
#bot.event
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')
#bot.command(pass_context=True)
async def hello1(ctx):
msg = 'Hello {0.author.mention}'.format(ctx.message)
await bot.say(msg)
bot.run(token)
second.py
import discord
from discord.ext import commands
class Second():
def __init__(self, bot):
self.bot = bot
#commands.command(pass_context=True)
async def hello2(ctx):
msg = 'Hello{0.author.mention}'.format(ctx.message)
await bot.say(msg)
def setup(bot):
bot.add_cog(Second(bot))
third.py
import discord
from discord.ext import commands
class Third():
def __init__(self, bot):
self.bot = bot
#commands.command(pass_context=True)
async def hello3(ctx):
msg = 'Hello{0.author.mention}'.format(ctx.message)
await bot.say(msg)
def setup(bot):
bot.add_cog(Third(bot))
Would you could do is setup your file with cogs for example your main file:
import discord
from discord.ext import commands
client = commands.Bot(command_prefix="!") # <- Choose your prefix
# Put all of your cog files in here like 'moderation_commands'
# If you have a folder called 'commands' for example you could do #'commands.moderation_commands'
cog_files = ['commands.moderation_commands']
for cog_file in cog_files: # Cycle through the files in array
client.load_extension(cog_file) # Load the file
print("%s has loaded." % cog_file) # Print a success message.
client.run(token) # Run the bot.
Say in your moderation_commands file it would look like:
import discord
from discord.ext import commands
class ModerationCommands(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command(name="kick") # Your command decorator.
async def my_kick_command(self, ctx) # ctx is a representation of the
# command. Like await ctx.send("") Sends a message in the channel
# Or like ctx.author.id <- The authors ID
pass # <- Your command code here
def setup(client) # Must have a setup function
client.add_cog(ModerationCommands(client)) # Add the class to the cog.
You can find more information on cogs here: https://discordpy.readthedocs.io/en/stable/ext/commands/cogs.html
Related
I'm developing discord bot with discord.py==2.1.0.
I use cog to write the main function that I wanna use, but I found when the whole bot is wrapped in async function and called by asyncio.run(), my terminal won't show any error message when there is any runtime error in my cog script.
Here is the example application. I stored my bot token in environment variable.
bot.py
import os
import discord
from discord.ext import commands
import asyncio
token = os.environ["BOT_TOKEN"]
class Bot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
description = "bot example."
super().__init__(
command_prefix=commands.when_mentioned_or('!'),
intents=intents,
description=description
)
async def on_ready(self):
print(f'Logged in as {self.user} (ID: {self.user.id})')
print('------')
bot = Bot()
async def load_extensions():
for f in os.listdir("./cogs"):
if f.endswith(".py"):
await bot.load_extension("cogs." + f[:-3])
async def main():
async with bot:
await load_extensions()
await bot.start(token)
asyncio.run(main())
./cogs/my_cog.py
from discord.ext import commands
class Test(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print("Ready")
#commands.command()
async def command(self, ctx):
test_error_message() # An runtime error example
print("Command")
async def setup(client):
await client.add_cog(Test(client))
Command that I run in terminal to start the bot.
python bot.py
When I type !command in the discord channel, there is no error message showing in the terminal, but there is no "Command" printed out so I'm sure the code stopped at the line I called test_error_message()
I expected that it should show error message normally, but I cannot find useful reference to make it work :(
There is one reason I need to use asyncio, I have a task loop to run in the bot, like the code below.
from discord.ext import tasks
#tasks.loop(seconds=10)
async def avatar_update():
# code here
async def main():
async with bot:
avatar_update.start()
await load_extensions()
await bot.start(token)
I would happy to know if there are some great practice to handle error in this situation.
Thanks!
Client.start() doesn't configure logging, so if you want to use that then you have to do it yourself (there's setup_logging to add a basic config). run() configures logging for you.
For more info, read the docs. https://discordpy.readthedocs.io/en/stable/logging.html?highlight=logging
I'm trying to get custom commands to work in my Discord server. But it doesn't work when I'm not using a decorator, and I do not know how to make it work within a class.
Please help.
(XXX.. just replaces an ID here)
Please have a look at add_my_commands() function. This one should be able to take the prefix and respond with the info. This doesn't work currently.
I have a main.py file which runs separately, as follows:
# Import discord.py
import discord
from discord.ext import commands
# Import Bot Token
from apikeys import *
# Import classes
from steward_bot import MyClient
intents = discord.Intents.default() # or .all() if you ticked all, that is easier
intents.message_content = True
intents.members = True # If you ticked the SERVER MEMBERS INTENT
# Initialize client
bot = MyClient(command_prefix="!", intents=intents)
bot.run(DISCORD_TOKEN)
The MyClient class:
class MyClient(commands.Bot):
def __init__(self, *args, command_prefix, **kwargs):
super().__init__(
*args, command_prefix=command_prefix, case_insensitive=True, **kwargs
)
self.target_message_id = XXXX
self.add_my_commands()
async def on_ready(self):
print("We have logged in as {0.user}".format(self))
print("---------------------------------------------")
async def on_member_remove(self, member):
channel = self.get_channel(XXXX)
await channel.send("Goodbye")
async def on_raw_reaction_add(self, payload):
"""
Give a role based on a reaction emoji
"""
if payload.message_id != self.target_message_id:
return
guild = self.client.get_guild(payload.guild_id)
print(payload.emoji.name)
print("Hello")
# Responding to messages
async def on_message(self, message):
if message.author == self.user:
return
if message.content == "Test":
await message.channel.send("Hey hey chill")
if message.content == "cool":
await message.add_reaction("\U0001F60E")
if message.content == "give me our prefix":
await message.channel.send(str(self.command_prefix))
await self.process_commands(message)
# Throws out reactions to messages
async def on_reaction_add(self, reaction, user):
await reaction.message.channel.send(f"{user} reacted with {reaction.emoji}")
def add_my_commands(self):
#self.command(name="info", pass_context=True)
async def info(ctx):
"""
ctx - context (information about how the command was executed)
info
"""
print(ctx)
await ctx.send("Hello X")
await ctx.send(ctx.guild)
await ctx.send(ctx.author)
await ctx.send(ctx.message.id)
Within the server, I want to run the command "!info" and get the information out. Would appreciate any help!
No need to define your entire bot within a class. Create a main.py file with your bot defined and import cogs from there. I'd also set up my commands through a cog with commands.command().
Example of how I'd go about adding an !info command:
main.py
import discord
from discord.ext import commands
from info import InfoCog
intents = discord.Intents.default()
intents.members = True
intents.guilds = True
intents.messages = True
intents.reactions = True
intents.presences = True
# Initialize client
bot = commands.Bot(command_prefix='!', intents=intents)
bot.add_cog(InfoCog(bot))
#bot.event
async def on_ready(self):
print("We have logged in as {0.user}".format(self))
print("---------------------------------------------")
bot.run(TOKEN)
info.py
import discord
from discord.ext import commands
class InfoCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.command()
async def info(self, ctx):
await ctx.send('Info')
Or, you could jumble everything into one file. This is how I used to do it with all my commands & events. It was easier to get the hang of at first.
main.py
# Import discord.py
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True
intents.guilds = True
intents.messages = True
intents.reactions = True
intents.presences = True
bot = commands.Bot(command_prefix='!', intents=intents)
#bot.event
async def on_ready(bot):
print("We have logged in as {0.user}".format(bot))
print("---------------------------------------------")
# [...]
#bot.command()
async def info(ctx):
await ctx.send('info')
# [...]
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content == "give me our prefix":
await message.channel.send(str(bot.command_prefix))
if message.content == "Test":
await message.channel.send("Hey hey chill")
# [...]
#bot.event()
async def on_member_remove(member):
channel = bot.get_channel(CHANNELID)
await channel.send(f"Goodbye, {member}")
# [...]
bot.run(TOKEN)
I am trying to learn discord.py V2.0. If I create a slash command without entering a guild to use then I takes some time before discord updated the bot slash command list. The qustion is how should I provide the guilds in my cog python file?
Here is my main.py:
import os
import asyncio
#---
import discord
from discord import app_commands
from discord.ext import commands
#---
MY_GUILD = discord.Object(id=1041079018713260173)
TOKEN = "token goes here"
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)
class abot(discord.Client):
def __init__(self, *, intents: discord.Intents):
super().__init__(intents=intents)
self.bot = bot
self.synced = False
self.tree = app_commands.CommandTree(self.bot)
async def on_ready(self):
await self.tree.sync(guild=MY_GUILD)
self.synced = True
async def load():
print("---Cogs---")
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
await bot.load_extension(f"cogs.{filename[:-3]}")
print(f'[i]: Loaded "{filename}" into cogs')
async def main():
await load()
await bot.start(TOKEN)
asyncio.run(main())
Here is the event.py file inside of "cogs" folder:
import asyncio
import os
#---
import discord
from discord import app_commands
from discord.ext import commands
status = "testar bara..."
MY_GUILD = discord.Object(id=1041079018713260173)
class events(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
print("---Info---")
print(f'Logged in as | "{self.bot.user}" | and is now online!')
await self.bot.change_presence(status=discord.Status.online, activity=discord.Game(status))
print(f'Updated status to -> "{status}"')
print("Running and listening for commands....")
print(f"----")
#app_commands.command(name = "latency", description="brrarar testar")
async def latencyf(self, interaction: discord.Interaction):
await interaction.response.send_message(f"test... test...")
async def setup(bot):
await bot.add_cog(events(bot))
You do not need to provide the guilds yourself. You can use bot.guilds, which provides a list of all the guilds where the bot is connected to.
I want to use a slash command in DMs. Take this simple test.py file in the folder cogs/.
import discord
from discord.ext import commands
from discord import app_commands
class Test(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
print("Loaded test command cog.")
#app_commands.command(name="test", description="Test command")
async def test(self, interaction: discord.Interaction):
await interaction.response.send_message(f'Hello')
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(Test(bot))
Outside the cogs folder is my launch_bot.py file which start the bot:
import discord
from discord.ext import commands
import json
with open("cogs/jsons/settings.json") as json_file:
data_dict = json.load(json_file)
guild_id = data_dict["guild_id"]
class MyBot(commands.Bot):
def __init__(self) -> None:
super().__init__(
command_prefix = "kt$",
intents = discord.Intents.all(),
tree_cls=CustomCommandTree)
async def setup_hook(self) -> None:
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
await self.load_extension(f"cogs.{filename[:-3]}")
await bot.tree.sync(guild=discord.Object(id=guild_id))
async def on_ready(self):
application_info = await self.application_info()
bot_owner = application_info.owner
await bot_owner.create_dm()
self.bot_owner_dm_channel = bot_owner.dm_channel
await self.change_presence(activity=discord.Game(presence_message))
print(f"Logged in as\n\tName: {self.user.name}\n\tID: {self.user.id}")
print(f"Running pycord version: {discord.__version__}")
print(f"Synced commands to guild with id {guild_id}.")
bot = MyBot()
bot.run(bot_token)
I tried following the instructions which were described in link but I have no guild specified, so this doesn't work.
The docs says it should work but it doesn't for me any ideas?
If you are using pycord, at least for me commands were usable in dm's by default. I'll show you how to disable that if you ever need to.
#bot.command()
#commands.guild_only()
async def example(ctx):
#do things
I made a discord bot with a main file and one other file of commands that are loaded with cogs and the problem is that the commands are not loaded.
I simplified the code triny to resolve the error but even this does not work:
bot.py:
import discord
from discord.ext import commands
import config
# declaring intents and launching client
intents = discord.Intents.default()
intents.members = True
intents.presences = True
bot = commands.Bot(command_prefix='.', description="Useful bot", intents=intents)
startup_extensions = ["private_channels"]
# listener
#bot.event
async def on_ready():
print(f'Connected to Discord as {bot.user} !')
#bot.event
async def on_message(message):
if message.author == bot.user:
return
print("message received")
# starting extensions
for extension in startup_extensions:
try:
bot.load_extension(extension)
except Exception as e:
exc = '{}: {}'.format(type(e).__name__, e)
print('Failed to load extension {}\n{}'.format(extension, exc))
# starting bot
bot.run(config.token)
private_channels.py:
from discord.ext import commands
class PrivateChannels(commands.Cog):
def __init__(self, bot):
self.bot = bot
# creates a new private channel
#commands.command(name="test")
async def test(self, ctx):
await ctx.send("test")
def setup(bot):
print("Loading private channels")
bot.add_cog(PrivateChannels(bot))
print("Private channels loaded")
Okay, the main problem that I had is that on_message event overwrites the commands. To correct that, I added await bot.process_commands(message) to on_message to process commands and now it works.