Python Asyncio: How to await something? - python

I am having a hard time understanding asyncio and the await function. I have a script that uses the Telethon wrapper that requires me to understand / use asyncio.
The only goal of the script is to download an image from a Telegram group.
I have read a beginner asyncio tutorial but I am still having a very hard time understand the concept of it and how to await something.
# Start Client
client1 = TelegramClient('sesh1', api_id1, api_hash1)
client1.start('xxx')
time.sleep(0.1)
# ---------------------------------------
# Get last message
for message in client1.iter_messages(groupname, limit=1):
data = message.file
print(data)
# Download is last message is media
if data is not None:
print("Img found")
x = client1.download_media(message=message)
print(x)
The error I keep getting is:
sys:1: RuntimeWarning: coroutine 'DownloadMethods.download_media' was never awaited.
How do I await the download function?

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.

Python Telegram Channel Reader

I've been scratching my head at this a while. Trying to just do the simple act of creating a program that will automatically read in every new post from a Telegram channel into str or something that I can use to then create a bot. I've been looking for days and everything I've seen and tried doesn't seem to work for me. Apologies cause I know this is probably stupid simple and there is an answer somewhere but the answer's I've seen just haven't worked or maybe I just don't get async at all.
import configparser
import json
import re
from telethon import TelegramClient, events
api_id = 'xxxxx'
api_hash = 'xxxxxxxxxxxx'
user_input_channel = 'https://t.me/Kucoin_news'
subjectFilter = ['']
levelFilter = ['']
client = TelegramClient(None, api_id, api_hash)
#client.on(events.NewMessage(chats=user_input_channel))
async def newMessageListener(event):
# Get message text
newMessage = event.message.message
print(newMessage)
client.start()
client.run_until_disconnected()
/home/enigma/.config/spyder-py3/Bot.py:35: RuntimeWarning: coroutine 'AuthMethods._start' was never awaited
client.start()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/home/enigma/.config/spyder-py3/Bot.py:36: RuntimeWarning: coroutine 'UpdateMethods._run_until_disconnected' was never awaited
client.run_until_disconnected()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Does async HAVE to be used with a telethon application like this? This will only be for reading one channels new posts, not several. By the time a new post comes out the Bot will easily have completed its task. I thought that since client.start() and client.run_until_disconnected() were outside of the async function they didn't need to be awaited? Awaiting is just when you call a function inside of the async function correct? I've tried to read on this subject but find the way they explain it confusing and long winded.
client.start() under client = "ecc"

Discord.py Bot Takes too Long to Respond

Goal:
I'm developing a discord bot which scans a url every 5 seconds or so, checks for a specified change on that webpage, and will send a message in the discord channel if that change occurs. I've done this by sending the url to the bot using an if statement in on_message. The url is then passed to a tasks.loop() function, where it is scanned and processed in another function for the change.
Problem:
I'd like to be able to send a message in the discord channel which quickly ends the process taking place in the tasks.loop(), so that I can pass it a different url to scan using the on_message function. In its current form, it works-- just very slowly. From the time the cancel trigger is sent, it takes around 3 minutes to send the verification message that the process has been cancelled. I need to make this 5 seconds or less. For what its worth, the bot is kept running using replit and uptime robot, but I am sure that the long response time is not related to the frequency the repl is awoken by uptime robot.
Code:
My code is much more complex and riddled with obscurely named variables, so here is a much simpler snippet of code with the same general structure.
client = discord.Client()
channel = client.get_channel(CHANNEL_ID)
#tasks.loop()
async def myloop(website, dataframe):
channel = client.get_channel(CHANNEL_ID)
try:
# iteratively scrape data from a website for
# a predefined change in the dataframe
if change = True:
await channel.send(notification)
except:
pass
#client.event
async def on_message(message):
channel = client.get_channel(CHANNEL_ID)
msg = message.content
if msg.startswith('track'):
website = msg[6:]
await channel.send('Now tracking '+str(website))
myloop(website,df)
if msg.starswith('stop'):
myloop.cancel()
await channel.send('Done tracking, awaiting orders.')
Attempted Solutions:
I have tried using some forms of threading, which I am very new to, and I haven't found a way to make it work any faster. Any suggestions or solutions would be greatly appreciated! I've been combing the web for help for quite some time now.
Looks like you could use client.loop.create_task to create asyncio task objects, and their cancel method to immediately cancel those asyncio tasks at the right time, e.g.
import asyncio
from replit import db
_task = None
async def myloop():
website = db['website']
dataframe = db['dataframe']
channel = client.get_channel(CHANNEL_ID)
while not client.is_closed():
await asyncio.sleep(5)
try:
# iteratively scrape data from a website for
# a predefined change in the dataframe
if change:
await channel.send(notification)
except:
pass
#client.event
async def on_message(message):
global _task # This gives the function access to the variable that was already created above.
msg = message.content
if msg.startswith('track'):
website = msg[6:]
await message.channel.send('Now tracking '+str(website))
db['website'] = website
db['dataframe'] = df
if _task is not None:
_task.cancel()
_task = client.loop.create_task(myloop())
if msg.startswith('stop'):
if _task is not None:
_task.cancel()
_task = None
await message.channel.send('Done tracking, awaiting orders.')
The argument create_task takes is a coroutine that takes no arguments, so the website URL and dataframe need to be accessible to the function a different way (I'm not sure which way you would prefer or would be best; using replit's db is just an example).
With this approach, you should be able to use track again to change which website is being monitored without using stop in between.
More details in the docs:
discord.Client.loop
loop.create_task
Task.cancel
asyncio.sleep
discord.Client.is_closed
Replit db

Microsoft Teams - infinite loop in bot main

I have developed a Teams bot that runs an infinite loop at startup in order to send proactive messages to users.
async def job():
i = 60
await asyncio.sleep(i)
await _create_file_of_the_day()
await _send_question_of_the_day()
await job()
if __name__ == "__main__":
try:
loop = asyncio.get_event_loop()
t1 = loop.create_task(job())
t2 = loop.create_task((web.run_app(APP, host="localhost", port=CONFIG.PORT)))
asyncio.gather(t1,t2)
loop.run_forever()
except Exception as error:
raise error
This work on local with python app.py but when I upload the bot to azure and test it online, the infinite loop is not started and so I find it impossible to proactively send messages to users.
The two methods called work. The first creates a file on azure and the second creates two questions using the contents of the file, which should be sent proactively to all members of the channel.
Does anyone know how to help me? I need to send messages to users based on a time delay not in response to their actions. This scheduling is not constant, for example I want to send messages only on working days and not on holidays.
Thanks to all
UPDATE
I have tried this second solution just on the comments, but the result is always the same. Locally the application behaves correctly, but on Azure cloud the routine that should loop seems not to be triggered.
async def job():
i = 60
await asyncio.sleep(i)
await _create_file_of_the_day()
await _send_question_of_the_day()
await job()
async def main():
runner = aiohttp.web.AppRunner(APP)
await runner.setup()
site = web.TCPSite(runner, host='localhost', port=CONFIG.PORT)
await site.start()
asyncio.create_task(job())
while True:
await asyncio.sleep(3600)
if __name__ == "__main__":
try:
asyncio.run(main())
except Exception as error:
raise error
Not being able to use the loop to be able to schedule messages, the problem was solved by using an Azure Function type timer trigger. This function calls an endpoint created inside the bot that each time it is called executes the job() method.
These two links may be useful to understand how to create an endpoint and how to query it. In the code samples, the query is given by a click on the link which can easily be replaced by a GET request within the code.
Proactive message sample with endpoint creation
Article with explanation of proactive messages
The sample code is in python, but by browsing the git folders you can find code in other programming languages.
For the development of Azure Function I found this series of three videos on YouTube very useful.
Useful video on development of timer trigger function in python

Discord.py || How to loop a part of Program infinite times without crashing it eventually?

I am Trying to Make a 24/7 Streaming Discord Bot using while(True): Infinite Loop,
But I think that the while(True): will get crashed by the OS (Using Heroku for Hosting) or Some kind of threads problem
#commands.command(name='play',aliases=["p"])
async def _play(self, ctx: commands.Context):
i = 0
while(True): #Infinite While Loop
search = URL[i] #URL is the List of Musics I What to Stream 24/7
if not ctx.voice_state.voice:
await ctx.invoke(self._join) #joins the voice channel if not in voice channel previously
async with ctx.typing():
try:
source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop)
#Sets the Status of the Bot to What Music it is Playing Currently
await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=f"{source.title}"))
except YTDLError as e:
await ctx.send('An error occurred while processing this request: {}'.format(str(e)))
else:
song = Song(source)
await ctx.voice_state.songs.put(song) #Enqueue the Song
i = (i + 1) % len(URL) # Updates the Index of URL
await asyncio.sleep(source.DURATION) #Gets the Lenght of the Music in int and Sleeps
I thought of using Asyncio Event Loops but Can't Figure it Out How to Use it Because my Function Has Parameters/Arguments like context (ctx)
I have Also thought of Cleaning the Memory stack after each songs play... But is it possible ??? If yes can we use it to fix my problem
So Is there anyway to Loop The above Mentioned Block or Code Infinitely without crashing it eventually
Thanks in advance !!!
I have a Out of Topic Query... Can we Use the ability of Context (ctx) without passing it as a Argument.
If we Can then I might be able to use asyncio_event_loop, I suppose

Categories