2021-06-06 11:48:48 +02:00
|
|
|
#!/usr/bin/env python
|
2023-09-09 23:12:30 +02:00
|
|
|
# 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.
|
|
|
|
|
2022-01-21 16:51:03 +01:00
|
|
|
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
|
2022-12-02 12:08:11 +01:00
|
|
|
|
|
|
|
Note:
|
|
|
|
To use arbitrary callback data, you must install PTB via
|
2023-06-29 07:46:00 +02:00
|
|
|
`pip install "python-telegram-bot[callback-data]"`
|
2021-06-06 11:48:48 +02:00
|
|
|
"""
|
|
|
|
import logging
|
|
|
|
from typing import List, Tuple, cast
|
|
|
|
|
|
|
|
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
|
|
|
from telegram.ext import (
|
2022-05-05 09:27:54 +02:00
|
|
|
Application,
|
2021-06-06 11:48:48 +02:00
|
|
|
CallbackQueryHandler,
|
2022-05-05 09:27:54 +02:00
|
|
|
CommandHandler,
|
2022-05-12 19:36:25 +02:00
|
|
|
ContextTypes,
|
2021-06-06 11:48:48 +02:00
|
|
|
InvalidCallbackData,
|
|
|
|
PicklePersistence,
|
|
|
|
)
|
|
|
|
|
2021-10-09 13:56:50 +02:00
|
|
|
# Enable logging
|
2021-06-06 11:48:48 +02:00
|
|
|
logging.basicConfig(
|
2022-05-05 17:40:22 +02:00
|
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
|
2021-06-06 11:48:48 +02:00
|
|
|
)
|
2023-06-07 22:32:04 +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__)
|
|
|
|
|
|
|
|
|
2022-05-12 19:36:25 +02:00
|
|
|
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] = []
|
2022-05-05 17:40:22 +02:00
|
|
|
await update.message.reply_text("Please choose:", reply_markup=build_keyboard(number_list))
|
2021-06-06 11:48:48 +02:00
|
|
|
|
|
|
|
|
2022-05-12 19:36:25 +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."""
|
2022-04-24 12:38:09 +02:00
|
|
|
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. "
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-05-12 19:36:25 +02:00
|
|
|
async def clear(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
2021-06-06 11:48:48 +02:00
|
|
|
"""Clears the callback data cache"""
|
2021-10-09 13:56:50 +02:00
|
|
|
context.bot.callback_data_cache.clear_callback_data()
|
|
|
|
context.bot.callback_data_cache.clear_callback_queries()
|
2022-05-05 17:40:22 +02:00
|
|
|
await update.effective_message.reply_text("All clear!")
|
2021-06-06 11:48:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
def build_keyboard(current_list: List[int]) -> InlineKeyboardMarkup:
|
|
|
|
"""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)]
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-05-12 19:36:25 +02:00
|
|
|
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
|
2022-04-24 12:38:09 +02:00
|
|
|
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)
|
|
|
|
# append the number to the list
|
|
|
|
number_list.append(number)
|
|
|
|
|
2022-04-24 12:38:09 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2022-05-12 19:36:25 +02:00
|
|
|
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."""
|
2022-04-24 12:38:09 +02:00
|
|
|
await update.callback_query.answer()
|
|
|
|
await update.effective_message.edit_text(
|
2022-05-05 17:40:22 +02:00
|
|
|
"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
|
2022-05-05 17:40:22 +02:00
|
|
|
persistence = PicklePersistence(filepath="arbitrarycallbackdatabot")
|
2022-04-24 12:38:09 +02:00
|
|
|
# Create the Application and pass it your bot's token.
|
|
|
|
application = (
|
|
|
|
Application.builder()
|
2021-10-09 13:56:50 +02:00
|
|
|
.token("TOKEN")
|
|
|
|
.persistence(persistence)
|
|
|
|
.arbitrary_callback_data(True)
|
|
|
|
.build()
|
|
|
|
)
|
2021-06-06 11:48:48 +02:00
|
|
|
|
2022-05-05 17:40:22 +02:00
|
|
|
application.add_handler(CommandHandler("start", start))
|
|
|
|
application.add_handler(CommandHandler("help", help_command))
|
|
|
|
application.add_handler(CommandHandler("clear", clear))
|
2022-04-24 12:38:09 +02:00
|
|
|
application.add_handler(
|
2021-06-06 11:48:48 +02:00
|
|
|
CallbackQueryHandler(handle_invalid_button, pattern=InvalidCallbackData)
|
|
|
|
)
|
2022-04-24 12:38:09 +02:00
|
|
|
application.add_handler(CallbackQueryHandler(list_button))
|
2021-06-06 11:48:48 +02:00
|
|
|
|
2022-04-24 12:38:09 +02:00
|
|
|
# Run the bot until the user presses Ctrl-C
|
2023-06-04 17:11:58 +02:00
|
|
|
application.run_polling(allowed_updates=Update.ALL_TYPES)
|
2021-06-06 11:48:48 +02:00
|
|
|
|
|
|
|
|
2022-05-05 17:40:22 +02:00
|
|
|
if __name__ == "__main__":
|
2021-06-06 11:48:48 +02:00
|
|
|
main()
|