InlineKeyboard Example - python-telegram-bot/python-telegram-bot GitHub Wiki

Introduction

Hey, this wiki page will walk you through the inline keyboard example found here. We will start with how python starts with the example, then follow through the code in the same way we expect updates from the user would go through it. Let's do it.

Disclaimer: We will conveniently ignore the imports.

Startup

if __name__ == '__main__':
    main()

Lines 68 to 69 tell python that after starting the script, it's supposed to call the main function

main

application = Application.builder().token("TOKEN").build()

The first line in the main function builds an application instance from the Application class. The function calls lined up after another means that the calls happen on the return of the previous call. So .builder() is called on Application, .token("TOKEN") on the return of .builder(), .build() on whatever .token("TOKEN") returns. If you check the docs, you will find that builder returns an ApplicationBuilder instance. So looking there for token, we find that it also returns an (updated) ApplicationBuilder instance, which is the same for almost every method on that page. This allows this chaining of function calls, since all the function are defined inside the ApplicationBuilder and it is always returned. Finally, the .build() builds and then returns the application instance we expect.

application.add_handler(CommandHandler("start", start))
application.add_handler(CallbackQueryHandler(button))
application.add_handler(CommandHandler("help", help_command))

Line 60 to 62 registers our three handlers. The first handler is a CommandHandler. Whenever a user sends a /start command to the bot, the function start is called. Same situation with the third handler: Whenever a user sends the /help command, help_command gets called.

The second handler is a CallbackQueryHandler. A Callbackquery is what Telegram sends to our bot when a user presses an InlineButton. Every press of a button gets sent to the button handler.

application.run_polling()

Line 65 tells the PTB library to start the bot using polling, which means that the library will continuously make a request to the telegram servers and get new updates from there, if they exists.

Let's start our way through the handlers in the same way we would expect a user to go through it. This means we begin with the start handler:

start

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:

In line 24 we define a function called start. It is an async function and it takes the two arguments update (instance of an Update) and context (instance of a CallbackContext). The context is the default context type, since we didn't change anything with it. If you want to see how that works, checkout the ContextType bot example. The -> None indicates to a type checker that this function returns nothing.

keyboard = [
    [
        InlineKeyboardButton("Option 1", callback_data='1'),
        InlineKeyboardButton("Option 2", callback_data='2'),
    ],
    [InlineKeyboardButton("Option 3", callback_data='3')],
]

Line 26 to 32 a variable called keyboard is defined. It is a list of lists, representing a 2D-Matrix. Every "parent" list is a row in the actual inline keyboard (so [1], [2](/python-telegram-bot/python-telegram-bot/wiki/1],-[2) would be two rows), every entry inside an parent list is a column. So this keyboard will have two rows, Option 1 and Option 2 will be in the first; Option 3 in the second one.

reply_markup = InlineKeyboardMarkup(keyboard)

Line 34 turns our list into an actual Inline Keyboard that we can pass along with our message.

await update.message.reply_text('Please choose:', reply_markup=reply_markup)

In line 36 we reply to the update message with a text (hence reply_text) and pass the keyboard along in the reply_markup argument. The await tells the program to stop and wait for the function call to finish. async and await are both fundamentals of asyncio programming in python, explaining this further is outside of this example explainer. If you are curious, feel free to search for it, otherwise just accept these keywords as they are.

Now we expect people to press one of the provided buttons, so let's jump to the button callback

button

async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:

Line 39 defines a function called button. It takes the two arguments update and context and returns nothing. Basically the same as start.

query = update.callback_query

Line 41 defines query as a shortcut to access the provided CallbackQuery. This is the part of the update which has all the information in it, remember, it gets generated/send to the bot once a user presses a button.

await query.answer()

Line 45 here we answer the CallbackQuery. We use a convenient shortcut PTB provides. It takes care of calling the actual function and passing all the required parameters to it. If you check out the function, you see that you can pass a text argument to it, which will be displayed in a little pop-up on the client end, and if you pass show_alert on top of it, the user has to dismiss the pop-up. Not useful for this example, so we just pass it without these optional arguments.

await query.edit_message_text(text=f"Selected option: {query.data}")

Line 47 edits the message where CallbackQuery originates from with the text where we tell the user which option we picked. We insert query.data into the string, which is the data we defined in the keyboard, so the number 1, 2 or 3. Since we don't pass the inline keyboard along again, it will disappear.

help

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text("Use /start to test this bot.")

Line 50 to 52 is a simple callback. Here we reply to the /help command with the provided text: They should use /start to use this bot.

error

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

Line 18 to 21 are the only lines of the code we haven't covered yet. Here we set up the logging module to have the format we want, and we define logger in case we want to use it later. More docs regarding logging can be found here


This section of the wiki is currently in development, feedback is greatly appreciated. Ping one of the admins in our telegram group to anything you want to tell us.