Search code examples
pythontelegramtelethon

Telegram bot function with event handler not executing before program ends; how to fix and print results properly?


I made a function to test my telegram bot, it sends a request message to the chat bot to change some value in the database for this user. The problem is that all the code is played before the code of the function "first_handler" with the decorator (due to which the "print (flag)" writes "false" ). Even if the reply message from the bot appears before the execution of the code reaches "print", then the function with the decorator does not trigger before the "print". Due to the same problem, I have to use "client.run_until_disconnected()" because without it, the bot's message handler doesn't work at all, and because of this method, I have to stop the program execution manually, since I don't need to disconnect the client. My scuffed code:

from telethon import TelegramClient, events, sync
import conf_tests as ct

import time

client = TelegramClient('TestClient', ct.api_id, ct.api_hash, system_version = ct.sys_ver)

def test_first():
    flag = False

    @client.on(events.NewMessage(chats=ct.bot_name))
    async def fist_handler(event):
        global flag, f2

        if (event.sender_id == ct.bot_id) and ('Enter new value' in event.raw_text):
            global f1
            f1 = True
            await client.send_message(ct.bot_name, 'Value')

        if (event.sender_id == ct.bot_id) and ('Value successfully changed!' in event.raw_text):
            f2 = True
            if f1 and f2:
                flag = True
    
    client.start()        
    client.send_message(ct.bot_name, ct.change_group_btn)
    
    client.run_until_disconnected() 
    print (flag)

test_first()       
  • Bonus problem, which is more related to my lack of knowledge of python: I cannot set f1 and f2 (no problem with f2 in this particular case) to False before the first if, because otherwise I will not be able to declare f1 a global variable to be able to change it in if below. If the check passes, there are no problems, but if it does not pass, it will give an error that the variables have not been assigned a value.

Tried to use this, but nothing has changed, but it shouldn't i guess, because in fact I just call the function, just in a different place.

with client:
   client.loop.run_until_complete(test_first())

And, to be honest, I don’t remember in what form I added these lines, cos now, it seems, they will not work due to asynchrony.


Solution

  • I think the main issue is that the test_first function should be asynchronous. The following code should help you fix your issues.

    from telethon import TelegramClient, events
    import conf_tests as ct
    
    import asyncio # Recommended to be used by the telethon package
    
    client = TelegramClient('TestClient', ct.api_id, ct.api_hash, system_version=ct.sys_ver)
    
    async def test_first():
        flag = False
        f1 = False
        f2 = False
    
        @client.on(events.NewMessage(chats=ct.bot_name))
        async def first_handler(event):
            nonlocal flag, f1, f2 # lets you use the flag, f1, and f2 variables that were defined earlier but doesnt make them global
            if event.sender_id == ct.bot_id:
                if 'Enter new value' in event.raw_text:
                    f1 = True
                    await client.send_message(ct.bot_name, 'Value')
                elif 'Value successfully changed!' in event.raw_text:
                    f2 = True
                    if f1 and f2:
                        flag = True
                        client.disconnect()
    
        async with client: # properly connect and disconnect the client
            await client.send_message(ct.bot_name, ct.change_group_btn)
            await client.run_until_disconnected()
        
        print(flag)
    
    asyncio.run(test_first()) # Creates a new asyncio event loop asynchronously running "test_first"
    

    As you can see, it uses the asyncio package that is recommended in the Telethon Documentation. It sets the flag, f1, and f2 variables as nonlocal so they can be used outside the first_handler function. It also makes the test_first function async and awaits on the client.

    I left comments in the code explaining what some of the changes are for. Let me know if this was helpful or not in the comments. You can also check out the documentation using the link above if you have not done so already.