Exception mechanism doesn't work after some times - python

I've created a Discord bot in Python using the discord.py library. This is the pseudo-code of my bot :
import discord
client = discord.Client()
async def test_func():
return "This is a test"
async def error_func():
raise Exception
text_to_func = {"test": test_func, "error": error_func}
#client.event
async def on_message(message):
if message.content.startswith("$"):
command = message.content[1:]
try:
func = text_to_func[command]
answer = await func()
except Exception:
answer = "Error !"
await message.reply(answer)
client.run("<TOKEN>")
When a message is received by the bot, the on_message function is executed. It checks if the message starts with "$", which is the prefix of my bot, and execute the function associated with the command in a try/except block.
I run this script on a ubuntu server using an ssh connection.
Now if I send "$test" on my discord server, the bot will reply with "This is a test" and if I send "$error", it will reply with "Error !". The thing is, after a certain amount of time (can be from 6 hours to 2 days), the "$error" command won't work anymore. The bot doesn't reply to the command, while it still does for "$test".
Does someone know what's going on there ? Thank you for your help.

I'm not 100% sure what you're trying to accomplish, but if you're actually just trying to react to errors, I recommend just using:
#client.event
async def on_error(event, args, kwargs):
#what you want to happen in the event of an error
instead of putting everything you do in a try...except block.
Here are the official docs for the on_error event listener.

Related

Whats wrong in my code my code for scheduled messages on discord.py on replit

so I've been trying to make my discord bot send a message every day at 12:30 UCT but i cant seem to get my code to work I'm not sure if its not working because of incorrect code or because its on replit or whatever else the issue could be as i get no errors from this it just send the message once it loads online and that's all.
import datetime, asyncio
bot = commands.Bot(command_prefix="+")
Async def on_Ready():
await schedule_daily_message()
async def schedule_daily_message():
now = datetime.datetime.now()
then = now+datetime.timedelta(days=1)
then.replace(hour=12, minute=30)
wait_time = (then-now).total_seconds()
await asyncio.sleep(wait_time)
channel = bot.get_channel(Channel_id)
await channel.send("Enemies Spawned!")
client.run(os.getenv('TOKEN'))
await asyncio.sleep is non blocking. Your script will execute beyond that statement. You will need to use time.sleep, which that will block all execution of code until the timer has run out.
See here for a more in depth explanation and how to use this in functions:
asyncio.sleep() vs time.sleep()
A way to implement a function that posts a message to a channel after a delay could look like this:
async def send_after_delay(d, c, m):
time.sleep(d)
await c.send(m)
Calling this function asynchronously allows you to continue with code execution beyond it, while still waiting past the calling of the function to send the message.

How to make a Discord Bot that can accept arguments from Python of what message to send to who and be able to close itself?

I'm trying to do something pretty simple. I just want Python to be able to call a quick function that sends a direct message over Discord. Basically a modified version of the FAQ example. I want another Python class to start the Discord client and pass the message string and user id. And I want the Discord client to simply send the string and then close and delete the entire class. After looking through docs I made these modifications:
import discord
class MyClient(discord.Client):
async def on_ready(self):
print('Logged on as {0}!'.format(self.user))
user = await self.fetch_user(self.destination_user)
await user.send(self.message)
await self.close()
def __init__(self, user_id, user_message):
self.destination_user = user_id
self.message = user_message
client = MyClient(desired_id, desired_message)
client.run('My Client ID')
#wait for client to end and then continue
However, I'm running into 2 problems. It looks like discord.Client doesn't allow an __init__() function, and when I try to do async def __init__() there's also an error. Are there other ways to pass arguments to it through Python, rather than react to messages in Discord? Also, self.close() results in "RuntimeError: Cannot close a running event loop". What's the proper way to wait for on_ready() to finish and then close it?
I can get it working by hardcoding the user ID and message, eliminating __init__() and simply not closing the class. However, for some reason, even then self.get_user() doesn't work, only self.fetch_user(). The docs say to use get_user(), so I'd prefer that, but I don't know what I'm doing wrong. My bot is in the same server as the target user, and I've given it both privileged intents, but get_user() continues to return "None", whereas fetch_user() properly messages the user, with the same exact arguments.
I found out what seems the proper way to run discord.Client in this fashion:
import discord
import nest_asyncio
import asyncio
nest_asyncio.apply()
class DiscordClient(discord.Client):
async def on_ready(self):
user = await self.fetch_user(self.send_user)
await user.send(self.message)
async def on_message(self, message):
#Pause so there's no warning about operations not finishing when class closes
await asyncio.sleep(0.1)
await DiscordClient.close(self)
async def parameters(self, user, message):
self.send_user = user
self.message = message
async def send_discord(user, message):
print("Sending Discord message")
client = DiscordClient()
await client.parameters(user, message)
await client.start('Private Key')
print("Discord message sent")
asyncio.run(send_discord(user_id, "Test message contents"))
on_message runs even it's the bot that sent the message, so it will quickly close itself. I had to add the wait or there were some race conditions or something causing a warning every time it closed.

discord.py bot doesnt respond to Bot.commands()

Hello I am creating a discord bot i was trying to add single command but bot doesn't respond to any commands
something like
Bot = commands.Bot(command_prefix="!")
#Bot.commands()
async def ping():
print("Pong!")
this thing should respond when I type !ping in to discord client it should print pong in to terminal
but nothing nothing at all
I have tried Bot.add_command(ping) but it says command it's aleady registered i have no idea..
From what I've read from the discord.py docs you should code it like this:
Bot = commands.Bot(command_prefix="!")
#Bot.commands()
async def ping(ctx):
ctx.send("Pong!")
When you use 'print' you print the answer on your idle terminal. 'ctx.send' print the answer on discord chat. And every function on discord.py needs and argument.

How to add a function to discord.py event loop?

I am using Python with discord.py. Documentation here
I've got a bot that is running on a Discord server that links the server with a subreddit. Users have various commands that do things like getting the top submissions, getting the latest submissions, and so on.
I want to add some features to the bot, with one of them being a keyword notifier. The bot should search the subreddit for keywords in the title, and then notify users if they are on the list for that keyword. I know how to do this, I've done it plenty of times, but I don't know how to do it with a Discord bot. I have no experience with asynchio or any kind of asynchronous programming.
The way I've tried to do it works, but it is very janky and definitely not good. At the top of the on message() function, I just add a call to the search_submissions() function, so that whenever someone puts sends a new message on the server, the bot will scan the Reddit submissions. The server is busy enough that this would work relatively okay, but I really want to do it the "proper" way.
I don't know how to call the search_submissions() function without putting it inside of on_message().
Edit for extra code:
import discord
TOKEN = "redacted"
client = discord.Client()
#client.event
async def reddit_search():
print("Searching")
#client.event
async def on_message(message):
if message.content.startswith("reddit!hot"):
# Get hot
# Do other things.
#client.event
async def on_ready():
print("Connected to Discord as {}.".format(client.user.name))
client.run(TOKEN)
You can add a function to the bot event loop with Client.loop.create_task(search_submissions()) like this:
async def search_submissions():
pass
client = discord.Client()
client.loop.create_task(search_submissions())
client.run(TOKEN)
Update:
If you want your function to continue working you can put it in a while loop with some sleeping in between:
async def search_submissions():
while(true):
# do your stuff
await asyncio.sleep(1)
The other answers here don't take into account discord.py's helpful tasks.loop decorator.
To make an event occur every 5 seconds, you would use
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self):
self.foo.start()
def cog_unload(self):
self.printer.cancel()
#tasks.loop(seconds=5.0)
async def foo(self):
print('bar')
More can be found here: https://discordpy.readthedocs.io/en/latest/ext/tasks/
You want your search_submissions() function to be async so other functions of your bot can still be invoked and your bot stays responsive. Define it to be def async and use aiohttp to send async HTTP requests to reddit -- what this does is send off the request, relinquish control to the event loop, and then take back control once the results have been transmitted back. If you use a standard HTTP library here instead then your whole bot will be blocked until the result comes back. This of course only makes sense if the task is mainly I/O-bound and less CPU-bound.
Then call search_submissions() in on_message(message) -- but call it asynchronously using result = await search_submissions(). This will resume execution of on_message once the result of search_submissions is ready.
If you truly want to do something else in the same context while waiting on search_submissions (which I think is unlikely), dispatch it as task = asyncio.create_task(search_submissions()). This will start the task immediately and allow you to do something else within the same function. Once you need the result you will have to result = await task.
async def search_submissions():
async with aiohttp.ClientSession() as session:
async with session.get(some_reddit_url) as response:
return await response.read()
#client.event
async def on_message(message):
if message.content.startswith("reddit!hot"):
result = await search_submissions()
await message.channel.send(result)

Say, send_message and send, do not work in #bot event what to do? discord.py

Hello reread all the documentation on discord.py, and unfortunately did not find a simple thing like the on_member_join event in the chat send a message?
I use a non-standard construction, and such a construction client = discord.Client (), but as I understood a new bot = commands.Bot(command_prefix='!')
import discord
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.event
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')
#bot.event
async def on_member_join(member):
print(member.name)
bot.send(member.name);
Print () output to the console properly, but to send it to the chat of the discord unfortunately does not work(
I also tried:
bot.say(member.name);
bot.send_message(member.name)
bot.send(member.name)
But all the time an error is issued "'Bot' object has no attribute 'say'"
Please tell me what is wrong I do?
The version of discord.py you're using will change how you send messages.
discord.py 0.16, the "async" branch, is the current stable release. It has two ways of sending messages. (In the below, note that Bot is a subclass of Client, so every Bot also has access to all of the Client methods)
Using Client.send_message(target, message). This is what you
would use in on_message(message)
await bot.send_message(message.channel, "I am responding to your message")
Using Bot.say(message). This is an easy way of sending
messages back to the channel a command was invoked in. It only
works in commands.
await bot.say("I am responding to your command")
discord.py 1.0, the "rewrite" branch, is the most recent branch. It's considered experimental still, but is entirely usable. One of the many changes is the way that message sending works.
Now, instead of having methods on the client to send messages, we have methods on the things that receive messages to send them a message. These all implement the Messageable abstract base class, and have a send method. In your on_message, this would look like
await message.channel.send("I am responding to your message")
I believe you are using version 1.0

Categories