6

I'm trying to send an InlineKeyboardHandler every x second. for that purpose I used updater.job_queue.run_repeating but it acts weird.

The keyboard doesn't work unless I have another interaction with the bot first. I've written a simple piece of code that you can test.

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, ConversationHandler, CallbackContext, CallbackQueryHandler

user_id = '*********'
tlg_token = '******************************'
SELECTING_COMMAND=1
keyboard = [[InlineKeyboardButton('Button: Print Clicked', callback_data=1)],]
reply_markup = InlineKeyboardMarkup(keyboard)

def menu(update: Update, context: CallbackContext) -> int:
    update.message.reply_text('sent by command button:', reply_markup=reply_markup)
    return SELECTING_COMMAND

def InlineKeyboardHandler(update: Update, _: CallbackContext) -> None:
    print('clicked')
    return 1

def cancel(update: Update, context: CallbackContext) -> int:
    return ConversationHandler.END    

updater = Updater(tlg_token, use_context=True)
dispatcher = updater.dispatcher

conv_handler = ConversationHandler(
    entry_points=[CommandHandler('request_button', menu)],
    states={
        SELECTING_COMMAND: [CallbackQueryHandler(InlineKeyboardHandler)],
    },
    fallbacks=[CommandHandler('cancel', cancel)],
)
dispatcher.add_handler(conv_handler)

j = updater.job_queue

def talker(update):    
    update.bot.sendMessage(chat_id=user_id, text='sent by talker:', reply_markup=reply_markup)
        
j.run_repeating(talker, interval=10, first=0)
updater.start_polling()
updater.bot.sendMessage(chat_id=user_id, text='/request_button')
updater.idle()

I expect I can see 'clicked' printed after clicking on the button but it's not going to work unless you click on the /request_button first. Why? And how can I fix it?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
parvij
  • 1,381
  • 3
  • 15
  • 31
  • 1
    You mean you have to click `/request_button` *once* before any of the inline keyboard buttons are handled? If so, that's expected since without sending `/request_button` the conversation has not started and thus the `SELECTING_COMMAND: [CallbackQueryHandler(InlineKeyboardHandler)]` handler will never be invoked since the conversation is not in the `SELECTING_COMMAND` state (by the way, you might want to return `SELECTING_COMMAND` from `InlineKeyboardHandler`?). – a_guest Sep 07 '21 at 08:10
  • I mean when the state is in SELECTING_COMMAND, furthermore there is no difference between returning 1 or SELECTING_COMMAND – parvij Sep 07 '21 at 22:04
  • Well that doesn't answer my first question which intends to clarify the problem. – a_guest Sep 08 '21 at 19:50
  • yes, I have to click once then the button works. At first, I didn't understand your question correctly. – parvij Sep 08 '21 at 21:56

1 Answers1

2

The problem with your code as a_guest mentioned in the comments, is that InlineKeyboardHandler will start to work only after calling request_button command.

Here's a working version where InlineKeyboardHandler is registered independently:

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, ConversationHandler, CallbackContext, CallbackQueryHandler

#################################
user_id = 0
tlg_token = 'bot_token'
SELECTING_COMMAND = 1
keyboard = [[InlineKeyboardButton('Button: Print Clicked', callback_data=1)], ]
reply_markup = InlineKeyboardMarkup(keyboard)


#################################

def menu(update: Update, context: CallbackContext) -> int:
    update.message.reply_text('sent by command button:', reply_markup=reply_markup)
    return SELECTING_COMMAND


def InlineKeyboardHandler(update: Update, _: CallbackContext) -> None:
    print('clicked')
    return 1


def cancel(update: Update, context: CallbackContext) -> int:
    return ConversationHandler.END


updater = Updater(tlg_token, use_context=True)
dispatcher = updater.dispatcher
updater.dispatcher.add_handler(CallbackQueryHandler(InlineKeyboardHandler))
updater.dispatcher.add_handler(CommandHandler('request_button', menu))
j = updater.job_queue


def talker(update):
    update.bot.sendMessage(chat_id=user_id, text='sent by talker:', reply_markup=reply_markup)


j.run_repeating(talker, interval=10, first=0)
updater.start_polling()
updater.bot.sendMessage(chat_id=user_id, text='/request_button')
updater.idle()

The other solution for the problem is what OP himself mentioned in the comments where you add the CallbackQueryHandler as an entry point:

entry_points=[CommandHandler('request_button', menu),                   CallbackQueryHandler(InlineKeyboardHandler)]
Ali Padida
  • 1,763
  • 1
  • 16
  • 34
  • It works but you change the main part of the code. Since InlineKeyboardHander can't change the status anymore. However, I understand what happens. So, if you add the InlineKeyboardHander to the entry_points, it would be a correct answer. – parvij Sep 08 '21 at 21:51
  • What do you mean by "status"? – Ali Padida Sep 09 '21 at 04:08
  • I've used ConversationHandler because I need status but you removed it. – parvij Sep 09 '21 at 17:34
  • What is the use of status here? Because I think you can handle it in other ways. I don't see what status does here, elaborate that and I'll give you a workaround – Ali Padida Sep 10 '21 at 21:01
  • 1
    in this example nothing, but in my program I need it. After your answer, I found if I change entry_points line in this way it works fine: `entry_points=[CommandHandler('request_button', menu), CallbackQueryHandler(InlineKeyboardHandler)],` then I have status and it works fine as well. I've accepted your answer but I suggest you to change it in this way. – parvij Sep 12 '21 at 16:34