Search code examples
pythontelegrampython-telegram-bot

Proper way to make ConversationHandler with both Buttons & Messages handling


I'm building a bot that should handle buttons and messages, this is an example that works:

INTRO, GUEST_OR_USER, USERNAME, GUEST = range(4)


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    keyboard = [
        [InlineKeyboardButton("YES SIR!", callback_data='user')],
        [InlineKeyboardButton("no", callback_data='guest')],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    await update.message.reply_text("Are you a Stack Overflow user?", reply_markup=reply_markup)
    return GUEST_OR_USER


async def guest_or_user_choice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    query = update.callback_query
    await query.answer()
    if query.data == 'user':
        await context.bot.send_message(chat_id=update.effective_chat.id,
                                       text="Cool! What's your username?")
        return USERNAME
    await context.bot.send_message(chat_id=update.effective_chat.id,
                                   text="Oh! Why not?")
    return GUEST


async def username_entered(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text("👍")
    return


async def guest_conv(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text("That's a shame!")
    return

if __name__ == '__main__':
    application = ApplicationBuilder().token(TOKEN).build()
    start_handler = CommandHandler('start', start)
    application.add_handler(start_handler)
    conv_handler = ConversationHandler(
        entry_points=[CallbackQueryHandler(guest_or_user_choice)],
        states={
            USERNAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, username_entered)],
            GUEST: [MessageHandler(filters.TEXT & ~filters.COMMAND, guest_conv)]
        },
        fallbacks=[],
        allow_reentry=True
    )
    application.add_handler(conv_handler)
    application.run_polling()

But even such a simple flow shows warnings like

PTBUserWarning: If 'per_message=False', 'CallbackQueryHandler' will not be tracked for every message

According to those, ConversationHandler should be something like:

conv_handler = ConversationHandler(
        entry_points=[CallbackQueryHandler(guest_or_user_choice)],
        states={
            USERNAME: [CallbackQueryHandler(username_entered)],
            GUEST: [CallbackQueryHandler(guest_conv)]
        },
        fallbacks=[],
        allow_reentry=True,
        per_message=True
    )

But this doesn't work, username_entered | guest_conv are never started. Is there a way to make it work without warnings? How to use CallbackQueryHandler for handling the user text input? Thanks a lot!


Solution

  • It's a warning, not an error. Seeing a warning doesn't necessarily mean that you have to change something. We even have an FAQ entry for this specific case.


    Disclaimer: I'm currently the maintainer of python-telegram-bot.