0

I'm using python-telegram-bot library
I'm trying to create telegram bot that works like anki. It add word and translation from user to database and later ask user to write translation of the word. I'm trying to send the user words for which he should write a translation. I have problems with this.
In main.py I can't run asynchronously application.run_polling() that run telegram bot and send_messages.setup(application.bot) from send_messages.py that run while true loop for sending words.
I was trying different ways to solve my problem like asyncio event loop or asyncio.create_task() but that don't work.
The code below only runs send_messages.setup(application.bot) with while true loop and prevents application.run_polling() from executing

main.py

import logging
import os

import telegram.ext as tg_ext

from bot import handlers, send_messages


TOKEN = os.getenv('TOKEN')

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO,
)
logger = logging.getLogger(__name__)


def main() -> None:
    application = tg_ext.ApplicationBuilder().token(TOKEN).build()

    handlers.setup_handlers(application)
    send_messages.setup(application.bot)

    application.run_polling()


if __name__ == '__main__':
    main()

send_messages.py

import telegram.ext as tg_ext

import asyncio

from database import db


async def send_words(bot: tg_ext.Application.bot) -> None:
    """Sends words to the user to write a translation."""
    while True:
        words = db.get_words_to_remember()

        for word in words:
            word_eng = word[0].word
            user = word[1]

            await bot.send_message(
                user.chat_id, f'Enter translation: {word_eng}')
            db.change_is_waiting(user)

        await asyncio.sleep(60)


def setup(bot: tg_ext.Application.bot) -> None:
    asyncio.run(send_words(bot))
  • maybe you should use [telegram.ext.JobQueue](https://github.com/python-telegram-bot/v13.x-wiki/wiki/Extensions-%E2%80%93-JobQueue) to run function periodically without using `while`-loop and without `sleep()` – furas Sep 03 '22 at 01:28
  • if you resolved problem then you could show your code as answer - and later you may mark you answer as accepted. This will be readable information that problem was resolved. – furas Sep 03 '22 at 12:38

3 Answers3

3

It could be solved by telegram.ext.JobQueue that allow to perform tasks periodically with a running telegram bot
Corrected code:
main.py

import logging
import os

import telegram.ext as tg_ext

from bot import handlers, send_messages

TOKEN = os.getenv('TOKEN')

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO,
)
logger = logging.getLogger(__name__)


def main() -> None:
    application = tg_ext.ApplicationBuilder().token(TOKEN).build()
    job_queue = application.job_queue

    job_queue.run_repeating(send_messages.setup, interval=60, first=10)
    handlers.setup_handlers(application)

    application.run_polling()


if __name__ == '__main__':
    main()

send_messages.py

import telegram.ext as tg_ext

from database import db


async def send_words(bot: tg_ext.Application.bot) -> None:
    """Sends words to the user to write a translation."""
    words = db.get_words_to_remember()

    for word in words:
        word_eng = word[0].word
        user = word[1]

        await bot.send_message(user.chat_id, f'Enter translation: {word_eng}')
        db.change_is_waiting(user)


async def setup(context: tg_ext.CallbackContext) -> None:
    await send_words(context.bot)
0

It is not possible to run a function which is not async concurrently in the same thread. You need to either use a different thread to run application.run_polling() or use a ThreadPoolExecutor, which in turn will use a different thread under the hood.

See https://docs.python.org/3/library/threading.html for python threading docs and examples.

See https://stackoverflow.com/a/51051980/4542928 for an example of ThreadPoolExecutor.

AndresR
  • 596
  • 3
  • 17
0

IMO the overall design looks like it could be improved. Specifically I'm thinking of ConversationHandler - see also the example. This should allow you to send words to the user, wait for the translation, then send the next word etc.

CallMeStag
  • 5,467
  • 1
  • 7
  • 22