Skip to content
This repository has been archived by the owner on Jun 2, 2019. It is now read-only.

Moving to BOT API 4.0 - a few steps made #414

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions telepot/namedtuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def UserArray(data):
# incoming
ChatPhoto = _create_class('ChatPhoto', [
'small_file_id',
'big_file_id',
'big_file_id'
])

# incoming
Expand All @@ -127,7 +127,7 @@ def UserArray(data):
'invite_link',
_Field('pinned_message', constructor=_Message),
'sticker_set_name',
'can_set_sticker_set',
'can_set_sticker_set'
])

# incoming
Expand All @@ -136,7 +136,7 @@ def UserArray(data):
'width',
'height',
'file_size',
'file_path', # undocumented
'file_path' # undocumented
])

# incoming
Expand All @@ -146,7 +146,8 @@ def UserArray(data):
'performer',
'title',
'mime_type',
'file_size'
'file_size',
_Field('thumb', constructor=PhotoSize)
])

# incoming
Expand All @@ -156,15 +157,15 @@ def UserArray(data):
'file_name',
'mime_type',
'file_size',
'file_path', # undocumented
'file_path' # undocumented
])

# incoming and outgoing
MaskPosition = _create_class('MaskPosition', [
'point',
'x_shift',
'y_shift',
'scale',
'scale'
])

# incoming
Expand All @@ -176,7 +177,7 @@ def UserArray(data):
'emoji',
'set_name',
_Field('mask_position', constructor=MaskPosition),
'file_size',
'file_size'
])

def StickerArray(data):
Expand All @@ -187,7 +188,7 @@ def StickerArray(data):
'name',
'title',
'contains_masks',
_Field('stickers', constructor=StickerArray),
_Field('stickers', constructor=StickerArray)
])

# incoming
Expand Down Expand Up @@ -280,6 +281,7 @@ def PhotoSizeArrayArray(data):
'can_add_web_page_previews',
])


def ChatMemberArray(data):
return [ChatMember(**p) for p in data]

Expand Down Expand Up @@ -432,7 +434,7 @@ def MessageEntityArray(data):
'shipping_option_id',
_Field('order_info', constructor=OrderInfo),
'telegram_payment_charge_id',
'provider_payment_charge_id',
'provider_payment_charge_id'
])

# incoming
Expand Down Expand Up @@ -479,6 +481,7 @@ def MessageEntityArray(data):
_Field('invoice', constructor=Invoice),
_Field('successful_payment', constructor=SuccessfulPayment),
'connected_website',
_Field('animation', constructor=Animation)
])

# incoming
Expand All @@ -487,7 +490,7 @@ def MessageEntityArray(data):
_Field('from_', constructor=User),
_Field('location', constructor=Location),
'query',
'offset',
'offset'
])

# incoming
Expand All @@ -496,7 +499,7 @@ def MessageEntityArray(data):
_Field('from_', constructor=User),
_Field('location', constructor=Location),
'inline_message_id',
'query',
'query'
])

# incoming
Expand All @@ -507,7 +510,7 @@ def MessageEntityArray(data):
'inline_message_id',
'chat_instance',
'data',
'game_short_name',
'game_short_name'
])

# incoming
Expand All @@ -519,7 +522,7 @@ def MessageEntityArray(data):
_Field('edited_channel_post', constructor=Message),
_Field('inline_query', constructor=InlineQuery),
_Field('chosen_inline_result', constructor=ChosenInlineResult),
_Field('callback_query', constructor=CallbackQuery),
_Field('callback_query', constructor=CallbackQuery)
])

# incoming
Expand Down
2 changes: 2 additions & 0 deletions update_desc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This collection of directories contain READMEs which describe the process to get the project up to the point where is is compatible with the Telegram Bot API as described in https://core.telegram.org/bots/api .

2 changes: 2 additions & 0 deletions update_desc/TG_bot_API_4.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This collection of READMEs describe the process to get the project up to the point where is is compatible with the Telegram Bot API as described in https://core.telegram.org/bots/api#july-26-2018 .

115 changes: 115 additions & 0 deletions update_desc/TG_bot_API_4.0/README__20180808_1016.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
Let me brief on anyone who wants to make changes to accommodate the latest Bot API (4.0). I start with more trivial ones, then move on to harder ones.

Telegram says:

Added the field thumb to the Audio object to contain the thumbnail of the album cover to which the
music file belongs.

Key phrase is "Added the field thumb to the Audio object". In telepot, the habit is to represent API objects using Python dictionaries, so a new field in an object should not affect us. However, to facilitate accessing a field using . notation, there is a way to convert a dictionary into a namedtuple. As a result, every API object has a corresponding namedtuple. When a field is added to an object, we need to make a corresponding change to that namedtuple. The file is namedtuple.py. The original definition of Audio is:

# incoming
Audio = _create_class('Audio', [
'file_id',
'duration',
'performer',
'title',
'mime_type',
'file_size'
])

With the addition of a thumb field of the type PhotoSize, it should be modified as:

# incoming
Audio = _create_class('Audio', [
'file_id',
'duration',
'performer',
'title',
'mime_type',
'file_size',
_Field('thumb', constructor=PhotoSize),
])

The thumb field looks more complicated than others because its type is not primitive (int, float, string, etc) and we
need to tell it to interpret the dictionary in that place into another namedtuple. The "constructor" in this case is
just the name of the target namedtuple, and can be considered a parsing hint.

Also note the comment above the namedtuple definition. They can be:

incoming: meaning we only receive the object from Telegram servers, but never send it out
outgoing: meaning we only send it out, but never receive it
or both (rarely)

This distinction is important because:

for incoming namedtuples, we must make sure all non-primitive fields be given a "constructor" like above. Otherwise, that field would remain a dictionary, which defeats the purpose of using namedtuples. This is not needed for outgoing namedtuples because fields are supplied by user, so no parsing hint is required,

for outgoing namedtuples, some fields have default values. For example, InlineQueryResultArticle's type field is default to article, as required by Bot API. In contrast, no field of any incoming namedtuples has default values.

DONE: 20180811_1742 (UH)

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

Telegram says:

Added the field animation to the Message object. For backward compatibility, when this field is set, the document
field will be also set.

Key phrase: Added the field animation to the Message object. Points to consider:

Message is an incoming namedtuple
the field animation is of the type Animation

Changes should be similar. I leave that to the reader as an exercise.

DONE: 20180811_1752 (UH)

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

Telegram says:

Added support for Foursquare venues: added the new field foursquare_type to the objects
Venue, InlineQueryResultVenue and InputVenueMessageContent, and the parameter foursquare_type
to the sendVenue method.

Points to consider:

The field foursquare_type is of the type String. No parsing hint (if incoming) is needed.
Venue is incoming
InlineQueryResultVenue and InputVenueMessageContent are outgoing

I also leave the changes as an exercise.

As for the method sendVenue, I will delay the discussion until later, lumping it together with other method changes.

DONE: 201808 (UH)

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

Telegram says:

Added vCard support when sharing contacts: added the field vcard to the objects Contact, InlineQueryResultContact, InputContactMessageContent and the method sendContact.

The field vcard is of the type String.
Contact is incoming
InlineQueryResultContact and InputContactMessageContent are outgoing

I will delay the discussion of the method sendContact similarly.

DONE: 201808 (UH)

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

Telegram says:

Added support for editing the media content of messages: added the method editMessageMedia and new types InputMediaAnimation, InputMediaAudio, and InputMediaDocument.

Finally, we have to create new types of namedtuple here.

InputMediaAnimation, InputMediaAudio, and InputMediaDocument are all outgoing

Luckily, there are two InputMedia* siblings in existence already: InputMediaPhoto and InputMediaVideo. Find them, and use them as templates for the new members.

DONE: 201808 (UH)

########################################################################################################################
99 changes: 99 additions & 0 deletions update_desc/TG_bot_API_4.0/README__20180809_1442.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
Tonight, let's see how to change methods.

Telegram says:

Added support for Foursquare venues: added ... the parameter foursquare_type to the sendVenue method.

Added vCard support when sharing contacts: added the field vcard to ... the method sendContact.

The two methods, sendVenue and sendContact, are adjacent in the file __init__.py, within the Bot class. Let's look at them together. Here are the original:

def sendVenue(self, chat_id, latitude, longitude, title, address,
foursquare_id=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None):
""" See: https://core.telegram.org/bots/api#sendvenue """
p = _strip(locals())
return self._api_request('sendVenue', _rectify(p))

def sendContact(self, chat_id, phone_number, first_name,
last_name=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None):
""" See: https://core.telegram.org/bots/api#sendcontact """
p = _strip(locals())
return self._api_request('sendContact', _rectify(p))

Changes are straight-forward:

def sendVenue(self, chat_id, latitude, longitude, title, address,
foursquare_id=None,
foursquare_type=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None):
""" See: https://core.telegram.org/bots/api#sendvenue """
p = _strip(locals())
return self._api_request('sendVenue', _rectify(p))

def sendContact(self, chat_id, phone_number, first_name,
last_name=None,
vcard=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None):
""" See: https://core.telegram.org/bots/api#sendcontact """
p = _strip(locals())
return self._api_request('sendContact', _rectify(p))

Both are optional parameters, so default to None. There's nothing to change in the method body. _strip(locals()) puts all method parameters other than self into a dict. _rectify(p) removes all None values before passing them to self._api_request().

Telegram says:

Added the method sendAnimation, which can be used instead of sendDocument to send animations, specifying their duration, width and height.

Luckily, we have a lot of send* methods to copy from, e.g. sendDocument, sendVideo, sendVoice, etc. I use sendVideo as an example:

def sendVideo(self, chat_id, video,
duration=None,
width=None,
height=None,
caption=None,
parse_mode=None,
supports_streaming=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None):
"""
See: https://core.telegram.org/bots/api#sendvideo

:param video: Same as ``photo`` in :meth:`telepot.Bot.sendPhoto`
"""
p = _strip(locals(), more=['video'])
return self._api_request_with_file('sendVideo', _rectify(p), 'video', video)

Making sendAnimation is just a matter of fixing names and matching method parameters with Telegram docs:

def sendAnimation(self, chat_id, animation,
duration=None,
width=None,
height=None,
caption=None,
parse_mode=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None):
"""
See: https://core.telegram.org/bots/api#sendanimation

:param video: Same as ``photo`` in :meth:`telepot.Bot.sendPhoto`
"""
p = _strip(locals(), more=['animation'])
return self._api_request_with_file('sendAnimation', _rectify(p), 'animation', animation)

Sending files takes some special handling. That's why I have to _strip the animation and pass it to self._api_request_with_file() outside of the rectified dict.

Unfortunately, I wasn't aware of the "thumb" parameter, which must have been added at some earlier date. To take care of it, we have to modify _api_request_with_file() to handle one more file to be uploaded.

Loading