Moisa
Moisa

Reputation: 13

Telethon async function to tkinter button

I have the this async function below and basically I wanna place It into the command of a button using tkinter.

async def main():
    await client.send_message('username', 'message')

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

In message I wanna put the variable cpf of my code, but I don't know exactly how should place It all together. I'm very new with python, so sorry for anything wrong...

The code above is how I'm trying to do it, but It's running the function just when I run the code, and not when I press the Button. I'm getting ValueError: The message cannot be empty unless a file is provided

from telethon import TelegramClient, events, sync
from tkinter import *

api_id = xxxxx
api_hash = 'xxxxxx'

client = TelegramClient('session_name', api_id, api_hash)
client.start()

root = Tk()

canvas = Canvas(root)
canvas.pack()

code_entry = Entry(canvas)
code_entry.pack()

async def main():
    cpf = code_entry.get()
    await client.send_message('ConsignadoBot', cpf)

with client:
    client.loop.run_until_complete(main)

search_btn = Button(canvas, text='Consultar', command=main)
search_btn.pack()

root.mainloop()

Upvotes: 1

Views: 1912

Answers (1)

Lonami
Lonami

Reputation: 7096

Your code produces a completely different error before producing the one you claim to have.

with client:
    client.loop.run_until_complete(main)

This line fails, because in loop.run_until_complete(), "an asyncio.Future, a coroutine or an awaitable is required":

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 558, in run_until_complete
    future = tasks.ensure_future(future, loop=self)
  File "/usr/local/lib/python3.7/asyncio/tasks.py", line 619, in ensure_future
    raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required

The correct code would be:

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

Now, it will error with "empty message" because it's executing before the user enters anything.


This code:

root.mainloop()

Is blocking. Telethon is an asyncio library, which means the event loop won't be running unless you do something else, which means Telethon won't be able to make any progress.

This can be solved by making it async:

async def main(interval=0.05):
    try:
        while True:
            # We want to update the application but get back
            # to asyncio's event loop. For this we sleep a
            # short time so the event loop can run.
            #
            # https://www.reddit.com/r/Python/comments/33ecpl
            root.update()
            await asyncio.sleep(interval)
    except KeyboardInterrupt:
        pass
    except tkinter.TclError as e:
        if 'application has been destroyed' not in e.args[0]:
            raise
    finally:
        await client.disconnect()

client.loop.run_until_complete(main())

For a more carefully designed async-friendly tkinter app, see Telethon's gui.py example.

Upvotes: 2

Related Questions