python-telegram-bot中InlineKeyboard点击后CallbackQueryHandler未触发
使用python-telegram-bot开发Telegram机器人时,添加InlineKeyboard后,点击任意按钮都无法触发关联的button()回调处理函数。
相关代码如下:
from telegram import * from telegram.ext import * print('bot executed') token = <BOT_TOKEN> async def send_message_in_channel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: global new_data await context.bot.send_message(chat_id=<CHANNEL_USERNAME>, text="new_data") async def message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: await context.bot.delete_message(update.effective_chat.id, message_id=update.message.id) async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: query = update.callback_query await query.answer() print('button reached') if query.data == 'True': print("choose yes") await send_message_in_channel(update, context) elif query.data == 'False': print("choose no") async def option(new_data) -> None: bot = Bot(token=token) options = [ [ InlineKeyboardButton('Yes, Post It', callback_data="True"), InlineKeyboardButton('No, Don\'t Post', callback_data="False") ], ] reply_markup = InlineKeyboardMarkup(options) await bot.send_message(chat_id=<MY_OWN_CHAT_ID>, text=new_data, reply_markup=reply_markup, disable_web_page_preview=True) if __name__ == '__main__': new_data = '' application = ApplicationBuilder().token(token).build() application.add_handler(CallbackQueryHandler(button)) application.add_handler(MessageHandler( filters.TEXT & (~filters.COMMAND), message)) application.run_polling()
注:option()函数由外部传入new_data调用,此前通过CommandHandler从机器人内部调用时功能正常,但外部调用时无法获取update或context对象,修改button()的context类型也无法解决问题。
原因分析
问题核心在于外部调用option()时,使用了独立创建的Bot实例发送消息。当前运行的Application仅会处理自身管理的bot实例产生的更新,而你手动创建的Bot(token=token)与Application无关联,导致该消息的回调查询无法被CallbackQueryHandler捕获。
之前通过CommandHandler调用正常,是因为此时可以通过context.bot获取Application管理的bot实例,发送的消息回调能被正确路由到处理函数。
解决方案
提供两种可行的修复方式:
方式一:通过Application的bot实例发送消息
修改option()函数,接收application作为参数,使用其管理的bot对象发送消息,避免创建独立Bot实例:
async def option(new_data, application: Application) -> None: options = [ [ InlineKeyboardButton('Yes, Post It', callback_data="True"), InlineKeyboardButton('No, Don\'t Post', callback_data="False") ], ] reply_markup = InlineKeyboardMarkup(options) # 使用Application管理的bot发送消息 await application.bot.send_message(chat_id=<MY_OWN_CHAT_ID>, text=new_data, reply_markup=reply_markup, disable_web_page_preview=True)
外部调用时,直接传入启动后的application对象:
if __name__ == '__main__': new_data = '' application = ApplicationBuilder().token(token).build() application.add_handler(CallbackQueryHandler(button)) application.add_handler(MessageHandler( filters.TEXT & (~filters.COMMAND), message)) # 外部调用示例(需在异步上下文执行) import asyncio asyncio.create_task(option("测试内容", application)) application.run_polling()
方式二:利用Application的上下文池访问bot
如果外部调用无法直接传递application,可将application声明为全局变量,通过其上下文池获取bot实例:
# 声明全局application变量 application = None async def option(new_data) -> None: global application # 通过上下文池获取Application管理的bot async with application.bot: options = [ [ InlineKeyboardButton('Yes, Post It', callback_data="True"), InlineKeyboardButton('No, Don\'t Post', callback_data="False") ], ] reply_markup = InlineKeyboardMarkup(options) await application.bot.send_message(chat_id=<MY_OWN_CHAT_ID>, text=new_data, reply_markup=reply_markup, disable_web_page_preview=True) if __name__ == '__main__': new_data = '' global application application = ApplicationBuilder().token(token).build() application.add_handler(CallbackQueryHandler(button)) application.add_handler(MessageHandler( filters.TEXT & (~filters.COMMAND), message)) # 外部调用示例 import asyncio asyncio.create_task(option("测试内容")) application.run_polling()
内容的提问来源于stack exchange,提问作者CloverSalt
相关产品推荐
相关产品推荐

