from discord.ext import commands
client = commands.Bot(command_prefix='{')
#client.command()
async def ping(ctx):
await ctx.send("Pong!")
I'm extremely new to Python and I'm currently learning how to program a discord bot with discord.py rewrite. I followed this code from a YouTuber named Lucas. This is his exact code. His seems to work but for some reason, my PyCharm still says that client has no attribute command. May someone teach me how to fix it?
This is the error
Traceback (most recent call last):
File "C:/Users/danie/PycharmProjects/Discord Tutorial/bot.py", line 93, in <module>
#client.command()
AttributeError: 'Client' object has no attribute 'command'
With my knowledge, if you wish to continue using the client part of discord.py, then you should try the on_message part of it, An example:
async def on_message(message):
if message.content.startswith('{ping'):
await message.channel.send('pong')
But if you want a reletivly easier alternative, (At least it makes more sense to me) You could try #bot.command Example:
import discord
from discord.ext import commands
TOKEN = ''
bot = commands.Bot(command_prefix='{')
#bot.command()
async def ping(ctx):
await ctx.send('pong')
One great thing about #bot.command is its easier to get input.
If you want to get what the user says after they do the command, then you could do.
#bot.command()
async def ping(ctx, *, variableName):
await ctx.send(f'You said {variableName}')
And if you want an error message if they mess up you could do
#bot.command()
async def ping(ctx, *, variableName):
await ctx.send(f'You said {variableName}')
#ping.error
async def ping_error(ctx, error):
ctx.send("Please enter something after the command")
And in my experience, it is much easier to find help on stackoverflow if you are using #bot.command as most other people use it as well. However, back to you wanting to use #client.command I do not know about that. However, if you want to switch over to #bot.command then I'm sure you can look up what you want to do on either google or stackoverflow and look until you find one for #bot.command Which shouldn't be that long.
Related
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")
I am trying to make a Discord bot and one of the features is a welcoming from my bot using on_member_join. This is the event:
#bot.event
async def on_member_join(member, self):
embed = discord.Embed(colour=discord.Colour(0x95efcc), description=f"Welcome to Rebellions server! You are the{len(list(member.guild.members))}th member!")
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.set_author(name=f"{member.name}", icon_url=f"{member.avatar_url}")
embed.set_footer(text=f"{member.guild}", icon_url=f"{member.guild.icon_url}")
embed.timestamp = datetime.datetime.utcnow()
await welcome_channel.send(embed=embed)
Although when the bot is working and running and someone joins my server I get this error:
[2022-11-07 19:38:10] [ERROR ] discord.client: Ignoring exception in on_member_join
Traceback (most recent call last):
File "C:\Users\stene\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\client.py", line 409, in _run_event
await coro(*args, **kwargs)
File "C:\Users\stene\OneDrive\Documents\GitHub\bot\main.py", line 25, in on_member_join
embed.set_thumbnail(url=f"{member.avatar_url}")
^^^^^^^^^^^^^^^^^
AttributeError: 'Member' object has no attribute 'avatar_url'
I am running the latest version of discord.py and python.
Thanks!
welcome cog:
import discord
from discord.ext import commands
import asyncio
import datetime
class WelcomeCog(commands.Cog, name="Welcome"):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_member_join(self, member):
embed = discord.Embed(colour=discord.Colour(0x95efcc), description=f"Welcome to Rebellions server! You are the{len(list(member.guild.members))}th member!")
embed.set_thumbnail(url=member.avatar.url)
embed.set_author(name=member.name, icon_url=member.avatar.url)
embed.set_footer(text=member.guild)
embed.timestamp = datetime.datetime.utcnow()
channel = self.bot.get_channel(1038893507961692290)
await channel.send(embed=embed)
async def setup(bot):
await bot.add_cog(WelcomeCog(bot))
print("Welcome cog has been loaded successfully!")
In discord.py 2.0 the attribute Member.avatar_url got removed and replaced by Member.avatar. To access the URL, you should use member.avatar.url.
Check out the migration guide for similar instances. Using pip freeze you can check which version of discord.py you have installed, but I assume it's 2.x, and probably you followed a tutorial or copied a code example that used discord.py 1.x.
Following your code you have several errors, which can be corrected in the following code:
First: async def on_member_join(member, self): is an incorrect code.
self always comes before any other argument if this event is in a cog file, but still it isn't a required argument so completely remove it. The correct code for this line is async def on_member_join(member):
Second: Make sure you're using the correct event listener.
#client.event or #bot.event if this is in your Main file, and #commands.Cog.listener() if this is in your cog file.
Third: Please change (member, self): to (member:discord.Member)
Good luck! :D
I'm trying to make some 'fun' commands as bots call them, and I wanted to embed them. However it doesnt spit out anything, not even an error on discord, nor on the command prompt, giving me no ideas on how to improve the code. I'd also like to implement a way to use the members: commands.Greedy[discord.Members] code so I can find who was the target for the command, but I think I need to solve this first. Any suggestions on how to do so?
I also am stumped because I used the .format and the f string to try to use arguments, and I also tried using message, but that gave me a syntax error of 'Error 'list' object has no attribute 'mention''. I really cant understand the documents on the commands since they dont really give any examples of actual code, and I suck at understanding new stuff. Can someone figure this out?
from discord.ext import commands
import discord
bot= commands.Bot(command_prefix='0!')
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content.startswith('Sample Text'):
await message.channel.send('Sample Text')
#bot.command()
async def slap(ctx):
embed = discord.Embed(color=0x00ff00, title='OH! Z E S L A P !', description="ooh, that hurt.")
embed.add_field(name="Man behind the slaughter:", value="test")
await ctx.send(embed=embed)
bot.run('token here')```
-During this edit, when I just had the 'bot command' area, It seemed to have functioned still. This makes it even more confusing...
Overriding the default provided on_message() event forbids any extra commands from running. To fix this, add a bot.process_commands(message) line at the end of your on_message() event.
#bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.content.startswith('Sample Text'):
await message.channel.send('Sample Text')
await bot.process_commands(message)
For some reason send_message isn't working properly on my Discord bot and I can't find anyway to fix it.
import asyncio
import discord
client = discord.Client()
#client.async_event
async def on_message(message):
author = message.author
if message.content.startswith('!test'):
print('on_message !test')
await test(author, message)
async def test(author, message):
print('in test function')
await client.send_message(message.channel, 'Hi %s, i heard you.' % author)
client.run("key")
on_message !test
in test function
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\indit\AppData\Roaming\Python\Python36\site-packages\discord\client.py", line 223, in _run_event
yield from coro(*args, **kwargs)
File "bot.py", line 15, in on_message
await test(author, message)
File "bot.py", line 21, in test
await client.send_message(message.channel, 'Hi %s, i heard you.' % author)
AttributeError: 'Client' object has no attribute 'send_message'
You are probably running the rewrite version of discord.py, since the discord.Client object does not a have a send_message method.
To fix your problem you can just have it as:
async def test(author, message):
await message.channel.send('I heard you! {0.name}'.format(author))
but for what i see you doing I reccomend using the commands extension
This makes creating a bot and commands for the bot much simpler, for example here is some code that does exactly the same as yours
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.command()
async def test(ctx):
await ctx.send('I heard you! {0}'.format(ctx.author))
bot.run('token')
As per discord.py documentation, migration to v1.0 brought a lot of major changes in the API, including the fact that a lot of functionality was moved out of discord.Client and put into their respective model.
E.g. in your specific case:
Client.send_message(abc.Messageable) --> abc.Messageable.send()
So your code would be restyled from this:
await client.send_message(message.channel, 'I heard you! {0}'.format(message.author))
to this:
await message.channel.send('I heard you! {0}'.format(message.author))
This makes the code much more consistent and more accurate in depicting the actual discord entities, i.e. it's intuitive that a discord Message is sent to a Channel (subclass of abc.Messageable) and not to the Client itself.
There is a quite large list of migrations in this sense; you can find them all here
under the Models are Stateful section.
The discord.py can't be used for the send_message() function anymore, I think. But this doesn't mean we can not send messages. Another way of sending messages into the channel do exist.
You can use:
await message.channel.send("")
for this purpose.
So let's apply this into your code now.
import asyncio
import discord
client = discord.Client()
#client.async_event
async def on_message(message):
author = message.author
if message.content.startswith('!test'):
print('on_message !test')
await test(author, message)
async def test(author, message):
print('in test function')
await message.channel.send(F'Hi {author}, I heard you.')
client.run("key")
Now this would fix your issue and you'll be able to use your bot to send messages easily.
Thank You! :D
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)