python-telegram-bot/examples/arbitrarycallbackdatabot.py

120 lines
4.3 KiB
Python
Raw Normal View History

2021-06-06 11:48:48 +02:00
#!/usr/bin/env python
# pylint: disable=unused-argument
2021-06-06 11:48:48 +02:00
# This program is dedicated to the public domain under the CC0 license.
"""This example showcases how PTBs "arbitrary callback data" feature can be used.
For detailed info on arbitrary callback data, see the wiki page at
https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data
Note:
To use arbitrary callback data, you must install PTB via
`pip install "python-telegram-bot[callback-data]"`
2021-06-06 11:48:48 +02:00
"""
import logging
from typing import cast
2021-06-06 11:48:48 +02:00
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (
Application,
2021-06-06 11:48:48 +02:00
CallbackQueryHandler,
CommandHandler,
ContextTypes,
2021-06-06 11:48:48 +02:00
InvalidCallbackData,
PicklePersistence,
)
# Enable logging
2021-06-06 11:48:48 +02:00
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
2021-06-06 11:48:48 +02:00
)
# set higher logging level for httpx to avoid all GET and POST requests being logged
logging.getLogger("httpx").setLevel(logging.WARNING)
2021-06-06 11:48:48 +02:00
logger = logging.getLogger(__name__)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
2021-06-06 11:48:48 +02:00
"""Sends a message with 5 inline buttons attached."""
number_list: list[int] = []
await update.message.reply_text("Please choose:", reply_markup=build_keyboard(number_list))
2021-06-06 11:48:48 +02:00
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
2021-06-06 11:48:48 +02:00
"""Displays info on how to use the bot."""
await update.message.reply_text(
2021-06-06 11:48:48 +02:00
"Use /start to test this bot. Use /clear to clear the stored data so that you can see "
"what happens, if the button data is not available. "
)
async def clear(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
2021-06-06 11:48:48 +02:00
"""Clears the callback data cache"""
context.bot.callback_data_cache.clear_callback_data()
context.bot.callback_data_cache.clear_callback_queries()
await update.effective_message.reply_text("All clear!")
2021-06-06 11:48:48 +02:00
def build_keyboard(current_list: list[int]) -> InlineKeyboardMarkup:
2021-06-06 11:48:48 +02:00
"""Helper function to build the next inline keyboard."""
return InlineKeyboardMarkup.from_column(
[InlineKeyboardButton(str(i), callback_data=(i, current_list)) for i in range(1, 6)]
)
async def list_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
2021-06-06 11:48:48 +02:00
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
await query.answer()
2021-06-06 11:48:48 +02:00
# Get the data from the callback_data.
# If you're using a type checker like MyPy, you'll have to use typing.cast
# to make the checker get the expected type of the callback_data
number, number_list = cast(tuple[int, list[int]], query.data)
2021-06-06 11:48:48 +02:00
# append the number to the list
number_list.append(number)
await query.edit_message_text(
2021-06-06 11:48:48 +02:00
text=f"So far you've selected {number_list}. Choose the next item:",
reply_markup=build_keyboard(number_list),
)
# we can delete the data stored for the query, because we've replaced the buttons
context.drop_callback_data(query)
async def handle_invalid_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
2021-06-06 11:48:48 +02:00
"""Informs the user that the button is no longer available."""
await update.callback_query.answer()
await update.effective_message.edit_text(
"Sorry, I could not process this button click 😕 Please send /start to get a new keyboard."
2021-06-06 11:48:48 +02:00
)
def main() -> None:
"""Run the bot."""
# We use persistence to demonstrate how buttons can still work after the bot was restarted
persistence = PicklePersistence(filepath="arbitrarycallbackdatabot")
# Create the Application and pass it your bot's token.
application = (
Application.builder()
.token("TOKEN")
.persistence(persistence)
.arbitrary_callback_data(True)
.build()
)
2021-06-06 11:48:48 +02:00
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
application.add_handler(CommandHandler("clear", clear))
application.add_handler(
2021-06-06 11:48:48 +02:00
CallbackQueryHandler(handle_invalid_button, pattern=InvalidCallbackData)
)
application.add_handler(CallbackQueryHandler(list_button))
2021-06-06 11:48:48 +02:00
# Run the bot until the user presses Ctrl-C
application.run_polling(allowed_updates=Update.ALL_TYPES)
2021-06-06 11:48:48 +02:00
if __name__ == "__main__":
2021-06-06 11:48:48 +02:00
main()