0

My program is supposed to reply Telegram messages the user's account receives with a user-defined text. This text can be changed by sending a message to a telegram bot. For the bot, I've been using PyTelegramBotAPI, and for sending messages from the user's account I've been using Telethon. I can run the bot by calling bot.polling() and it works fine. The Telethon Client also works fine separately, It has methods like:

async def run():
    self.add_event_handler(self.message_handler, events.NewMessage)

    while True:
        #(Every Second the while is supposed to be checked)
        if(condition):
            do_something()

async def message_handler(self, event):
     do_another_thing()

and to start running the client I would just:

loop = asyncio.get_event_loop()

loop.run_until_complete(client.run())

But I can't make them run simultaneously.

I've tried:

asyncio.get_event_loop().run_until_complete(asyncio.gather(
    bot.bot.polling(none_stop=True, interval=0.1, timeout=15),
    client.run()
))

to run both of them simultaneously, but this only runs the bot.

I've also tried:

executor = ProcessPoolExecutor(2)
loop = asyncio.get_event_loop()
boo = asyncio.create_task(loop.run_in_executor(executor, bot.bot.polling(none_stop=True, interval=0.5, timeout=15)))
baa = asyncio.create_task(loop.run_in_executor(executor, client.run()))

but it doesn't work either.

could you please tell me how to run the bot and client at the same time?

Danial
  • 362
  • 4
  • 18
  • 1
    Do you not have any `await` calls in your `while True` loop in the actual code? Because if you don't, that method will never yield control back to the event loop, which will prevent the polling coroutine from ever running. – dano Jun 16 '20 at 17:27
  • It seems you want to run some task periodically. Does this answer your question? [How can I periodically execute a function with asyncio?](https://stackoverflow.com/questions/37512182/how-can-i-periodically-execute-a-function-with-asyncio) – Roman-Stop RU aggression in UA Jun 16 '20 at 17:28
  • Yes, i do have ```await``` in the ```while True``` in the actual code. Apologies for missing it. – Danial Jun 16 '20 at 17:31
  • I think you'll need to provide sample code that actually reproduces the problem you're seeing for someone to help. – dano Jun 16 '20 at 17:38
  • *> Every Second the while is supposed to be checked*. Perhaps in your case you could do better, maybe instead of every second you want every time the handler is called? In which case you could just call other functions within the handler. – Lonami Jun 16 '20 at 18:26
  • If you don't have a lot of code, replacing the synchronous library with an asynchronous one (like Telethon itself) may make things easier. Telethon is capable of running bots too. – Lonami Jun 16 '20 at 18:27

3 Answers3

1

This worked for me using the asyncronous mode for python-telegram-bot'2 handlers:

from telegram import Bot, Chat
from telegram.ext import Updater, CommandHandler

telegram_bot = Bot(token=token)
telegram_chat = Chat(id=test_group_chat_id, type='group', bot=telegram_bot)
updater = Updater(bot=telegram_bot, use_context=True)
dp = updater.dispatcher

async def main_loop():
    while condition_1:
        # Do stuff
        if condition_2:
            telegram_chat.send_message('Something happened')
        pass

def callback_function(update, context):
    telegram_chat.send_message('Test')

async def main_telegram():
    dp.add_handler(CommandHandler("command", callback_function, run_async=True))
    updater.start_polling()

if __name__ == '__main__':
    
   
    loop = asyncio.get_event_loop()
    try:
        loop.create_task(main_loop(), name="Main loop")
        loop.create_task(main_telegram(), name="Telegram listen task")
        loop.run_forever()
    finally:
        log.info("Shutting down ...")
        log.info("Updater running " + str(updater.running))
        updater.stop()

        pending = asyncio.all_tasks(loop=loop)
        for task in pending:
            task.cancel()
    
        loop.stop()
        loop.close()
gilgorio
  • 528
  • 6
  • 10
0

You should put this code at the end of your script.

loop = asyncio.get_event_loop()
loop.create_task(function1())
loop.create_task(function2())
loop.run_forever()
TheKill-996
  • 953
  • 5
  • 10
0

The problem, as mentioned in comments by Lonami, was that the PyTelegramBotAPI is not an asynchronous library, therefor when adding it to asyncio event loop, it never gave control back to other tasks, (client.run() method in my case). I switched to aiogram, which is an asynchronous library, and the problem was solved.

P.S. PyTelegramBotAPI offers an asynchronous module, but I was't able to make it work. Openning an issue on its GitHub page didn't help either.

Danial
  • 362
  • 4
  • 18