2021-06-06 11:48:48 +02:00
|
|
|
#!/usr/bin/env python
|
2022-05-05 09:27:54 +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
|
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,
|
|
|
|
CallbackContext,
|
2021-06-06 11:48:48 +02:00
|
|
|
CallbackQueryHandler,
|
2022-05-05 09:27:54 +02:00
|
|
|
CommandHandler,
|
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(
|
|
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
|
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2022-04-24 12:38:09 +02:00
|
|
|
async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None:
|
2021-06-06 11:48:48 +02:00
|
|
|
"""Sends a message with 5 inline buttons attached."""
|
|
|
|
number_list: List[int] = []
|
2022-04-24 12:38:09 +02:00
|
|
|
await update.message.reply_text('Please choose:', reply_markup=build_keyboard(number_list))
|
2021-06-06 11:48:48 +02:00
|
|
|
|
|
|
|
|
2022-04-24 12:38:09 +02:00
|
|
|
async def help_command(update: Update, context: CallbackContext.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-04-24 12:38:09 +02:00
|
|
|
async def clear(update: Update, context: CallbackContext.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-04-24 12:38:09 +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-04-24 12:38:09 +02:00
|
|
|
async def list_button(update: Update, context: CallbackContext.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-04-24 12:38:09 +02:00
|
|
|
async def handle_invalid_button(update: Update, context: CallbackContext.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(
|
2021-06-06 11:48:48 +02:00
|
|
|
'Sorry, I could not process this button click 😕 Please send /start to get a new keyboard.'
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
|
|
|
"""Run the bot."""
|
|
|
|
# We use persistence to demonstrate how buttons can still work after the bot was restarted
|
2021-10-05 19:50:11 +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-04-24 12:38:09 +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)
|
|
|
|
)
|
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
|
|
|
|
application.run_polling()
|
2021-06-06 11:48:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|