How could I reset a command cooldown from an error function - discord.py

I have a question. It seems that I have no idea how to reset a command cooldown, not in the actual command itself.
#bot.command()
#commands.cooldown(1,900,type=commands.BucketType.member)
async def rob(ctx, left: discord.Member):
guild=ctx.author.guild
server_members=guild.members
if left in server_members:
print('found user')
random_chance = random.randint(0,1)
if random_chance == 1:
print('robbery successful')
else:
await ctx.channel.send('Robbery not successful lol noob')
else:
await ctx.channel.send('That person is not in this server... :sob:')
#rob.error
async def roberror(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.channel.send('You have to supply me with someone to rob.. noob')
elif isinstance(error, commands.BadArgument):
await ctx.channel.send('You have to provide me with a valid person..')
elif isinstance(error, commands.CommandOnCooldown):
await ctx.channel.send(f'Chill. Your on cooldown. Try again in {math.ceil(error.retry_after)} seconds')
else:
raise error``` I would like to have it reset the command cooldown in the roberror function. Can anyone help me with this?

A command's cooldown can be reset with the reset_cooldown attribute, then pass the command context as a parameter. Heres a example using it,
rob is the command identifier then reset_cooldown is the attribute. This example would reset the cooldown of the command
rob.reset_cooldown(ctx)
It seems you would like to put this when the "rob" command was unsuccessful, you can just add it like this:
else:
await ctx.channel.send('Robbery not successful lol noob')
rob.reset_cooldown(ctx)
You can find more information in the documentation: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html

Related

Command raised an exception: AttributeError: 'str' object has no attribute 'send'

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

is there another command should i use?

So, I can't use the "?roast" command and "?roast #(user)" at the same time...
#client.event
async def on_ready():
await client.change_presence(status=discord.Status.dnd, activity=discord.Game(' "?" Booe'))
print('Bot is ready to play!')
#client.command()
async def roast(ctx, member:discord.Member):
roast_messages = [
f'{ctx.message.author.mention}You are useless as the UEUE in Queue {member.mention}',
]
await ctx.send(random.choice(roast_messages))
There is always a way to solve that , discord gives us a way like this
#client.command()
async def roast(ctx, member:discord.Member=None):#None is if nothing is given then its None
if member == None:
member = ctx.author
roast_messages = [
f'{ctx.message.author.mention}You are useless as the UEUE in Queue {member.mention}',]
await ctx.send("imagine roasting yourself")#Your Choice Absolutely :)
await ctx.send(random.choice(roast_messages))
here if the member isnt specified , the function is called taking member as none , later gives the none value to the ctx.author itself (dont try to write ctx.author instead of none in the async def roast it gives error as ctx aint defined. also i forgot your roast messages wont make sense then so make sure to edit them too TY :)

how do i display a message if user puts a non existing sub command?

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.

I want to make a command that deletes a channel discord.py

Here is what I got so far
It is saying that "await" is outside of async function and I am just confused on how to fix this. I copied part of the code from a giveaway command because that is my only source of Q&A code I have
#commands.has_permissions(administrator = True)
async def cdelete(ctx):
embed=discord.Embed(title = Which channel would you like to delete?)
await ctx.send(embed=embed)
answer = []
def check(m):
return m.author == cx.author and m.channel == ctx.channel
try:
await client.wait_for('message', timeout=15, check=check)
except asyncio.TimeoutError:
await ctx.send("Timeout. Please run the command again")
else:
answer.append(message.content)
try:
c_id= int(answer[0][2:-1])
await ctx.channel.delete
await ctx.send("Channel Deleted")
except:
await ctx.send("Thats not a valid channel!")```
If you just want a command you can make it a lot easier if you just execute a command with the channel name. You can have a look at the following:
#client.command()
#commands.has_permissions(administrator=True)
async def cdelete(ctx, channel_name):
"""Deletes a channel by name or ID."""
channel_id = int(''.join(i for i in channel_name if i.isdigit())) # Get channel ID
existing_channel = client.get_channel(channel_id) # Get channel ID with defined method
if existing_channel: # If channel with the name/ID exists
await existing_channel.delete()
else: # If the channel does not exist
await ctx.send(f'**No channel named `{channel_name}` was found.**')
We have a method to catch the channel ID and also pass that in as a valid argument. If the ID or channel name then exists we delete the channel.
You can here either mention the channel or pass in the ID.
Usage would be: cdelete #channel/ID.
If you want to avoid a long console output if you input no channel/ID/name you can build in an error handler:
#cdelete.error
async def cdelete_error(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send("You need to name a channel.")
The problem you have here is with the check() function. According to the doc you only can use await inside of an async function. To solve the problem change def check(m): into async def check(m):

This Ban command does not work... How can I fix it?

Here is my ban command! Everytime I want to ban someone it dosen't go thru else! To be honest it dosen't do anything other than the if! Please help!
#bot.command() #ban (verified works)
#commands.has_permissions(ban_members = True)
async def ban(ctx, member : discord.Member, *, reason = None):
if member == ctx.author or member.id == bot.user.id:
await ctx.send("Unfortunatly I cannot do that!")
return
else:
await ctx.send('Banned the member {}'.format(ctx.member.mention))
await member.ban(reason = reason)
await ctx.message.delete()
I recommend not using the role to check if the user can use the command, rather try using something like this:
#client.command()
#commands.has_permissions(ban_members=True)
async def ban(ctx, member : discord.Member,*,reason=None):
try:
await member.ban(reason=reason)
embed = discord.Embed(description=f":white_check_mark: succesfully banned {member.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
except:
e2 = discord.Embed(description="You don't have permission to use this command",color=0xff0000)
await ctx.send(embed=e2)
This allows you to use the bot in multiple servers, who don't necessarily have the same roles, and also narrows it down to a certain permission.

Resources