How can you call a function in discord.py - python

I am new to discord.py and I am stuck on this error. I am trying to call the command removerole later in the code.
This first part works fine, I can type in discord chat:
.removerole admin Rythm
And it works, but I get an error in the second part:
'str' object has no attribute 'remove_roles'
import discord
from discord.ext import commands
client = commands.Bot(command_prefix = '.')
#client.command()
async def removerole(ctx, role: discord.Role, member: discord.Member):
await member.remove_roles(role)
await ctx.send(f'Successfully removed {role.mention} from {member.mention}')
I want to type .removeRythm in chat and the bot would remove the admin role from Rythm.
#client.command()
async def removeRythm():
await removerole(".remove", "admin", "Rythm")
Does anybody know how to do this if it even is possible to do?
Thanks MB

You are passing into the removerole method 3 strings. ".remove", "admin", "Rythm". "Rythm" is not a discord object but a String. Annotations in Python have no meaning and the compiler totally ignores them. So highlighting that member is of type discord.Member does not actaully change anything, but only confuses you.
Instead you should pass in a discord user object into the method.

I changed like so and it now works
#client.command()
async def removeRythm():
await removerole(ctx, ctx.message.guild.get_role(779716603448787004), ctx.message.guild.get_member(235088799074484224))
Thanks for the help.

Related

discord.ext.commands.bot Ignoring exception in command None discord.ext.commands.errors.CommandNotFound: Command "ping" is not found

so i was trying to create my first discord bot, with no experience in Python whatsoever just to learn stuff by doing so and stumbled on an Error (Title) which was answered quiet a lot, but didn't really help me.
Im just gonna share my code:
import discord
from discord.ext import commands
import random
client = commands.Bot(command_prefix="=", intents=discord.Intents.all())
#client.event
async def on_ready():
print("Bot is connected to Discord")
#commands.command()
async def ping(ctx):
await ctx.send("pong")
client.add_command(ping)
#client.command()
async def magic8ball(ctx, *, question):
with open("Discordbot_rank\magicball.txt", "r") as f:
random_responses = f.readlines()
response = random.choice(random_responses)
await ctx.send(response)
client.add_command(magic8ball)
client.run(Token)
I tried to run this multiple times, first without the client.add_command line, but both methods for registering a command didn't work for me. I also turned all options for privileged gateway intents in the discord developer portal on. What am i doing wrong?
Because you have an incorrect decorator for your command ping. It should be #client.command() in your case.
Also, in most of the cases, you don't need to call client.add_command(...) since you use the command() decorator shortcut already.
Only when you have cogs, you will use #commands.command() decorator. Otherwise, all commands in your main py file should have decorator #client.command() in your case.
A little bit of suggestion, since you already uses commands.Bot, you could rename your client variable to bot since it is a little bit ambiguous.
You have to use Slash commands cause user commands are no longer available
Example code using Pycord library
import discord
bot = discord.Bot()
#bot.slash_command()
async def hello(ctx, name: str = None):
name = name or ctx.author.name
await ctx.respond(f"Hello {name}!")
bot.run("token")

How to print every server using my bot with their members. discord.py

I want to print in a chat all the servers using my bot with their users count.
Code I tried:
#bot.command()
async def list(ctx):
for guild in bot.guilds:
print(f"{guild.name} with {guild.users}")
guild.name works and guild.users doesn't. How to fix?
error: 'Guild' object has no attribute 'users'
You have to use the following:
f"{guild.member_count}"
Your full code could/would be:
#bot.command()
async def list(ctx):
for guild in bot.guilds:
print(f"{guild.name} with {guild.member_count}")
Make sure to turn Intents on, if you have not
Also have a look at the docs for more information.

Discord.py react with emoji to a message

async def react(ctx):
emoji = '\N{THUMBS UP SIGN}'
await ctx.add_reaction(emoji)
Doesnt work if I type ".react"
I want the bot to react with a specific emoji on the message if a user types ".react"
Without any extra context, I can't really tell what is causing your issue. However, one thing does stand out is that the add_reaction method is a member of the message attribute of ctx, not `ctx directly. This means you need to access it first, e.g:
await ctx.message.add_reaction()
Changing that might not solve your issue though, especially if you are not getting an error. Do you have #commands.command() or #client.command() before your async def react?
Your overall code should look something like this:
from discord.ext import commands
bot = commands.Bot(command_prefix='.')
#bot.command()
async def react(ctx):
emoji = '\N{THUMBS UP SIGN}'
await ctx.message.add_reaction(emoji)
bot.run('token')

Permission Check Discord.py Bot

I am working on a discord bot for basic moderation which does kick, ban and mute for now at least. But the problem is other members can use it too. I want only a few specified role who can use it.
Don't want to work on it depending on the #role either because the name of the roles across different servers aren't the same. Also wanting to keep the bot as simple as possible.
Now, I started out as this:
#client.command(name='ban')
async def mod_ban(member: discord.User):
try:
await client.ban(member, delete_message_days=0)
await client.say('**{0}** has been banned.'.format(str(member)))
except Exception as error:
await client.say(error)
But any member can use the commands then. So, tried follow this one = Permission System for Discord.py Bot and ended up with this:
#client.command(name='ban')
async def mod_ban(context, member: discord.User):
if context.message.author.server_premission.administrator:
try:
await client.ban(member, delete_message_days=0)
await client.say('**{0}** has been banned.'.format(str(member)))
except Exception as error:
await client.say(error)
else:
await client.say('Looks like you don\'t have the perm.')
Which lands me with this error: ;-;
raise MissingRequiredArgument('{0.name} is a required argument that is missing.'.format(param))
discord.ext.commands.errors.MissingRequiredArgument: member is a required argument that is missing.
Also, besides context.message.author.server_premission.administrator I don't only want the roles with Admin perm to use this command. I also want a few other roles with have few perms like manage message, manage roles etc. to use to command too.
Thanks in advance for the help! Also, sorry if I've missed anything stupid or silly ;-;
You aren't passing the context into the coroutine in your second example (and as #Andrei suggests, you can only ban members):
#client.command(name='ban', pass_context=True)
async def mod_ban(context, member: discord.Member):
...
Also, I should probably update my answer to that question. In the context of commands, you can use the very powerful checks built into discord.ext.commands to do a lot of this for you. has_permissions does exactly what you're looking for, validating that the user has any of the necessary permissions.
from discord.ext.commands import has_permissions, CheckFailure
#client.command(name='ban', pass_context=true)
#has_permissions(administrator=True, manage_messages=True, manage_roles=True)
async def mod_ban(ctx, member: discord.Member):
await client.ban(member, delete_message_days=0)
await client.say('**{0}** has been banned.'.format(str(member)))
#mod_ban.error
async def mod_ban_error(error, ctx):
if isinstance(error, CheckFailure):
await client.send_message(ctx.message.channel, "Looks like you don't have the perm.")
As far as I can see in the discord.py documentation discord.User is not the same as discord.Member.
Try to change
async def mod_ban(context, member: discord.User):
to
async def mod_ban(context, member: discord.Member):
If you are using discord.py rewrite, you can use checks (Discord.py rewrite checks)
Which (obviusly) checks for certain things suchs as roles or permissions on the command invoker
You can use both of this decorators, below your first decorator
#commands.has_role("rolename"/roleid)
#commands.has_any_role("rolename"/roleid,"rolename"/roleid,"rolename"/roleid ...)
Where rolename is a string containing the EXACT name of the role, letter by letter and space by space, and roleid is the id of the role, which, in case it's mentionable, you can get it by typing #rolename on any of your server chatrooms
Note how you must use the second decorator if you want to pass more than one role to check

Discord.py trouble with move_member()

Im having trouble with using move_member() for a python bot. The purpose of the command is to "kick" a user by moving them to a channel, then deleting it so that they disconnect from the voice call, but do not need an invite back to the server. I am aware that just moving a user accomplishes this purpose, but I would like for a user to disconnect instead.
import discord
import random
import time
import asyncio
from discord.ext import commands
from discord.ext.commands import Bot
bot = commands.Bot(command_prefix="!")
#bot.event
async def on_ready():
await bot.change_presence(game=discord.Game(name='with fire'))
print("Logged in as " + bot.user.name)
print(discord.Server.name)
#bot.command(pass_context=True)
async def kick(ctx,victim):
await bot.create_channel(message.server, "kick", type=discord.ChannelType.voice)
await bot.move_member(victim,"kick")
await bot.delete_channel("bad boi")
bot.run('TOKEN_ID')
the line gives the error:
The channel provided must be a voice channel
await bot.move_member(victim,"kick")
and this line gives this error:
'str' object has no attribute 'id'
await bot.delete_channel("kick")
Im pretty sure you have to get the channel id instead of "kick", but I don't see exactly how to do so, because the code below isnt working, even when I replace
ChannelType.voice to discord.ChannelType.voice
discord.utils.get(server.channels, name='kick', type=ChannelType.voice)
delete_channel('kick') will not work because you need to pass in a channel object and not a string.
You do not need to use discord.utils to get the channel you want. The create_channel returns a channel object, so you should be able to use that.
But, you do need to get the Member object that you're going to kick. You also made the mistake of referencing message.server rather than ctx.message.server
#bot.command(pass_context=True)
async def kick(ctx, victim):
victim_member = discord.utils.get(ctx.message.server.members, name=victim)
kick_channel = await bot.create_channel(ctx.message.server, "kick", type=discord.ChannelType.voice)
await bot.move_member(victim_member, kick_channel)
await bot.delete_channel(kick_channel)
Now if you're using rewrite library, you would have to do the following
#bot.command()
async def kick(ctx, victim):
victim_member = discord.utils.get(ctx.guild.members, name=victim)
kick_channel = await ctx.guild.create_voice_channel("kick")
await victim_member.move_to(kick_channel, reason="bad boi lul")
await kick_channel.delete()
As abccd mentioned in the comments, this is evaluated as a string, which will not guarantee the fact that you'll be kicking the right person. discord.utils.get will grab the first result, and not necessarily the correct user if multiple users have the same name.
A better approach would be to use #user or to use UserIDs. Here's an example in the old library
#bot.command(pass_context=True)
async def kick(ctx):
victim = ctx.message.mentions[0]
kick_channel = await bot.create_channel(ctx.message.server, "kick", type=discord.ChannelType.voice)
await bot.move_member(victim,kick_channel)
await bot.delete_channel(kick_channel)
I would highly recommend to start using the rewrite library since it's much more Pythonic and it's going to be the new library in the future anyways.
According to the Discord documentation, the call to delete_channel expects a parameter of type Channel.
For more information on the Channel class, refer to the Channel documentation
If I understand what you're attempting to do, for your code to run as expected, you would need to maintain a reference to the channel you are using as your temporary channel, and then change your offending line to:
await bot.delete_channel(tmp_channel)

Categories