Verification system. (discordpy) - python

Okay so im trying to make a verify system, but im stuck with it. How could i fix it? (The reason for why i dont use simply ctx, is that this is in an on_ready event.)
guild = client.get_guild(id)
if client.fetch_guild(guild) == '928779004654256239':
channel = client.get_channel('930910261332819968')
text = discord.Embed(title="React below to verify.", color=discord.colour.blue())
moji = await client.send_message(channel, text, embed=text)
await client.add_reaction(moji, emoji='✔')
else:
return
Traceback:
C:\Users\User\Desktop\Dexton\Dexton.py:19: RuntimeWarning: coroutine 'Client.fetch_guild' was never awaited
if client.fetch_guild(guild) == '928779004654256239'

To answer your question, fetch_guild makes an API call and is a coroutine, so any calls to it should be awaited. It also accepts an int as a parameter, not a Guild, and you probably don't want to be comparing a Guild to an int either.
However, it seems that you're making unnecessary function calls anyway - you shouldn't need to call get_guild or fetch_guild at all. Just calling get_channel should be enough since the return type will be None if your bot account isn't in the guild anyway (as the channel won't be found).
With that in mind, you can change your code as such:
channel = client.get_channel(930910261332819968)
text = discord.Embed(title="React below to verify.", color=discord.Colour.blue())
if channel:
moji = await channel.send(embed=text)
await moji.add_reaction('✔')
A few other improvements were also made in the above code snippet, namely using TextChannel.send and Message.add_reaction in favor of Client.send_message and Client.add_reaction, respectively.
You should also keep in mind that a new verification message will be sent each time you run your bot unless you add a mechanism to prevent that. You may also want to use fetch_channel rather than get_channel to prevent any cache issues.

Related

bot.get_channel() occasionally returning none in discord.py,

I am trying to write a discord.py bot. The following is an abridgement of my full code.
intents = discord.Intents.default()
intents.message_content = True
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(intents=intents, command_prefix="!", sort_commands=False)
client = discord.Client(intents=intents)
#bot.event
async def on_ready():
print(f'{bot.user.name} has connected to Discord!')
channel = bot.get_channel(12345678912345678912)
await channel.send("This is a test.")
bot.run(TOKEN)
Sometimes, the code above will work as intended, printing the connection message and sending the desired message into the target channel.
This is not always the case, however! I am getting an issue where the bot.get_channel() command returns none instead of the correct data. I assume this means that the channel cannot be found, except for the fact that the channel does exist.
The error that is sent to the console is;
AttributeError: 'NoneType' object has no attribute 'send'
I am very, very new to discord.py so I would appreciate any help I can get to better understand what's going on under the hood here. Thank you very much for your help.
The get_channel method is a cache lookup method, so it's not always reliable, or the bot doesn't have access to the channel, and since it doesn't raise an exception if the cache wasn't found and returns None instead, you can't know the reason for sure. You can use fetch_channel to make an API request after get_channel if it returns none; this method will raise an exception if the channel was not found or it doesn't have permission to fetch.
channel = (bot.get_channel(1234567890) or await bot.fetch_channel(1234567890))
await channel.send("This is a test.")
Also it seems like you have both discord.ext.commands.Bot and discord.Client instance, please choose one and remove the other.
The accepted answer is not recommended.
The reason it doesn't work is because the cache isn't populated yet in on_ready, but you should not make API requests (fetch_X & send) in on_ready! Making API calls in there has a high chance for Discord to just disconnect your bot.
Also, on_ready gets triggered multiple times, so you'll end up sending this message constantly even though you only started it once.
There's rarely a reason to do anything at all in there. If you want something to run once on startup you can create a Task & start it in setup_hook.

How does discord.py detect that a message is sent using just a coroutine which is being defined in the code itself?

I am a intermediate python programmer and just started coding discord bots using the discord.py module. One question that always revolves around my head is, how does the module detect that a message is sent using on_message() coroutine which is declared in our code and no such detection construct is there?
async def on_message(mssg):
#our conditions and responses
Consider the above code. Is there an equivalent predefined coroutine in the module that calls when we declare the on_message() in our code or is there something else that makes it to detect messages and pass it to the function argument, or detect any other event? On youtube or elsewhere, they just make you learn the syntax for some reason that you have to use async...await from the documentation.
so if memory serves me correct, the on_message() is what calls the bot to listen to each message that is sent, every time a message is sent. So with your code there:
async def on_message(mssg):
#our conditions and responses
we can actually dress that up a bit with some inter-workings, like so:
#bot.listen('on_message')
it's a bot event, so every-time a message is sent, this function is called.
async def stuff(message):
pass message so that the bot knows what to scan.
if message.content.startswith("buttlerprefix"):
start it off with an if statement so that the bot has something to check the user's message against
If I typed buttlerprefix and hit enter, it would respond with this message:
msg = await message.channel.send("my prefix is `>`")
if you want to go an extra step, and keep the channels declutterd, you can set the response equal to a variable msg in the event that you want to manipulate it later, thus in this scenario, it's set to auto delete with
await asyncio.sleep(10)
await msg.delete()
So if we put all of that together:
#bot.listen('on_message')
async def stuff(message):
if message.content.startswith("buttlerprefix"):
msg = await message.channel.send("my prefix is `>`")
await asyncio.sleep(10)
await msg.delete()
we get a function that is now scanning every message that comes through the guild that this bot functions in, no matter the channel, due to the on_message() function being called every-time a message is sent which is triggered by the #bot.listen

Capturing user input as a string in Discord.py rewrite and returning said input in a message

I'm trying to capture a users input, what they say in a message, and have it returned to them in a message from the bot. More specifically, when they run a command, it'll return what ever text they have entered after that.
So far, I'm here:
async def on_message(message):
if message.content.startswith["=ok"]:
await client.send_message(message.channel, message.content[6:])
...unfortunately, I believe this was valid for the previous version of Discord.py before the rewrite. Essentially I want someone to be able to run the command =pressf and have the bot return the message "Everyone, lets pay respects to (string)!" An event probably isn't the best way to go about this but I'm stumped.
I've been struggling to find a specific answer online for my issue so I greatly appreciate anyone who could point me in the proper direction. Thanks!
I would recommend using the newer Commands Extension, it is much simpler to implement what you are wanting. See this bit specifically for passing everything a user types after the command into a variable.
There is an official example I would recommend looking at here: https://github.com/Rapptz/discord.py/blob/master/examples/basic_bot.py
You should use commands instead of on_message event. Here is a simple command:
#client.command()
async def test(ctx):
await ctx.send('A Simple Command')
ctx parameter is the parameter that all commands must have. So, when you type =test, it will send to that channel A Simple Command.
If we come to what you try to do, you can use more parameters than ctx. Here is how you can do it:
#client.command()
async def pressf(ctx, *, mess):
await ctx.send(mess)
In this code, you have 1 more parameter called mess and also there's a *. That means mess parameter includes every message after =pressf. So when a user type =pressf Hello, it will send the channel Hello.

send bot framework activity from business logic Python

I'm trying the Bot Framework SDK V4 Python GA. Once I detect the intent with LUIS, I want to be able to process some business logic and respond back. I want to be able to send messages while the business logic
as I want to user to know that the logic is being processed and need him to wait for a moment. I understand that bots aren't generally used for long running processes, but I've an use case where this is needed. I'm trying to pass the turncontext to the business logic and send a message from there, but it throws the following error.
can't pickle coroutine objects
I'm new to async programming and not sure what's exactly happening here. Below is what I've tried. I've tried doing the same by placing the business logic in a different class altogether, but got the same issue. The initial message from on_message_activity goes well, but when trying to send the message from business, it throws the above error. What am I missing here?
async def someUseCase(self,turncontext: TurnContext):
await turncontext.send_activity(MessageFactory.text("Processing your query. Give me a moment."))
output = someLongRunningBusinessLogic()
return MessageFactory.text(output)
async def on_message_activity(self, turn_context: TurnContext):
luisResult = await self.LuisRecog.recognize(turn_context)
print(luisResult.get_top_scoring_intent())
intent = LuisRecognizer.top_intent(luisResult,min_score=0.40)
if intent != "None":
await turn_context.send_activity("processing your query...")
return await turn_context.send_activity(self.someUseCase(turn_context))
else:
await turn_context.send_activity(MessageFactory.text("No intent detected."))
async def functions return awaitables that should be awaited. The error you encountered is likely because you were trying to pass a coroutine to a function that expected an activity on this line:
return await turn_context.send_activity(self.someUseCase(turn_context))
send_activity expects an activity but someUseCase returns a coroutine.
You can read more about coroutines in the Python documentation: https://docs.python.org/3/library/asyncio-task.html

on_reaction_add not being run

I'm new to discord.py and trying to make a translator bot. When the user reacts with a certain flag, the bot translates it, but the event is never getting called hence I have no code to translate any messages yet. I know it's not getting called because the program isn't printing an 'x' to the console.
#client.event
async def on_reaction_add(reaction, user):
channel = reaction.message.channel
print('x')
await client.send_message(channel, '{} has added {} to the the message {}'.format(user.name, reaction.emoji, reaction.message.content))
await client.process_commands(reaction.message)
Probably a bit late to this thread but, the answer above is a valid answer. But you can also use on_raw_reaction_add which gets called even if the messages aren't in the Bot's cache.
Called when a message has a reaction added. Unlike on_reaction_add(), this is called regardless of the state of the internal message cache.
Documentation Link
Example:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
channel = await self.bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
user = await self.bot.fetch_user(payload.user_id)
emoji = payload.emoji
await channel.send("Hello")
There isn't much valid reason for why the event isn't registered/called.
One of which is stated in the docs: http://discordpy.readthedocs.io/en/async/api.html#discord.on_reaction_add. Try adding a reaction immediately to a message that is sent after the bot is online. Since messages sent before the bot is online will not be recognized by the bot (not in Client.messages).
if the message is not found in the Client.messages cache, then this
event will not be called.
Another possible reason is that this function was never defined before the client loop commenced. Verify your indentation. And/Or try placing the function directly under client = Bot(...), to check if this is the problem.
If neither of the aforementioned solves your problem, please post a minimal, complete, verifiable example (a short runnable code from top to bottom that indicates your problem).

Categories