nickoala / telepot

Python framework for Telegram Bot API
MIT License
2.43k stars 475 forks source link

Pressing button does not trigger callback query: on_close() called due to IdleTerminate #313

Open tesserata opened 6 years ago

tesserata commented 6 years ago

Hello!

I've tried to write a bot that should react to button pressing with some further actions. Part of the code is omitted below, but the problem is that on_callback_query method of DocumentsHandler is never called. I also tried to put all this just in one ChatHandler - UserHandler, but the problem persists.

class DocumentHandler(CallbackQueryOriginHandler):
    def __init__(self, *args, **kwargs):
        super(DocumentHandler, self).__init__(*args, **kwargs)
        self._store = None

    def on_callback_query(self, msg):
        print('in on_callback_query')
        query_id, from_id, query_data = glance(msg, flavor='callback_query')
        print('Callback Query:', query_id, from_id, query_data)
        query_call = getattr(self, '_%s' % query_data)
        query_call()
        self.sender.answerCallbackQuery(query_id, text=query_data, alert=True)

class UserHandler(ChatHandler):
    def __init__(self, seed_tuple, **kwargs):
        super(UserHandler, self).__init__(seed_tuple, **kwargs)

    def on_chat_message(self, msg):
        content_type, chat_type, chat_id = glance(msg)

        if content_type != 'text':
            return

        command = msg['text']
        print('Command received: %s' % command)

        if command == '/start':
            content_type, chat_type, chat_id = glance(msg)
            self._store = Storage(chat_id)
            self.sender.sendMessage('Hi! Type a command to begin')
        elif command == '/docs':
            keyboard = InlineKeyboardMarkup(inline_keyboard=[
                       [InlineKeyboardButton(text='New document', callback_data='doc_new'),
                       InlineKeyboardButton(text='Add to document', callback_data='doc_add')],
                       [
                        InlineKeyboardButton(text='Delete document', callback_data='doc_del'),
                        InlineKeyboardButton(text='List documents', callback_data='doc_list')
                       ],
                   ])
            self.sender.sendMessage('Choose a command', reply_markup=keyboard)

bot = DelegatorBot(token,[
                    pave_event_space()(
                        per_chat_id(), create_open, UserHandler, timeout=10),
                     pave_event_space()(
                         per_callback_query_origin(), create_open, DocumentHandler, timeout=10)
                    ])

MessageLoop(bot).run_as_thread()
print('Listening ...')

This way I got only 'Listening...' in the output

Another way I tried was

class UserHandler(ChatHandler):
    def __init__(self, seed_tuple, **kwargs):
        super(UserHandler, self).__init__(seed_tuple, **kwargs)

    def on_chat_message(self, msg):
        content_type, chat_type, chat_id = glance(msg)
        if content_type != 'text':
            return

        command = msg['text']
        print('Command received: %s' % command)

        if command == '/start':
            content_type, chat_type, chat_id = glance(msg)
            self._store = Storage(chat_id)
            self.sender.sendMessage('Hi! Type a command to begin')
        elif command == '/docs':
            keyboard = InlineKeyboardMarkup(inline_keyboard=[
                       [InlineKeyboardButton(text='New document', callback_data='doc_new'),
                       InlineKeyboardButton(text='Add to document', callback_data='doc_add')],
                       [
                        InlineKeyboardButton(text='Delete document', callback_data='doc_del'),
                        InlineKeyboardButton(text='List documents', callback_data='doc_list')
                       ],
                   ])
            self.sender.sendMessage('Choose a command', reply_markup=keyboard)

    def on_callback_query(self, msg):
        print('in on_callback_query')
        query_id, from_id, query_data = glance(msg, flavor='callback_query')
        print('Callback Query:', query_id, from_id, query_data)
        query_call = getattr(self, '_%s' % query_data)
        query_call()
        self.sender.answerCallbackQuery(query_id, text=query_data, alert=True)

bot = DelegatorBot(token,[
                    pave_event_space()(
                        per_chat_id(), create_open, UserHandler, timeout=10)
                    ])

MessageLoop(bot).run_as_thread()
print('Listening ...')

The output was the following:

Listening ...
Command received: /docs
ERROR:root:on_close() called due to IdleTerminate: 10

Any help would be appreciated! Thanks.

TanShengRong commented 6 years ago

increase your timeout = 10 to something bigger.

tesserata commented 6 years ago

Well, then it just takes longer before IdleTerminate appears. The problem is that no callback is returned after push or the callback handler doesn't react to it (the input would contain the log otherwise)

nickoala commented 6 years ago

I think you forgot to put these lines at the end:

while 1:
    time.sleep(10)

Without them, the program's main thread will end right away, and the MessageLoop, which is run as a second thread, will evaporate. You need to keep the program alive for MessageLoop to keep working.

tesserata commented 6 years ago

Oh, I did not specify this in the question; I'm running my code in the IPython notebook for now, so the kernel doesn't die after executing the code and continues to listen. I've tried to add the cycle you mentioned, but it changes nothing.

The thing is that bot reacts to commands with a slash (like, /docs), but doesn't react to pressing a button in InlineKeyboardMarkup. So I suppose it has something to do with callback response.

AditiChoksi commented 6 years ago

You will need to mention the 'callback_query' parameter in the MessageLoop. I think this should work:

MessageLoop(bot, {'chat': on_chat_message, 'callback_query': on_callback_query}).run_as_thread()