I have this code and I want to run it on google colab. It works great on my PC but on colab I always get errors like these:
SyntaxError: 'async with' outside async function
or
RuntimeError: You must use "async with" if the event loop is running (i.e. you are inside an "async def")
sometimes it does not wait for getting new messages and finish after one running.
import json
import time
import telethon as tlt
import asyncio
from telethon import events,TelegramClient
chat_name = "sample"
telegram_session="sample_1"
api_id = "0000000"
api_hash = ""
client = TelegramClient(None , api_id, api_hash)
#client.on(events.NewMessage(chats=chat_name))
async def handler(event):
get_message = event.message.to_dict()
get_message['date'] = get_message['date'].strftime("%Y-%m-%d %H:%M:%S")
message_json = json.dumps(get_message)
print(message_json)
async with client:
client.run_until_disconnected()
You need to put async with inside of async def:
...
async def main():
async with client:
await client.run_until_disconnected()
client.loop.run_until_complete(main())
Related
I understand that usually the discord bots are in a listening (blocking) loop, but how can I create a function that connects, send a message or perform any action and disconnect in a non blocking flow?
I'm using discord.py and I'm looking for something like:
import discord
TOKEN = "mYtOkEn"
discord.connect(TOKEN)
discord.send("I'm sending this message")
discord.disconnect()
I already tryied playing with the async but have problems with the threading, so was wondering if there is something more simple.
It is for a button that when clicked, perform that action but after that it can continue working on other tasks
Thanks beforehand
One way you could accomplish this is by using a custom event loop.
Example:
import discord
import asyncio
from threading import Thread
TOKEN = "secret"
client = discord.Client()
def init():
loop = asyncio.get_event_loop()
loop.create_task(client.start(TOKEN))
Thread(target=loop.run_forever).start()
#client.event
async def on_message(message):
if message.author == client.user:
return
await message.channel.send('Hello!')
#client.event
async def on_ready():
print("Discord bot logged in as: %s, %s" % (client.user.name, client.user.id))
init()
print("Non-blocking")
Take a look at this for more info: C-Python asyncio: running discord.py in a thread
Thank you for your help and support. With the SleepyStew answer I could find the path to solve it and went this way:
import discord
import asyncio
def discord_single_task():
# Define Coroutine
async def coroutine_to_run():
TOKEN = "Secret"
# Instantiate the Client Class
client = discord.Client()
# # Start (We won't use connect because we don't want to open a websocket, it will start a blocking loop and it is what we are avoiding)
await client.login(TOKEN)
# Do what you have to do
print("We are doing what we want to do")
# Close
await client.close()
# Create Loop to run coroutine
loop = asyncio.new_event_loop()
llll = loop.create_task(coroutine_to_run())
loop.run_until_complete(llll)
return 'Action performed successfully without a blocking loop!'
I'm creating a script to forward messages it worked perfectly, but I created a graphical interface and put the id group data in tkinter entries, and then the code stopped working I also put the ids in inputs and it doesn't work,
the code runs but does not forward the msg would anyone know how to solve it
from telethon import TelegramClient, events
import asyncio
with open('Id1.txt', 'r')as f:
Id_Group1 = f.read()
with open('Id2.txt', 'r')as j:
Id_Group2 = j.read()
print (Id_Group1, Id_Group2)
api_id = '#######'
api_hash = '#######################'
client = TelegramClient('none', api_id, api_hash)
#client.on(events.NewMessage)
async def handler(event):
chat = await event.get_chat()
chat_id = event.chat_id
print('{} {}'.format(chat_id, chat))
if chat_id == Id_Group1:
await client.send_message(Id_Group2, event.raw_text)
client.start()
client.run_until_disconnected()
This is not working because your code in if condition will never execute.
The problem is
chat_id is and Integer and
Id_Group1 is a String.
according to python and almost all other programming language.
"-1001659707082" is not equal to -1001659707082
Here is the modified codes..
import asyncio
from telethon import TelegramClient
from telethon.sync import events
Id_Group1 = "-1001659707082"#You can add username and add entity thing instead
Id_Group2 = "thisistest_2"
api_id = 123
api_hash = "12gh3"
print (Id_Group1, Id_Group2)
client = TelegramClient('none', api_id, api_hash)
#client.on(events.NewMessage)
async def handler(event):
chat = await event.get_chat()
chat_id = event.chat_id
if str(chat_id) == Id_Group1:
print('{} {}'.format(chat_id, chat))
await client.send_message(Id_Group2, event.text)
client.start()
client.run_until_disconnected()
Also watch the Id_Group1 and Id_Group2
i am using Pyrogram to work with telegram API.
I have succeed to join channel.
I have a task to add message handler and receive messages in channel.
But the message handler is not invoked when message arrives (i am the owner of channel)
The code:
import asyncio
from pyrogram import Client
import time
from pyrogram.handlers import MessageHandler, RawUpdateHandler
api_id = "xx"
api_hash = "xx"
def my_handler(client, message):
message.forward("me")
print('sent msg')
async def main():
async with Client("my_account", api_id, api_hash) as app:
a = await app.get_chat('test2k3')
msg_handler = MessageHandler(my_handler)
app.add_handler(msg_handler)
await app.join_chat(str(a.id))
print(f'joined chat ' + str(a.id))
while True:
time.sleep(2.4)
asyncio.get_event_loop().run_until_complete(main())
Sleeping while the client runs halts it until the sleep is over. Pyrogram itself will already keep itself alive until Ctrl and C is pressed. Remove your while True sleep loop.
as recommended by sudden_appearance
use asyncio.sleep() inside async functions instead of time.sleep()
I make disocord bot with api in flask. Now it just needs to send message to channel. But if I start bot with flask all flask code stops. I tried to use client.close and I had exception RuntimeError: Event loop is closed. I tried to use client.clean in different places. But I still had this exception.
Now my code looks so :
from flask import Flask, request
import json
import discord
global data
app = Flask(__name__)
client = discord.Client()
CHANNEL = <id>
#client.event
async def on_ready():
global data
channel = client.get_channel(id=CHANNEL)
await channel.send(f"{data['products'][0]['custom_fields'][0]['discord']}\nТовар : {data['products'][0]['name']}")
await client.close()
client.clear()
#app.route('/purchase', methods=['POST'])
def purchase():
global data
data = json.loads(request.data)
client.run('token')
return data['products'][0]['custom_fields'][0]['discord']
I can recommend to run it in the thread. I had the same issue when I had not to block the main thread of the game-client (I believe this should work with Flask too). Example can be found here:
import discord
import asyncio
discord_loop = asyncio.get_event_loop()
client = discord.Client(loop=discord_loop, heartbeat_timeout=20, intents=discord.Intents.all())
def init():
try:
asyncio.get_child_watcher()
global discord_loop
discord_loop = asyncio.get_event_loop()
thread = threading.Thread(target=discord_loop.run_forever)
thread.start()
asyncio.run_coroutine_threadsafe(client.connect(reconnect=True), discord_loop)
asyncio.run_coroutine_threadsafe(client.login(token=DiscordSettings.TOKEN, bot=True), discord_loop)
except:
utils.get_and_log_exception_info()
def stop():
asyncio.run_coroutine_threadsafe(client.logout(), discord_loop)
discord_loop.call_soon_threadsafe(discord_loop.stop)
def reconnect():
client.clear()
asyncio.run_coroutine_threadsafe(client.connect(reconnect=True), discord_loop)
I'm trying to run this first code snippet provided by the Telethon documentation. But, after multiple problems (here and here), I ended up with this modified version:
import os
import sys
from telethon.sync import TelegramClient, events
# import nest_asyncio
# nest_asyncio.apply()
session_name = "<session_name>"
api_id = <api_id>
api_hash = "<api_hash>"
os.chdir(sys.path[0])
if f"{session_name}.session" in os.listdir():
os.remove(f"{session_name}.session")
async with TelegramClient(session_name, api_id, api_hash) as client:
client.send_message('me', 'Hello, myself!')
print(client.download_profile_photo('me'))
#client.on(events.NewMessage(pattern='(?i).*Hello'))
async def handler(event):
await event.reply('Hey!')
client.run_until_disconnected()
However now I'm getting these warnings:
usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:23: RuntimeWarning: coroutine 'MessageMethods.send_message' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:24: RuntimeWarning: coroutine 'DownloadMethods.download_profile_photo' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:30: RuntimeWarning: coroutine 'UpdateMethods._run_until_disconnected' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
when running the code on Jupyter. Now here are my questions:
what those warning messages mean and how should I address them?
what is the expected result of this code if working properly? Should I receive a message in Telegram or something? Because I don't recive any messages other than the signin code.
What does the # symbol at the beginning of the #client.on... line mean? what does that line is supposed to do? From this line onwards I do not understand the code. Would appreciate if you could help me understand it.
Just add await the client.send_message('me', 'Hello, myself!') to solve that error and print afterdownload_profile_photo has done its work downloads an image to localhost so that may be why you don't see anything. You should read telethon documentation thoroughly and also how to use photo downloads correctly
All the calls to the client have a delay and should always be awaited so that your code doesn't get blocked. You should read the asyncio tutorial
The correct code would be:
async with TelegramClient(session_name, api_id, api_hash) as client:
await client.send_message('me', 'Hello, myself!')
print(await client.download_profile_photo('me'))
#client.on(events.NewMessage(pattern='(?i).*Hello'))
async def handler(event):
await event.reply('Hey!')
#await client.run_until_disconnected()
The # is a decorator and you should read the PEP related to decorators, but in short words, they execute a function before yours.
In this case #client.on(events.NewMessage means:
When there is a new event that happens to be a message that matches the pattern specified handle it with this function called handler
Jupyter will run the asyncio event loop so that you can use async for / with / await outside of an async def. This conflicts with Telethon's .sync magic which you should try to avoid when using Jupyter, IPython, or similar.
To fix your code:
from telethon import TelegramClient, events
# ^ note no .sync
session_name = "<session_name>"
api_id = <api_id>
api_hash = "<api_hash>"
async with TelegramClient(session_name, api_id, api_hash) as client:
await client.send_message('me', 'Hello, myself!')
# ^ note you need to use `await` in Jupyter
# we are avoiding the `.sync` magic so it needs to be done by yourself
print(await client.download_profile_photo('me'))
# ^ same here, needs await
#client.on(events.NewMessage(pattern='(?i).*Hello'))
async def handler(event):
await event.reply('Hey!')
await client.run_until_disconnected()
# ^ once again needs await
If you want code to run anywhere (Jupyter, Python shell, normal run), just be sure to do everything inside async def:
import asyncio
from telethon import TelegramClient, events
session_name = "<session_name>"
api_id = <api_id>
api_hash = "<api_hash>"
async def main():
async with TelegramClient(session_name, api_id, api_hash) as client:
await client.send_message('me', 'Hello, myself!')
print(await client.download_profile_photo('me'))
#client.on(events.NewMessage(pattern='(?i).*Hello'))
async def handler(event):
await event.reply('Hey!')
await client.run_until_disconnected()
# Only this line changes, the rest will work anywhere.
# Jupyter
await main()
# Otherwise
asyncio.run(main())