Discord.py - passing an argument role functions - python-3.x

I wanted to create a command, like !iknow #user . A normal verification bot I think. Here's my code, I only pasted the important parts:
import discord
from discord.ext import commands
#client.command(pass_context=True)
async def iknow(ctx, arg):
await ctx.send(arg)
unknownrole = discord.utils.get(ctx.guild.roles, name = "Unknown")
await client.remove_roles(arg, unknownrole)
knownrole = discord.utils.get(ctx.guild.roles, name = "Verified")
await client.add_roles(arg, knownrole)
(The Unknown role is automatically passed when a user joins the server.)
The problem is: I get an error on line 6 (and I think I will get on line 9, too).
File
"/home/archit/.local/lib/python3.7/site-packages/discord/ext/commands/core.py",
line 83, in wrapped
ret = await coro(*args, **kwargs) File "mainbot.py", line 6, in iknow
await client.remove_roles(arg, unknownrole) AttributeError: 'Bot' object has no attribute 'remove_roles'
I just started learning python, so please don't bully me!

You're looking for Member.remove_roles and Member.add_roles.
You can also specify that arg must be of type discord.Member, which will automatically resolve your mention into the proper Member object.
Side note, it's no longer needed to specify pass_context=True when creating commands. This is done automatically, and context is always the first variable in the command coroutine.
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='!')
#client.command()
async def iknow(ctx, arg: discord.Member):
await ctx.send(arg)
unknownrole = discord.utils.get(ctx.guild.roles, name="Unknown")
await arg.remove_roles(unknownrole)
knownrole = discord.utils.get(ctx.guild.roles, name="Verified")
await arg.add_roles(knownrole)
client.run('token')

Related

Discord.py : coroutine was never awaited

Can't seem to fix this code where I'm trying to get the name of the discord server from it's invite link.
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
async def get_invite_name(link):
name = await client.fetch_invite(link).guild.name
return name
print(get_invite_name('https://discord.com/invite/veefriends'))
Tried putting await infront of client.fetch_invite(link).guild.name but it didn't work. I don't understand async.
Tried what #matthew-barlowe suggested but it spit out more errors -
File "~/DLG/sandbox.py", line 14, in <module>
print(asyncio.run(get_invite_name('https://discord.com/invite/veefriends')))
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "~/DLG/sandbox.py", line 12, in get_invite_name
return await invite.guild.name
AttributeError: 'coroutine' object has no attribute 'guild'
sys:1: RuntimeWarning: coroutine 'Client.fetch_invite' was never awaited
You have to await the async wrapper function get_invite_name as well. Running it in asyncio.run(get_invite_name('https://discord.com/invite/veefriends')) will handle that in a non async setting. You will need to import asyncio as well.
import discord
import asyncio
from discord.ext import commands
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
async def get_invite_name(link):
response = await client.fetch_invite(link)
name = response.guild.name
return name
print(asyncio.run(get_invite_name('https://discord.com/invite/veefriends')))
If you were calling it in another async function then just await get_invite_name('https://discord.com/invite/veefriends') would be sufficient

Pycord mute command doesn't throw error but doesn't add role

I am using pycord for this so I can use slash commands.
Here is my code:
import discord, os
from dotenv import load_dotenv
from discord.ext import commands
load_dotenv(f'{os.getcwd()}/token.env')
bot = commands.Bot()
token = str(os.getenv('TOKEN'))
#bot.slash_command(description = 'mutes member of choice')
#commands.has_permissions(administrator = True)
async def mute(ctx, member: discord.Member):
guild = ctx.guild
mutedRole = discord.utils.get(guild.roles, name="Muted")
if not mutedRole:
mutedRole = await guild.create_role(name="Muted")
for channel in guild.channels:
await channel.set_permissions(mutedRole, speak=False, send_messages=False, read_message_history=True, read_messages=False)
await member.add_roles(mutedRole)
await ctx.send(f"Muted {member.mention}")
#mute.error
async def permserror(ctx, error):
if isinstance(error, commands.MissingPermissions):
ctx.respond('Sorry! You dont have permission.')
#bot.event
async def on_ready():
print(f'Client ready as {bot.user}')
bot.run(token)
This isn't my full code, but the other commands don't seem necessary for my problem.
Anyway, when I try to use this command, it doesn't throw an error in the console, but the application doesn't respond and it doesn't add the role.
I put a print statement between each line of code, and it seems to stop just before it adds the role.
How can I fix this?
Update: My previous code did not run so I have updated it.
This doesn't actually have to do with the code of the program. All you have to do is move the bot role to the top and it'll work. The error is 403 Forbidden (error code: 50013): Missing Permissions. Also, you have to reinvite the bot and add applications.commands if you haven't already.

Nextcord Ban & Kick issue

I'm trying to make a discord.py bot with the help of nextcord and i've come far enough to make the code work in theory but nothing happens when i try to kick / ban, it just throws an
nextcord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Context' object has no attribute 'ban'
and i have no idea why it does so, i want it to work as inteded.
Note, the command(s) are class commands so the main bot loads in the command from another file.
Main Bot Script
# import nextcord
from nextcord.ext import commands
# import asyncio
import json
# Import all of the commands
from cogs.ban import ban
from cogs.hello import hello
from cogs.help import help
from cogs.info import info
from cogs.kick import kick
from cogs.test import test
#Define bot prefix and also remove the help command built in.
bot = commands.Bot(command_prefix=json.load(open("config.json"))["prefix"])
bot.remove_command("help")
#bot.event
async def on_ready():
print(f'Logged in as {bot.user}')
bot.add_cog(hello(bot))
bot.add_cog(help(bot))
bot.add_cog(info(bot))
bot.add_cog(test(bot))
bot.add_cog(ban(bot))
bot.add_cog(kick(bot))
bot.run(json.load(open("config.json"))["token"])
Problematic command
import discord
from nextcord.ext import commands
from nextcord.ext.commands import has_permissions, CheckFailure
bot = commands.bot
class ban(commands.Cog):
def __init__(self, client):
self.client = client
self._last_member = None
#commands.Cog.listener()
async def on_ready(self):
print('ban Cog Ready')
#commands.command()
#has_permissions(ban_members=True)
async def ban(ctx, user: discord.Member = None, *, Reason = None):
if user == None:
await ctx.send("Could you please enter a valid user?")
return
try:
await user.ban(reason=Reason)
await ctx.send(f'**{0}** has been banned.'.format(str(user)))
except Exception as error:
if isinstance(error, CheckFailure):
await ctx.send("Looks like you don't have the permissions to use this command.")
else:
await ctx.send(error)
You are doing:
user: discord.Member
You need to use nextcord instead.
user: nextcord.Member
#commands.command()
#has_permissions(ban_members=True)
async def ban(ctx, user: nextcord.Member = None, *, Reason = None):#
#The rest of your code here
You can do the following
For Normal bot
#client.command(name="ban", aliases=["modbancmd"], description="Bans the mentioned user.")
#commands.has_permissions(ban_members=True)
async def ban(self, ctx, member: nextcord.Member, *, reason=None):
# Code for embed (optional)
await member.ban(reason=reason)
# (optional) await ctx.send(embed=banembed)
You can do the following
For Cogs
#commands.command(name="ban", aliases=["modbancmd"], description="Bans the mentioned user.")
#commands.has_permissions(ban_members=True)
async def ban(self, ctx, member: nextcord.Member, *, reason=None):
# Code for embed (optional)
await member.ban(reason=reason)
# (optional) await ctx.send(embed=banembed)
Well, here are the problems:
Your command is in a cog therefore you need to say (self, ctx, and so on)
You need to change the discord to nextcord
You should change the commands.bot to commands.Bot()
And if I'm correct, you should change the self.client to self.bot since your commands.Bot() is defined as bot
And uhh yeah it should work perfectly after you fix those.

Discordpy welcome bot

So, i tried to make a bot that send embed to specific channel everytime user join my server.
The code is look like this
import discord
import asyncio
import datetime
from discord.ext import commands
intents = discord.Intents()
intents.members = True
intents.messages = True
intents.presences = True
bot = commands.Bot(command_prefix="a!", intents=intents)
#bot.event
async def on_ready():
print('Bot is ready.')
#bot.event
async def on_member_join(ctx, member):
embed = discord.Embed(colour=0x1abc9c, description=f"Welcome {member.name} to {member.guild.name}!")
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.set_author(name=member.name, icon_url=member.avatar_url)
embed.timestamp = datetime.datetime.utcnow()
channel = guild.get_channel(816353040482566164)
await channel.send(embed=embed)
and i got an error
Ignoring exception in on_member_join
Traceback (most recent call last):
File "C:\Users\Piero\AppData\Roaming\Python\Python39\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "C:\Users\Piero\Documents\Discord\a-chan\achan_bot\main.py", line 24, in on_member_join
channel = guild.get_channel(816353040482566164)
NameError: name 'guild' is not defined
Anyone know what is wrong in my code?
First of all, looking at the discord.py documention, ctx is not passed to the on_member_join event reference. However, you can use the attributes of member which is passed in order to get the values which you need.
#bot.event
async def on_member_join(member):
embed = discord.Embed(
colour=0x1abc9c,
description=f"Welcome {member.name} to {member.guild.name}!"
)
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.set_author(name=member.name, icon_url=member.avatar_url)
embed.timestamp = datetime.datetime.utcnow()
channel = member.guild.get_channel(816353040482566164)
await channel.send(embed=embed)
Interestingly enough, you did this perfectly for getting the guild name, but it seems you forgot to do the same when retrieving channel.
You did not define guild.
To define your guild you can do the following:
guild = bot.get_guild(GuildID)
It's the same method you used to define your channel, just for your guild now.
For further information you can have a look at the docs: https://discordpy.readthedocs.io/en/latest/api.html#discord.Client.get_guild
Also take into account that we do not have a paramter like ctx in an on_member_join event.
The event just has the parameter member in your case:
#bot.event
async def on_member_join(member): #Removed ctx

Discord.py, Required argument that is missing

from discord.utils import get
import discord
TOKEN = '########' #Taken out
BOT_PREFIX = '!'
ROLE = 'Bot'
bot = commands.Bot(command_prefix=BOT_PREFIX)
#bot.event
async def on_ready():
print("Logged in as: " + bot.user.name + "\n")
#bot.command(pass_context=True)
#commands.has_role("Sergeant") # This must be exactly the name of the appropriate role
async def addrole(ctx, members):
member = ctx.message.author
role = get(member.server.roles, name="Test")
await bot.add_roles(member, role)
bot.run(TOKEN)
So the code above is what I use.
Traceback (most recent call last):
File "C:\Users\Joshua\AppData\Local\Programs\Python\Python37-32\lib\site-packages\discord\ext\commands\bot.py", line 892, in invoke
await ctx.command.invoke(ctx)
File "C:\Users\Joshua\AppData\Local\Programs\Python\Python37-32\lib\site-packages\discord\ext\commands\core.py", line 790, in invoke
await self.prepare(ctx)
File "C:\Users\Joshua\AppData\Local\Programs\Python\Python37-32\lib\site-packages\discord\ext\commands\core.py", line 751, in prepare
await self._parse_arguments(ctx)
File "C:\Users\Joshua\AppData\Local\Programs\Python\Python37-32\lib\site-packages\discord\ext\commands\core.py", line 670, in _parse_arguments
transformed = await self.transform(ctx, param)
File "C:\Users\Joshua\AppData\Local\Programs\Python\Python37-32\lib\site-packages\discord\ext\commands\core.py", line 516, in transform
raise MissingRequiredArgument(param)
discord.ext.commands.errors.MissingRequiredArgument: author is a required argument that is missing.
And this is the error, I belive this is todo with the rewrite but honestly I can't get to grips with it. If anyboby could shine some light on this I would really appreciate it.
Alright, so first you need to import commands from discord at the top of your file. Your bot variable calls this when grabbing the prefix:
from discord.ext import commands
Next, you no longer need pass_content=True in #bot.command(), as context is now always passed. The documentation stating that can be found here.
I noticed that you are checking if the author has a role by name. Although this does work, a better method is checking if the author has the permissions to manage roles, or if he/she is an administrator. That is typed like so:
#commands.has_permissions(administrator=True)
A full list of the different arguments that you can pass into that decorator are found here.
Now regarding your error message, you have a parameter called members in your command function. Since this is a positional parameter, you must provide it when typing your command in discord. However, its not doing anything in your code, so you can remove it:
async def addrole(ctx):
More info on command parameters can be found here.
In you variable named member, you can change ctx.message.author to ctx.author.
In the role variable, when attempting to get the roles on your server, we no longer use member.server.roles. It has been changed to guild, as shown in the docs. Here's how you would type it:
role = get(member.guild.roles, name="Test")
And the final change is adding the role to the member. The rewrite version of discord.py removed a lot of functionality from bot. The add_roles function is now called from a member object, so this would be written like so:
await member.add_roles(role)
We're taking your member variable (ctx.author, which is a member object) and adding a role (the role variable, which fetches a role object with the name Test) to that member. Docs on it are found here.
So your code should look something like this:
from discord.ext import commands
from discord.utils import get
import discord
TOKEN = '########' # Taken out
BOT_PREFIX = '!'
ROLE = 'Bot'
bot = commands.Bot(command_prefix=BOT_PREFIX)
#bot.event
async def on_ready():
print(f"Logged in as: {bot.user.name}")
#bot.command()
#commands.has_permissions(administrator=True)
async def addrole(ctx):
member = ctx.author
role = get(member.guild.roles, name="Test")
await member.add_roles(role)
bot.run(TOKEN)
I hope this helps with your problem :-)
Here's some links that can help you get a better grip on how discord.py-rewrite works:
Migrating to the rewrite branch
Discord.py Rewrite API

Resources