nickoala / telepot

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

KeyError exception in __init__.py line 792 #184

Closed carloalbertobarbano closed 7 years ago

carloalbertobarbano commented 7 years ago

Telepot throws an exception while retrieveing messages from telegram servers. Here's the traceback:

(traceback from OSX)

Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 792, in get_from_telegram_server offset = max([relay_to_collector(update) for update in result]) + 1 File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 792, in <listcomp> offset = max([relay_to_collector(update) for update in result]) + 1 File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 779, in relay_to_collector 'chosen_inline_result']) File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 61, in _find_first_key raise KeyError(keys) KeyError: ['message', 'edited_message', 'callback_query', 'inline_query', 'chosen_inline_result']

Here's the code:

bot_token = "xxxxxxxxxxxxx"

#mock handle function
def handle(msg):
    chat_id = msg['chat']['id']
    type = msg['chat']['type']
    message_id = msg['message_id']

    bot.sendMessage(chat_id, "Test")

bot = telepot.Bot(bot_token)
bot.message_loop(handle) #Exception thrown here

while 1:
    time.sleep(10)

My bot no longer receives messages

Shayan123456 commented 7 years ago

Yeah When I send message to bot from Channel I receive this error Too: line 61, in _find_first_key raise KeyError(keys) KeyError: ['message', 'edited_message', 'callback_query', 'inline_query', 'chosen_inline_result']

carloalbertobarbano commented 7 years ago

@Shayan123456 @nickoala The issue is related to Telegram Channels. They're not supported by telepot so the bot crashes, but the messages remains in the telegram's queue (that's why my bot crashes on startup). We need support for channels in telepot.

Here's a sample message that will make it crash (from https://api.telegram.org/botXXXXXXXXXXX/getUpdates):

{"update_id":441783091,` "channel_post":{"message_id":1291,"chat":{"id":<channel_id>,"title":"<channel_title>","username":"<username>","type":"channel"},"date":1479733054,"text":"<some long unicode message>"}}

My bot was added as a channel admin.

So the exception is thrown as the message type is "channel_post" (or also "edit_channel_post") which is not included in https://github.com/nickoala/telepot/blob/master/telepot/__init__.py at line 776

Here's quick and dirty fix: replace _relay_tocollector function in init.py at line 774 with this one:

def relay_to_collector(update):
            key = _find_first_key(update, ['message',
                                           'channel_post',
                                           'edited_channel_post',
                                           'edited_message',
                                           'callback_query',
                                           'inline_query',
                                           'chosen_inline_result'])
            collect_queue.put(update[key])
            return update['update_id']

This will at least prevent the bot from crashing on startup. Thanks to https://github.com/ruste96 for this fix

nickoala commented 7 years ago

This seems to be related to the changes in Bot API 2.3. Expect an update on or before Nov 30.

R0bertoG commented 7 years ago

Can I suggest a better error message? Something like:

def _find_first_key(d, keys):
    for k in keys:
        if k in d:
            return k
    raise KeyError("Server returns a key that it's not in " + str(keys))

Maybe even return what is the name of the not expected key. I was coding when the error started to happen and I spent sometime until I undernstood what the problems was.

efazati commented 7 years ago

I have same error how can fix this?


Traceback (most recent call last):
  File "/home/argus/10days/pahlevon/env/lib/python2.7/site-packages/telepot/__init__.py", line 761, in get_from_telegram_server
    offset = max([relay_to_collector(update) for update in result]) + 1
  File "/home/argus/10days/pahlevon/env/lib/python2.7/site-packages/telepot/__init__.py", line 748, in relay_to_collector
    'chosen_inline_result'])
  File "/home/argus/10days/pahlevon/env/lib/python2.7/site-packages/telepot/__init__.py", line 61, in _find_first_key
    raise KeyError(keys)
KeyError: ['message', 'edited_message', 'callback_query', 'inline_query', 'chosen_inline_result']
carloalbertobarbano commented 7 years ago

Okay so here's the solution to fix telepot with the new API (2.3):

Replace function _relay_tocollector in file init.py at line 774 with:

def relay_to_collector(update):
            key = _find_first_key(update, ['message',
                                           'channel_post',
                                           'edited_channel_post',
                                           'edited_message',
                                           'callback_query',
                                           'inline_query',
                                           'chosen_inline_result'])
            collect_queue.put(update[key])
            return update['update_id']

Now in your bot's code to find out the chat type you can do:

def handle(msg):
    type = msg['chat']['type']

    if type == "private":
          #message from msg['chat']['first_name']
    else:
          #message from msg['chat']['title']

I'd wait until the next release of telepot to mark this issue as closed.

efazati commented 7 years ago

@carloalbertobarbano I use something like this

class AppManager(telepot.helper.ChatHandler):
    def __init__(self, *args, **kwargs):
        super(AppManager, self).__init__(*args, **kwargs)

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

        user, is_first_time = get_or_create_user(self.sender, msg, True)
carloalbertobarbano commented 7 years ago

@efazati you have to edit the telepot library yourself for now. Just replace the function in this file https://github.com/nickoala/telepot/blob/master/telepot/__init__.py as described above.

You can find the correct path for that file on your machine in the traceback of the exception

efazati commented 7 years ago

@carloalbertobarbano I did change that code, but what about handle in my code? i use with this method and i dont have method like your handle

i mean this


def handle(msg):
    type = msg['chat']['type']

    if type == "private":
          #message from msg['chat']['first_name']
    else:
          #message from msg['chat']['title'
carloalbertobarbano commented 7 years ago

@efazati That was just a sample. You can use telepot in the way you are used to without further changes. For any doubts about implementation refer to the Telepot Api Reference http://telepot.readthedocs.io/en/latest/reference.html or contact the author @nickoala

Let's keep this thread for this library bug only and free from other implementation-specific issues.

gonardfreeman commented 7 years ago

For all who dont want to wait update u can fix this problem by theyself, just add at 780 string at init.py (in relay_to_collector(update) this function) to list one value 'channel_post'

gonardfreeman commented 7 years ago

Oh, im sort of slowpoke)) sorry)

96Octavian commented 7 years ago

Following this issue, how could I know which channel my bot has been added to? Is there a way?

nickoala commented 7 years ago

@96Octavian, when a bot is added to a group, it receives a new_chat_member. But when added to a channel ...... I am not sure what notification you will get, if you get any notification at all. :thinking:

On the other hand, I have updated telepot (10.2) to encompass Bot API 2.3. Just do:

pip install telepot --upgrade

This issue should be no more. Thanks everyone for using telepot :blush:

snowcat404 commented 5 years ago

Telepot throws an exception while retrieveing messages from telegram servers. Here's the traceback:

(traceback from OSX)

Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 792, in get_from_telegram_server offset = max([relay_to_collector(update) for update in result]) + 1 File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 792, in <listcomp> offset = max([relay_to_collector(update) for update in result]) + 1 File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 779, in relay_to_collector 'chosen_inline_result']) File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/telepot/__init__.py", line 61, in _find_first_key raise KeyError(keys) KeyError: ['message', 'edited_message', 'callback_query', 'inline_query', 'chosen_inline_result']

Here's the code:

bot_token = "xxxxxxxxxxxxx"

#mock handle function
def handle(msg):
    chat_id = msg['chat']['id']
    type = msg['chat']['type']
    message_id = msg['message_id']

    bot.sendMessage(chat_id, "Test")

bot = telepot.Bot(bot_token)
bot.message_loop(handle) #Exception thrown here

while 1:
  time.sleep(10)

My bot no longer receives messages

Same error in the latest bot API update when working with polls. `

@Shayan123456 @nickoala The issue is related to Telegram Channels. They're not supported by telepot so the bot crashes, but the messages remains in the telegram's queue (that's why my bot crashes on startup). We need support for channels in telepot.

Here's a sample message that will make it crash (from https://api.telegram.org/botXXXXXXXXXXX/getUpdates):

{"update_id":441783091,` "channel_post":{"message_id":1291,"chat":{"id":<channel_id>,"title":"<channel_title>","username":"<username>","type":"channel"},"date":1479733054,"text":"<some long unicode message>"}}

My bot was added as a channel admin.

So the exception is thrown as the message type is "channel_post" (or also "edit_channel_post") which is not included in https://github.com/nickoala/telepot/blob/master/telepot/__init__.py at line 776

Here's quick and dirty fix: replace _relay_tocollector function in init.py at line 774 with this one:

def relay_to_collector(update):
            key = _find_first_key(update, ['message',
                                           'channel_post',
                                           'edited_channel_post',
                                           'edited_message',
                                           'callback_query',
                                           'inline_query',
                                           'chosen_inline_result'])
            collect_queue.put(update[key])
            return update['update_id']

This will at least prevent the bot from crashing on startup. Thanks to https://github.com/ruste96 for this fix

got a monkey patch like this for the Bot API 4.2 poll update?