I found this code in Stackoverflow which prints any error messages. But it doesn't print the error. Just to say if it is relevant, PyCharm said that Bot doesn't have attribute AppInfo.
Code:
#bot.event
async def on_error(event, *args, **kwargs):
embed = discord.Embed(title=':x: Event Error', colour=0xe74c3c)
embed.add_field(name='Event', value=event)
embed.description = '```py\n%s\n```' % traceback.format_exc()
embed.timestamp = datetime.datetime.utcnow()
await bot.AppInfo.owner.send(embed=embed)
The bot class does not have an AppInfo attribute by default. To create it, include on your on_ready() event that attribute:
#bot.event
async def on_ready():
if not hasattr(bot, 'AppInfo'):
bot.AppInfo = await bot.application_info()
Doing this, it will be available when it is used in your on_error event.
I found another Stackoverflow question (Discord.py-Rewrite Sending an Error message when there is an unknown command or other error) which has the answer. As it seems, there was no need to complicate the command as the case with my code.
Related
I'm trying to do a custom embed command and i got this error.
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'str' object has no attribute 'send'
And this is my code:
#client.command()
#commands.has_permissions(administrator=True)
async def embed(self, ctx,*, msg=None):
if msg == None:
await ctx.send("No Message has been provided. Please write your message within 30secs.")
def check(message):
return message.author == ctx.author and message.channel == ctx.channel
try:
mes=await self.client.wait_for('message',check=check,timeout=30.0)
except asyncio.TimeoutError:
await ctx.send('Timeout! Please be quicker next time.')
else:
msg=mes.content
em=discord.Embed(
description=msg,
timestamp=datetime.utcnow(),
color=discord.Color.random()).set_author(
name=f'{ctx.author.name}#{ctx.author.discriminator}',
icon_url=f'{ctx.author.avatar_url}')
await ctx.send(embed=em)
If u can patch it please say me below :(
You're doing
#client.command()
#commands.has_permissions(administrator=True)
async def embed(self, ctx,*, msg=None):
If you're in a cog, you need to be doing #commands.command. When doing client.command decorator though, you're adding the callback itself (and it isn't called from the class). The actual context is passed to self, and ctx becomes your first argument (a string) while the other argument msg just stays as None.
If you are in a cog, then change it to a normal command.
#commands.command()
#commands.has_permissions(administrator=True)
async def embed(self, ctx,*, msg=None):
#testy.command(name='d')
#commands.has_permissions(administrator=True)
async def embed(ctx, msg=None):
if msg == None:
await ctx.send("No Message has been provided. Please write your message within 30secs.")
def check(message):
return message.author == ctx.author and message.channel == ctx.channel
try:
mes=await testy.wait_for('message',check=check,timeout=30.0)
except asyncio.TimeoutError:
await ctx.send('Timeout! Please be quicker next time.')
else:
msg=mes.content
em=discord.Embed(description=msg, timestamp=datetime.datetime.utcnow(), color=discord.Color.random())
em.set_author(name=ctx.author, icon_url=ctx.author.avatar)
await ctx.send(embed=em)
Using your code as a base, I tweaked a couple of things and verified it worked on my tester bot. You can see the name of my bot is "testy" so you'll want to replace that with your client.
The command is invoked with the command 'd' and then prompts the user for a text string. That string is then displayed in an embed with a timestamp and the user's discord name and avatar.
Hope this leads you in the right direction.
I am not sure what you are passing in for ctx, but it looks like you're passing in a string for ctx based off of the error, in which case there is no send() function for a string object
So i startet today with python and wanted to code a discord bot. Now I ran into that problem that I have 4 asyncs all of them back to back but only the first one is working.
bot = commands.Bot(command_prefix="$")
async def Member(ctx):
await ctx.channel.send("||#Member||")
async def Supporter(ctx):
await ctx.channel.send("||#Supporter||")
async def everyone(ctx):
await ctx.channel.send("||#everyone||")```
So, I think you might be new to this. But when we post questions here we provide the code along with an error if there is one. Otherwise, how are we going to know your issue. But I am going to try to guess. Your bot.start() before the other functions because if so, the bot wont recognize them.
Needs to be like this.
#commands.has_permissions(administrator=True)
#bot.command()
async def setdefaultrole(ctx, defualtRole):
guildID = ctx.guild.id
updateDefualtRole(guildID, defualtRole)
################################ Add Defualt Role ##################################################
##commands.has_permissions(administrator=True)
##bot.command()
#async def setdefualtrole(ctx, defualtRole):
#guildID = ctx.guild.id
#updateDefualtRole(guildID, defualtRole)
bot.run("TOKEN")
See how the bot.run() or bot.start() is at the bottom of all the functions. If this is not the problem, then add a code snippet from your code and then at me. Good luck.
So the answer to this question for anyone in the future. He need to add bot.command() to every new command he was trying to make. Otherwise, it will not register as a command.
New code:
#bot.command()
async def Member(ctx):
await ctx.channel.send("||#Member||")
#bot.command()
async def Supporter(ctx):
await ctx.channel.send("||#Supporter||")
#bot.command()
async def everyone(ctx):
await ctx.channel.send("||#everyone||")
I've scrolled through other people's posts about this, ive tried reworking their code to mine, but it doesnt seem to work
snipe_message_author = {}
#client.event
async def on_message_edit(message_before, message_after):
snipe_message_author = message_before.author
guild = message_before.guild.name
#client.command()
async def snipeedit(ctx):
channel = ctx.channel
try:
snipeEmbed = discord.Embed(colour = discord.Colour.orange(),title=f"{snipe_message_author[channel.id]}", description = f"""Original message : {message_before.content}
Updated message : {message_after.content}""")
await ctx.send(embed = snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{channel.name}")
Every time i try the code, it returns "There are no edited messages in #*channel*"
I think its because of the snipe_message_author
thanks to anyone who helps.
As Łukasz Kwieciński's comment says:
You never add anything to snipe_message_author = {}, it can't work at all. Based on other posts, you can easily come up with a solution.
Take a look at the following code:
edited_messages = {}
#client.event
async def on_message_edit(message_before, message_after):
edited_messages[message_before.guild.id] = (message_before.content, message_after.content, message_before.author)
#client.command()
async def snipeedit(ctx):
try:
content_before, content_after, message_author = edited_messages[ctx.guild.id]
snipeEmbed = discord.Embed(color=discord.Colour.orange(), title=f"{message_author}",
description=f"Original message : {content_before}
Updated message : {content_after}")
await ctx.send(embed=snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{ctx.channel.name}")
In our on_message_edit event, we first define what should be "saved" for our guild or what exactly applies.
After we define these things, they are saved in the order specified. So now we have 3 "data" stored. We query or redefine these in our try statement and then read them from edited_messages for the corresponding ctx.guild.
So I made a sub command that just sends a message back. I found that if the user types a non existing command it still displays the message from the sub command. It sounds confusing but here's an example.
User: ;id
Bot: This command help you find the name of anyone in the server!
User: ;id Slayer
Bot: Bob Miller
So while testing I found if the user sends some thing like ;id jgfjkag the bot still sends the original message for ;id which is "This command help you find the name of anyone in the server!". How would I make the bot send a specific message if the user trys to use a non existing sub command? Here's the code:
#commands.group()
async def id(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send("This command help you find the name of anyone in the server! ")
#id.command()
async def Slayer(self, ctx):
await ctx.send("Bob Miller")
#id.command()
async def Skel(self, ctx):
await ctx.send("John Dove")
Check ctx.subcommand_passed first:
#commands.group()
async def id(self, ctx):
if ctx.subcommand_passed is None:
await ctx.send("This command help you find the name of anyone in the server!")
elif ctx.invoked_subcommand is None:
await ctx.send(f"Subcommand '{ctx.subcommand_passed}' does not exist.")
This is my favorite method of doing it:
#commands.group(invoke_without_command=True)
async def group(self, ctx):
await ctx.send_help(ctx.command) # invokes the help command for the group
#group.command()
async def subcommand(self, ctx):
await ctx.send("You passed a valid subcommand!")
The invoke_without_command parameter, when set to true, will only call the command if there are no (valid) subcommands passed. This means that if the code inside if the group() function is called, you can safely assume that they didn't pass a subcommand (or passed an invalid one).
I also like to use ctx.send_help, since that will automatically list subcommands. You could replace this with something like:
await ctx.send("You didn't pass a valid subcommand!")
[EDIT]
More careful reading of your question revealed that the subcommand already has some functionality. This makes it more difficult, but this will work:
#commands.group(invoke_without_command=True, ignore_extra=False)
async def group(self, ctx):
await ctx.send("This is a group command!")
#group.error
async def on_group_error(self, ctx, error):
if isinstance(error, commands.TooManyArguments):
await ctx.send("You passed an invalid subcommand!")
#group.command()
async def subcommand(self, ctx):
await ctx.send("You passed a VALID subcommand!")
Here is what it would look like:
!group
Bot: This is a group command!
!group bla
Bot: You passed an invalid subcommand!
!group subcommand
Bot: You passed a VALID subcommand!
NOTE: The ignore_extra field raises the commands.TooManyArguments error, which then invokes the error handler allowing the bot to send the error message. Unfortunately, the default on_command_error hook will still be called. I would suggest ignoring the commands.TooManyArguments error inside of your main error handler to fix this.
Discord.py, how to set a command, without Prefix, only with certain word to which bot replies, and also bot replies to that command while Dm with the bot.
Remember about the errors for example, bot object has no attribute on_message, etc, errors.
You can write a function to pass to command_prefix that will check for one prefix in servers and another (or none) in private messages:
from discord.ext import commands
def command_prefix(bot, message):
if message.guild is None:
return ''
else:
return '$'
bot = commands.Bot(command_prefix=command_prefix)
#bot.command(name='hello')
async def hello(ctx):
await ctx.send("Hello")
bot.run("TOKEN")
If you are using this in a cog.
#commands.Cog.listener()
async def on_message(self,message):
await message.send("Hello!")
or in the main.py
#bot.event
async def on_message(message):
await message.send("Hello!")
Please reply back if you have an error with this.
message.guild will return None if the message is in dms.