From bab9b4077d159fad6607e707ce30e8c574de31f2 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 25 Aug 2020 18:18:51 +0300 Subject: [PATCH] Bot API support checked/updated up to 4.2 --- README.md | 7 +++++- telebot/__init__.py | 34 +++++++++++++++++-------- telebot/apihelper.py | 11 +++++--- telebot/types.py | 60 ++++++++++++++++++++++++++++++-------------- tests/test_types.py | 2 +- 5 files changed, 79 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 9285c4e..59a3dbf 100644 --- a/README.md +++ b/README.md @@ -539,8 +539,13 @@ apihelper.proxy = {'https':'socks5://userproxy:password@proxy_address:port'} _Checking is in progress..._ -✅ [Bot API 3.5](https://core.telegram.org/bots/api-changelog#november-17-2017) _- To be checked..._ +✅ [Bot API 4.3](https://core.telegram.org/bots/api-changelog#may-31-2019) _- To be checked..._ +* ✔ [Bot API 4.2](https://core.telegram.org/bots/api-changelog#april-14-2019) +* ➕ [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support. +* ➕ [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support. +* ✔ [Bot API 3.6](https://core.telegram.org/bots/api-changelog#february-13-2018) +* ✔ [Bot API 3.5](https://core.telegram.org/bots/api-changelog#november-17-2017) * ✔ [Bot API 3.4](https://core.telegram.org/bots/api-changelog#october-11-2017) * ✔ [Bot API 3.3](https://core.telegram.org/bots/api-changelog#august-23-2017) * ✔ [Bot API 3.2](https://core.telegram.org/bots/api-changelog#july-21-2017) diff --git a/telebot/__init__.py b/telebot/__init__.py index 3ca0cfe..1c74d02 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -711,6 +711,7 @@ class TeleBot: :param chat_id: which chat to forward :param from_chat_id: which chat message from :param message_id: message id + :param timeout: :return: API reply. """ return types.Message.de_json( @@ -721,6 +722,7 @@ class TeleBot: Use this method to delete message. Returns True on success. :param chat_id: in which chat to delete :param message_id: which message to delete + :param timeout: :return: API reply. """ return apihelper.delete_message(self.token, chat_id, message_id, timeout) @@ -736,6 +738,7 @@ class TeleBot: :param disable_notification: :param reply_to_message_id: :param reply_markup: + :param timeout: :return: Message """ return types.Message.de_json( @@ -755,6 +758,7 @@ class TeleBot: :param parse_mode :param reply_to_message_id: :param reply_markup: + :param timeout: :return: API reply. """ parse_mode = self.parse_mode if not parse_mode else parse_mode @@ -924,6 +928,7 @@ class TeleBot: :param media: :param disable_notification: :param reply_to_message_id: + :param timeout: :return: """ result = apihelper.send_media_group( @@ -945,6 +950,7 @@ class TeleBot: :param reply_to_message_id: :param reply_markup: :param disable_notification: + :param timeout: :return: API reply. """ return types.Message.de_json( @@ -962,6 +968,7 @@ class TeleBot: :param message_id: :param inline_message_id: :param reply_markup: + :param timeout: :return: """ return types.Message.de_json( @@ -979,6 +986,7 @@ class TeleBot: :param message_id: :param inline_message_id: :param reply_markup: + :param timeout: :return: """ return types.Message.de_json( @@ -986,8 +994,8 @@ class TeleBot: self.token, chat_id, message_id, inline_message_id, reply_markup, timeout)) def send_venue( - self, chat_id, latitude, longitude, title, address, foursquare_id=None, disable_notification=None, - reply_to_message_id=None, reply_markup=None, timeout=None): + self, chat_id, latitude, longitude, title, address, foursquare_id=None, foursquare_type=None, + disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None): """ Use this method to send information about a venue. :param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel @@ -996,25 +1004,26 @@ class TeleBot: :param title: String : Name of the venue :param address: String : Address of the venue :param foursquare_id: String : Foursquare identifier of the venue + :param foursquare_type: Foursquare type of the venue, if known. (For example, “arts_entertainment/default”, “arts_entertainment/aquarium” or “food/icecream”.) :param disable_notification: :param reply_to_message_id: :param reply_markup: + :param timeout: :return: """ return types.Message.de_json( apihelper.send_venue( - self.token, chat_id, latitude, longitude, title, address, foursquare_id, + self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, disable_notification, reply_to_message_id, reply_markup, timeout) ) def send_contact( - self, chat_id, phone_number, first_name, - last_name=None, disable_notification=None, - reply_to_message_id=None, reply_markup=None, timeout=None): + self, chat_id, phone_number, first_name, last_name=None, vcard=None, + disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None): return types.Message.de_json( apihelper.send_contact( - self.token, chat_id, phone_number, first_name, last_name, disable_notification, - reply_to_message_id, reply_markup, timeout) + self.token, chat_id, phone_number, first_name, last_name, vcard, + disable_notification, reply_to_message_id, reply_markup, timeout) ) def send_chat_action(self, chat_id, action, timeout=None): @@ -1025,6 +1034,7 @@ class TeleBot: :param chat_id: :param action: One of the following strings: 'typing', 'upload_photo', 'record_video', 'upload_video', 'record_audio', 'upload_audio', 'upload_document', 'find_location', 'record_video_note', 'upload_video_note'. + :param timeout: :return: API reply. :type: boolean """ return apihelper.send_chat_action(self.token, chat_id, action, timeout) @@ -1297,6 +1307,7 @@ class TeleBot: :param disable_notification: :param reply_to_message_id: :param reply_markup: + :param timeout: :return: """ result = apihelper.send_game( @@ -1368,6 +1379,7 @@ class TeleBot: :param reply_to_message_id: If the message is a reply, ID of the original message :param reply_markup: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button :param provider_data: A JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. + :param timeout: :return: """ result = apihelper.send_invoice( @@ -1400,6 +1412,7 @@ class TeleBot: :param disable_notifications: :param reply_to_message_id: :param reply_markup: + :param timeout: :return: """ @@ -1414,14 +1427,15 @@ class TeleBot: explanation, explanation_parse_mode, open_period, close_date, is_closed, disable_notifications, reply_to_message_id, reply_markup, timeout)) - def stop_poll(self, chat_id, message_id): + def stop_poll(self, chat_id, message_id, reply_markup=None): """ Stops poll :param chat_id: :param message_id: + :param reply_markup: :return: """ - return types.Poll.de_json(apihelper.stop_poll(self.token, chat_id, message_id)) + return types.Poll.de_json(apihelper.stop_poll(self.token, chat_id, message_id, reply_markup)) def answer_shipping_query(self, shipping_query_id, ok, shipping_options=None, error_message=None): """ diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 70c3f26..b80a627 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -427,12 +427,14 @@ def stop_message_live_location( def send_venue( token, chat_id, latitude, longitude, title, address, - foursquare_id=None, disable_notification=None, + foursquare_id=None, foursquare_type=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None): method_url = r'sendVenue' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address} if foursquare_id: payload['foursquare_id'] = foursquare_id + if foursquare_type: + payload['foursquare_type'] = foursquare_type if disable_notification is not None: payload['disable_notification'] = disable_notification if reply_to_message_id: @@ -445,13 +447,14 @@ def send_venue( def send_contact( - token, chat_id, phone_number, first_name, - last_name=None, disable_notification=None, - reply_to_message_id=None, reply_markup=None, timeout=None): + token, chat_id, phone_number, first_name, last_name=None, vcard=None, + disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None): method_url = r'sendContact' payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name} if last_name: payload['last_name'] = last_name + if vcard: + payload['vcard'] = vcard if disable_notification is not None: payload['disable_notification'] = disable_notification if reply_to_message_id: diff --git a/telebot/types.py b/telebot/types.py index d00cb6d..55689a6 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -274,6 +274,8 @@ class Message(JsonDeserializable): opts['forward_from_message_id'] = obj.get('forward_from_message_id') if 'forward_signature' in obj: opts['forward_signature'] = obj.get('forward_signature') + if 'forward_sender_name' in obj: + opts['forward_sender_name'] = obj.get('forward_sender_name') if 'forward_date' in obj: opts['forward_date'] = obj.get('forward_date') if 'reply_to_message' in obj: @@ -416,6 +418,7 @@ class Message(JsonDeserializable): self.forward_from_chat = None self.forward_from_message_id = None self.forward_signature = None + self.forward_sender_name = None self.forward_date = None self.reply_to_message = None self.edit_date = None @@ -544,14 +547,16 @@ class MessageEntity(JsonDeserializable): length = obj['length'] url = obj.get('url') user = User.de_json(obj.get('user')) - return cls(type, offset, length, url, user) + language = obj.get('language') + return cls(type, offset, length, url, user, language) - def __init__(self, type, offset, length, url=None, user=None): + def __init__(self, type, offset, length, url=None, user=None, language=None): self.type = type self.offset = offset self.length = length self.url = url self.user = user + self.language = language class Dice(JsonSerializable, Dictionaryable, JsonDeserializable): @@ -711,13 +716,15 @@ class Contact(JsonDeserializable): first_name = obj['first_name'] last_name = obj.get('last_name') user_id = obj.get('user_id') - return cls(phone_number, first_name, last_name, user_id) + vcard = obj.get('vcard') + return cls(phone_number, first_name, last_name, user_id, vcard) - def __init__(self, phone_number, first_name, last_name=None, user_id=None): + def __init__(self, phone_number, first_name, last_name=None, user_id=None, vcard=None): self.phone_number = phone_number self.first_name = first_name self.last_name = last_name self.user_id = user_id + self.vcard = vcard class Location(JsonDeserializable): @@ -745,13 +752,15 @@ class Venue(JsonDeserializable): title = obj['title'] address = obj['address'] foursquare_id = obj.get('foursquare_id') - return cls(location, title, address, foursquare_id) + foursquare_type = obj.get('foursquare_type') + return cls(location, title, address, foursquare_id, foursquare_type) - def __init__(self, location, title, address, foursquare_id=None): + def __init__(self, location, title, address, foursquare_id=None, foursquare_type=None): self.location = location self.title = title self.address = address self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type class UserProfilePhotos(JsonDeserializable): @@ -1281,12 +1290,13 @@ class InputLocationMessageContent(Dictionaryable): class InputVenueMessageContent(Dictionaryable): - def __init__(self, latitude, longitude, title, address, foursquare_id=None): + def __init__(self, latitude, longitude, title, address, foursquare_id=None, foursquare_type=None): self.latitude = latitude self.longitude = longitude self.title = title self.address = address self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type def to_dict(self): json_dict = { @@ -1297,19 +1307,24 @@ class InputVenueMessageContent(Dictionaryable): } if self.foursquare_id: json_dict['foursquare_id'] = self.foursquare_id + if self.foursquare_type: + json_dict['foursquare_type'] = self.foursquare_type return json_dict class InputContactMessageContent(Dictionaryable): - def __init__(self, phone_number, first_name, last_name=None): + def __init__(self, phone_number, first_name, last_name=None, vcard=None): self.phone_number = phone_number self.first_name = first_name self.last_name = last_name + self.vcard = vcard def to_dict(self): json_dict = {'phone_numbe': self.phone_number, 'first_name': self.first_name} if self.last_name: json_dict['last_name'] = self.last_name + if self.vcard: + json_dict['vcard'] = self.vcard return json_dict @@ -1737,8 +1752,8 @@ class InlineQueryResultLocation(JsonSerializable): class InlineQueryResultVenue(JsonSerializable): - def __init__(self, id, title, latitude, longitude, address, foursquare_id=None, reply_markup=None, - input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None): + def __init__(self, id, title, latitude, longitude, address, foursquare_id=None, foursquare_type=None, + reply_markup=None, input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None): self.type = 'venue' self.id = id self.title = title @@ -1746,6 +1761,7 @@ class InlineQueryResultVenue(JsonSerializable): self.longitude = longitude self.address = address self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type self.reply_markup = reply_markup self.input_message_content = input_message_content self.thumb_url = thumb_url @@ -1757,6 +1773,8 @@ class InlineQueryResultVenue(JsonSerializable): 'longitude': self.longitude, 'address': self.address} if self.foursquare_id: json_dict['foursquare_id'] = self.foursquare_id + if self.foursquare_type: + json_dict['foursquare_type'] = self.foursquare_type if self.thumb_url: json_dict['thumb_url'] = self.thumb_url if self.thumb_width: @@ -1771,13 +1789,15 @@ class InlineQueryResultVenue(JsonSerializable): class InlineQueryResultContact(JsonSerializable): - def __init__(self, id, phone_number, first_name, last_name=None, reply_markup=None, - input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None): + def __init__(self, id, phone_number, first_name, last_name=None, vcard=None, + reply_markup=None, input_message_content=None, + thumb_url=None, thumb_width=None, thumb_height=None): self.type = 'contact' self.id = id self.phone_number = phone_number self.first_name = first_name self.last_name = last_name + self.vcard = vcard self.reply_markup = reply_markup self.input_message_content = input_message_content self.thumb_url = thumb_url @@ -1788,16 +1808,18 @@ class InlineQueryResultContact(JsonSerializable): json_dict = {'type': self.type, 'id': self.id, 'phone_number': self.phone_number, 'first_name': self.first_name} if self.last_name: json_dict['last_name'] = self.last_name + if self.vcard: + json_dict['vcard'] = self.vcard + if self.reply_markup: + json_dict['reply_markup'] = self.reply_markup.to_dict() + if self.input_message_content: + json_dict['input_message_content'] = self.input_message_content.to_dict() if self.thumb_url: json_dict['thumb_url'] = self.thumb_url if self.thumb_width: json_dict['thumb_width'] = self.thumb_width if self.thumb_height: json_dict['thumb_height'] = self.thumb_height - if self.reply_markup: - json_dict['reply_markup'] = self.reply_markup.to_dict() - if self.input_message_content: - json_dict['input_message_content'] = self.input_message_content.to_dict() return json.dumps(json_dict) @@ -1976,9 +1998,10 @@ class Game(JsonDeserializable): description = obj['description'] photo = Game.parse_photo(obj['photo']) text = obj.get('text') - text_entities = None if 'text_entities' in obj: text_entities = Game.parse_entities(obj['text_entities']) + else: + text_entities = None animation = Animation.de_json(obj.get('animation')) return cls(title, description, photo, text, text_entities, animation) @@ -2446,7 +2469,6 @@ class Poll(JsonDeserializable): explanation_entities = None open_period = obj.get('open_period') close_date = obj.get('close_date') - #poll = return cls( question, options, poll_id, total_voter_count, is_closed, is_anonymous, poll_type, @@ -2469,7 +2491,7 @@ class Poll(JsonDeserializable): self.allows_multiple_answers = allows_multiple_answers self.correct_option_id = correct_option_id self.explanation = explanation - self.explanation_entities = explanation_entities if not(explanation_entities is None) else [] + self.explanation_entities = explanation_entities # Default state of entities is None. if (explanation_entities is not None) else [] self.open_period = open_period self.close_date = close_date diff --git a/tests/test_types.py b/tests/test_types.py index 742c113..d8c1403 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -110,7 +110,7 @@ def test_json_UserProfilePhotos(): def test_json_contact(): - json_string = r'{"phone_number":"00011111111","first_name":"dd","last_name":"ddl","user_id":8633}' + json_string = r'{"phone_number":"00011111111","first_name":"dd","last_name":"ddl","user_id":8633,"vcard":"SomeContactString"}' contact = types.Contact.de_json(json_string) assert contact.first_name == 'dd' assert contact.last_name == 'ddl'