'Object' object had no attitude 'name' discord.py - python

I am trying to make an id converter that converts any id to name.
#bot.command()
async def idconv(ctx, *, arg):
id=int(arg)
conv=discord.Object(id)
await ctx.send(conv.name)

It appears as though you are trying to get a users name from their ID.
discord.py offers a class called Member that does it for you
import discord
#bot.command()
async def idconv(ctx, member: discord.Member):
await ctx.send(member.name)
While creating a discord.Object with an id is useful for banning\unbanning a user who doesn't share a guild with your bot, it isn't useful for your case.
Here is the documentation for discord.Member.
Here the command idconv accepts arguments like user-id, name, nickname and tries to convert it into a Member object.
There might be instances where the ID of the member you provided may not share a server with the bot, and hence member ends up being None , resulting in any operation with member raising an error.
You can account for that by checking it beforehand
if member: #or if member is not None
await ctx.send(member.name)
else:
await ctx.send("Could not find a user with that ID")
If you use bot.fetch_user, you
can fetch any discord user by their ID, if found it returns an User object,
which is similar to Member but has overall lesser information.

Related

Discord.py set user id as an argument

I want to create a command where its using an user id as an argument after ctx to make the bot send the user mention. The problem is, i dont know whats the syntax for user id. Im already looking through the documentation but didnt find the answer there.
Heres the code.
#client.command()
async def userid(ctx, member: discord.Member.id):
await ctx.send(f'{member.mention})
You are nearly there.
The typehint converts usernames, mentions, ID and display_name into a Member object, this object contains all of the above.
#client.command()
async def userid(ctx, member: discord.Member):
await ctx.send(member.mention)

Discord.py — Check if the user has specific roles?

I am trying to create a command that can ban people on the Server and those who are not on the server. But there is a problem: If I use async def ban(ctx, member: discord.Member, *, reason): to use the "roles" attribute, then it will not be able to ban those who are not on the server. If i use async def ban(ctx, member: discord.User, *, reason): i will not be able to use the "roles" attribute because it is not an attribute.
Why am I doing this? I am trying to make it so that Server Moderators cannot ban those who have Moderator roles
Code:
async def ban(ctx, member: discord.User = None, *, reason=None):
if get(ctx.author.roles, id=866038959980544050) or get(ctx.author.roles, id=866436325503008768) or get(
ctx.author.roles, id=866441730631008316) or ctx.author.guild_permissions.administrator: # Check if the author has the Role "Moderator", "Admin", etc.
if get(member.roles, id=867371024466968596) or get(member.roles, id=867132420489871411) and not ctx.author.guild_permissions.administrator: # Check if the member has the Role "Moderator", "Admin", etc.
await ctx.send("You cannot ban this user.")
Assuming that you use discord.ext.commands, you could use a typing.Union converter to ensure that the argument is either a user or a member.
import typing
[...]
async def ban(ctx, user: typing.Union[discord.Member, discord.User]):
Note that order matters: By having discord.Member first, it tries to apply this converter first before trying discord.User, thus prioritising conversion to a member over conversion to a user (which should be what you want).
To distinguish between the two cases, you can now check whether user is of type discord.Member and perform your checks on it.
if type(user) is discord.Member:
if YOUR_CHECKS:
await ctx.send('You cannot ban this user')
return
# Perform ban
await ctx.send('Ban successful')
When testing, I discovered that the command library will give you a numerical user id instead of a real user and shows
Failed fetching discord object! Passing ID instead. as a warning. If you need more than just the user id, you could convert it to a User object using
if type(user) is int:
user = await bot.fetch_user(user)
if user is None:
await ctx.send('User not found')
return
Note that fetch_user is an API call and you might want to avoid it. See the docs for more info.
One way of doing this would be to check if the given member is in the current guild. If this is True, you can create a new member object with their id or with another prefered method, otherwise you can assume that they do not have the Moderator role. For simplicity, I only included checking for a single role, but you can tweak this in the way you want to do it. Other than that, everything else is explained in further detail in the code below.
if member in ctx.guild.members: # checks if the provided member is in the current server
member = ctx.guild.get_member(member.id) # Get the member object of the user
if get(member.roles, id=866038959980544050): # Check if this role is in the member's roles
await ctx.send("This member has <#&866038959980544050>")
else:
await ctx.send("This member does not have <#&866038959980544050>")
return # returns, since member was in the server
# This happens if the provided member is not in the current server
await ctx.send("This member, who is not in this server, does not have <#&866038959980544050>")
You must use this
#bot.command(...)
#commands.has_any_role(role id)
...

Is there a way of kicking everyone with a certain role in discord.py?

I'm trying to make a command that kicks all the members with a certain role. It's not going very well - this is my current code:
import discord
from discord.ext import commands
from discord.ext.commands import has_permissions
client = commands.Bot(command_prefix = "k!")
#client.command(pass_context=True)
#has_permissions(administrator=True)
async def kickall(ctx):
role_id = 754061046704242799
for role_id in roles: #roles undefined lol
try:
await member.kick()
except:
continue
You can iterate through all members, and check if they have the specified role. If they do, you can kick them.
#client.command(pass_context=True)
#has_permissions(administrator=True)
async def kick(ctx, role: discord.Role, reason: str=None):
for member in ctx.guild.members:
if role in member.roles: # does member have the specified role?
await ctx.guild.kick(member, reason=reason)
The usage would be k! kick <role> <reason(optional)>
I'd recommend looking at the documentation for more details.
The parameters (ctx, role: discord.Role, reason: str=None) are as follows:
ctx - is passed in by default. This contains all the context information such as message author, server the message was sent in etc
role: discord.Role - the user must specify a role to kick when calling the command. The colon tells python and discord.py the type to try and convert the parameter to, meaning that it will convert a role name (i.e. a string) into a discord.Role object, so you can do operations on it such as comparing roles.
reason: str=None - an optional parameter (default is None). If this is provided, the users kicked will see this string as the reason message for being kicked.

How to set a default using context with context defined in same line?

I am creating a discord bot, and I am trying to make it where if a member says a command with no user mentioned, it defaults to themself. It doesn't work inline, and I need the arg in the same line.
I tried to put the default in the same line, but I need the ctx for that, and ctx is defined in the same line, so it won't work.
#bot.command(name="joined", description="Shows precisely when a member of the server joined", aliases=["entry", "jointime", "join_time"], pass_context=True)
async def joined(**ctx**, member: discord.Member = **ctx.message.author.name**):
"""Says when a member joined."""
await ctx.send('{0.name} joined in {0.joined_at}'.format(member))
I expected this, when you say !joined or !entry, with no user mention, to take the user from the context and use that instead. However, it throws me the error message "ctx is not defined."
You can mark the parameter Optional, then check if it is None in the body of the coroutine:
from discord import Member
from typing import Optional
#bot.command(name="joined", description="Shows precisely when a member of the server joined", aliases=["entry", "jointime", "join_time"], pass_context=True)
async def joined(ctx, member: Optional[Member]):
"""Says when a member joined."""
member = member or ctx.author
await ctx.send('{0.name} joined in {0.joined_at}'.format(member))

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

Categories