Refactoring and API conformance

Refactoring.

new_chat_member is out of support.

Bugfix in html_text.

Started Bot API conformance checking.
This commit is contained in:
Badiboy 2020-04-11 16:54:25 +03:00
parent 36a228da92
commit 995814d846
2 changed files with 101 additions and 120 deletions

View File

@ -514,9 +514,29 @@ apihelper.proxy = {'https':'socks5://userproxy:password@proxy_address:port'}
```
## New in library
## API conformance
06.06.2019 - Добавленна поддержка опросов (Poll). Добавлены функции send_poll, stop_poll
_Checking is in progress..._
✅ [Bot API 3.5](https://core.telegram.org/bots/api-changelog#november-17-2017) _- To be checked..._
* ✔ [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)
* ✔ [Bot API 3.1](https://core.telegram.org/bots/api-changelog#june-30-2017)
* ✔ [Bot API 3.0](https://core.telegram.org/bots/api-changelog#may-18-2017)
* ✔ [Bot API 2.3.1](https://core.telegram.org/bots/api-changelog#december-4-2016)
* ✔ [Bot API 2.3](https://core.telegram.org/bots/api-changelog#november-21-2016)
* ✔ [Bot API 2.2](https://core.telegram.org/bots/api-changelog#october-3-2016)
* ✔ [Bot API 2.1](https://core.telegram.org/bots/api-changelog#may-22-2016)
* ✔ [Bot API 2.0](https://core.telegram.org/bots/api-changelog#april-9-2016)
## Change log
11.09.2020 - Refactoring. new_chat_member is out of support. Bugfix in html_text. Started Bot API conformance checking.
06.06.2019 - Added polls support (Poll). Added functions send_poll, stop_poll
## F.A.Q.

View File

@ -66,14 +66,9 @@ class JsonDeserializable(object):
:param json_type:
:return:
"""
try:
str_types = (str, unicode)
except NameError:
str_types = (str,)
if type(json_type) == dict:
if isinstance(json_type, dict):
return json_type
elif type(json_type) in str_types:
elif isinstance(json_type, str):
return json.loads(json_type)
else:
raise ValueError("json_type should be a json dict or string.")
@ -94,36 +89,16 @@ class Update(JsonDeserializable):
def de_json(cls, json_type):
obj = cls.check_json(json_type)
update_id = obj['update_id']
message = None
edited_message = None
channel_post = None
edited_channel_post = None
inline_query = None
chosen_inline_result = None
callback_query = None
shipping_query = None
pre_checkout_query = None
poll = None
if 'message' in obj:
message = Message.de_json(obj['message'])
if 'edited_message' in obj:
edited_message = Message.de_json(obj['edited_message'])
if 'channel_post' in obj:
channel_post = Message.de_json(obj['channel_post'])
if 'edited_channel_post' in obj:
edited_channel_post = Message.de_json(obj['edited_channel_post'])
if 'inline_query' in obj:
inline_query = InlineQuery.de_json(obj['inline_query'])
if 'chosen_inline_result' in obj:
chosen_inline_result = ChosenInlineResult.de_json(obj['chosen_inline_result'])
if 'callback_query' in obj:
callback_query = CallbackQuery.de_json(obj['callback_query'])
if 'shipping_query' in obj:
shipping_query = ShippingQuery.de_json(obj['shipping_query'])
if 'pre_checkout_query' in obj:
pre_checkout_query = PreCheckoutQuery.de_json(obj['pre_checkout_query'])
if 'poll' in obj:
poll = Poll.de_json(obj['poll'])
message = Message.de_json(obj.get('message'))
edited_message = Message.de_json(obj.get('edited_message'))
channel_post = Message.de_json(obj.get('channel_post'))
edited_channel_post = Message.de_json(obj.get('edited_channel_post'))
inline_query = InlineQuery.de_json(obj.get('inline_query'))
chosen_inline_result = ChosenInlineResult.de_json(obj.get('chosen_inline_result'))
callback_query = CallbackQuery.de_json(obj.get('callback_query'))
shipping_query = ShippingQuery.de_json(obj.get('shipping_query'))
pre_checkout_query = PreCheckoutQuery.de_json(obj.get('pre_checkout_query'))
poll = Poll.de_json(obj['poll'])
return cls(update_id, message, edited_message, channel_post, edited_channel_post, inline_query,
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll)
@ -145,22 +120,15 @@ class Update(JsonDeserializable):
class WebhookInfo(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
url = obj['url']
has_custom_certificate = obj['has_custom_certificate']
pending_update_count = obj['pending_update_count']
last_error_date = None
last_error_message = None
max_connections = None
allowed_updates = None
if 'last_error_message' in obj:
last_error_date = obj['last_error_date']
if 'last_error_message' in obj:
last_error_message = obj['last_error_message']
if 'max_connections' in obj:
max_connections = obj['max_connections']
if 'allowed_updates' in obj:
allowed_updates = obj['allowed_updates']
last_error_date = obj.get('last_error_date')
last_error_message = obj.get('last_error_message')
max_connections = obj.get('max_connections')
allowed_updates = obj.get('allowed_updates')
return cls(url, has_custom_certificate, pending_update_count, last_error_date, last_error_message,
max_connections, allowed_updates)
@ -178,6 +146,7 @@ class WebhookInfo(JsonDeserializable):
class User(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
id = obj['id']
is_bot = obj['is_bot']
@ -199,6 +168,7 @@ class User(JsonDeserializable):
class GroupChat(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
id = obj['id']
title = obj['title']
@ -212,6 +182,7 @@ class GroupChat(JsonDeserializable):
class Chat(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
id = obj['id']
type = obj['type']
@ -220,14 +191,10 @@ class Chat(JsonDeserializable):
first_name = obj.get('first_name')
last_name = obj.get('last_name')
all_members_are_administrators = obj.get('all_members_are_administrators')
photo = None
if 'photo' in obj:
photo = ChatPhoto.de_json(obj['photo'])
photo = ChatPhoto.de_json(obj.get('photo'))
description = obj.get('description')
invite_link = obj.get('invite_link')
pinned_message = None
if 'pinned_message' in obj:
pinned_message = Message.de_json(obj['pinned_message'])
pinned_message = Message.de_json(obj.get('pinned_message'))
sticker_set_name = obj.get('sticker_set_name')
can_set_sticker_set = obj.get('can_set_sticker_set')
return cls(id, type, title, username, first_name, last_name, all_members_are_administrators,
@ -254,11 +221,10 @@ class Chat(JsonDeserializable):
class Message(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
message_id = obj['message_id']
from_user = None
if 'from' in obj:
from_user = User.de_json(obj['from'])
from_user = User.de_json(obj.get('from'))
date = obj['date']
chat = Chat.de_json(obj['chat'])
content_type = None
@ -326,15 +292,11 @@ class Message(JsonDeserializable):
if 'venue' in obj:
opts['venue'] = Venue.de_json(obj['venue'])
content_type = 'venue'
if 'new_chat_member' in obj:
opts['new_chat_member'] = User.de_json(obj['new_chat_member'])
content_type = 'new_chat_member'
if 'new_chat_members' in obj:
chat_members = obj['new_chat_members']
nms = []
for m in chat_members:
nms.append(User.de_json(m))
opts['new_chat_members'] = nms
new_chat_members = []
for member in obj['new_chat_members']:
new_chat_members.append(User.de_json(member))
opts['new_chat_members'] = new_chat_members
content_type = 'new_chat_members'
if 'left_chat_member' in obj:
opts['left_chat_member'] = User.de_json(obj['left_chat_member'])
@ -410,9 +372,10 @@ class Message(JsonDeserializable):
self.from_user = from_user
self.date = date
self.chat = chat
self.forward_from = None
self.forward_from_chat = None
self.forward_from_message_id = None
self.forward_from = None
self.forward_signature = None
self.forward_date = None
self.reply_to_message = None
self.edit_date = None
@ -433,7 +396,7 @@ class Message(JsonDeserializable):
self.location = None
self.venue = None
self.animation = None
self.new_chat_member = None
self.new_chat_member = None # Deprecated since Bot API 3.0. Not processed anymore
self.new_chat_members = None
self.left_chat_member = None
self.new_chat_title = None
@ -455,6 +418,7 @@ class Message(JsonDeserializable):
def __html_text(self, text, entities):
"""
Author: @sviat9440
Updaters: @badiboy
Message: "*Test* parse _formatting_, [url](https://example.com), [text_mention](tg://user?id=123456) and mention @username"
Example:
@ -471,12 +435,13 @@ class Message(JsonDeserializable):
if not entities:
return text
_subs = {
"bold" : "<b>{text}</b>",
"italic" : "<i>{text}</i>",
"pre" : "<pre>{text}</pre>",
"code" : "<code>{text}</code>",
"url" : "<a href=\"{url}\">{text}</a>",
#"url" : "<a href=\"{url}\">{text}</a>", # @badiboy plain URLs have no text and do not need tags
"text_link": "<a href=\"{url}\">{text}</a>"
}
if hasattr(self, "custom_subs"):
@ -503,8 +468,15 @@ class Message(JsonDeserializable):
if entity.offset > offset:
html_text += func(utf16_text[offset * 2 : entity.offset * 2])
offset = entity.offset
html_text += func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user)
offset += entity.length
html_text += func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user)
offset += entity.length
elif entity.offset == offset:
html_text += func(utf16_text[offset * 2 : (offset + entity.length) * 2], entity.type, entity.url, entity.user)
offset += entity.length
else:
# TODO: process nested entities from Bot API 4.5
# Now ignoring them
pass
if offset * 2 < len(utf16_text):
html_text += func(utf16_text[offset * 2:])
return html_text
@ -521,14 +493,13 @@ class Message(JsonDeserializable):
class MessageEntity(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
type = obj['type']
offset = obj['offset']
length = obj['length']
url = obj.get('url')
user = None
if 'user' in obj:
user = User.de_json(obj['user'])
user = User.de_json(obj.get('user'))
return cls(type, offset, length, url, user)
def __init__(self, type, offset, length, url=None, user=None):
@ -542,6 +513,7 @@ class MessageEntity(JsonDeserializable):
class PhotoSize(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
width = obj['width']
@ -559,6 +531,7 @@ class PhotoSize(JsonDeserializable):
class Audio(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
duration = obj['duration']
@ -580,6 +553,7 @@ class Audio(JsonDeserializable):
class Voice(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
duration = obj['duration']
@ -597,6 +571,7 @@ class Voice(JsonDeserializable):
class Document(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
thumb = None
@ -618,14 +593,13 @@ class Document(JsonDeserializable):
class Video(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
width = obj['width']
height = obj['height']
duration = obj['duration']
thumb = None
if 'thumb' in obj:
thumb = PhotoSize.de_json(obj['thumb'])
thumb = PhotoSize.de_json(obj.get('thumb'))
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
return cls(file_id, width, height, duration, thumb, mime_type, file_size)
@ -643,13 +617,12 @@ class Video(JsonDeserializable):
class VideoNote(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
length = obj['length']
duration = obj['duration']
thumb = None
if 'thumb' in obj:
thumb = PhotoSize.de_json(obj['thumb'])
thumb = PhotoSize.de_json(obj.get('thumb'))
file_size = obj.get('file_size')
return cls(file_id, length, duration, thumb, file_size)
@ -664,6 +637,7 @@ class VideoNote(JsonDeserializable):
class Contact(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
phone_number = obj['phone_number']
first_name = obj['first_name']
@ -681,6 +655,7 @@ class Contact(JsonDeserializable):
class Location(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
longitude = obj['longitude']
latitude = obj['latitude']
@ -711,6 +686,7 @@ class Venue(JsonDeserializable):
class UserProfilePhotos(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
total_count = obj['total_count']
photos = [[PhotoSize.de_json(y) for y in x] for x in obj['photos']]
@ -764,7 +740,6 @@ class ReplyKeyboardMarkup(JsonSerializable):
self.one_time_keyboard = one_time_keyboard
self.selective = selective
self.row_width = row_width
self.keyboard = []
def add(self, *args):
@ -818,13 +793,10 @@ class ReplyKeyboardMarkup(JsonSerializable):
json_dict = {'keyboard': self.keyboard}
if self.one_time_keyboard:
json_dict['one_time_keyboard'] = True
if self.resize_keyboard:
json_dict['resize_keyboard'] = True
if self.selective:
json_dict['selective'] = True
return json.dumps(json_dict)
@ -849,7 +821,6 @@ class KeyboardButton(Dictionaryable, JsonSerializable):
class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
def __init__(self, row_width=3):
self.row_width = row_width
self.keyboard = []
def add(self, *args):
@ -961,9 +932,7 @@ class CallbackQuery(JsonDeserializable):
obj = cls.check_json(json_type)
id = obj['id']
from_user = User.de_json(obj['from'])
message = None
if 'message' in obj:
message = Message.de_json(obj['message'])
message = Message.de_json(obj.get('message'))
inline_message_id = obj.get('inline_message_id')
chat_instance = obj['chat_instance']
data = obj.get('data')
@ -1046,9 +1015,7 @@ class InlineQuery(JsonDeserializable):
obj = cls.check_json(json_type)
id = obj['id']
from_user = User.de_json(obj['from'])
location = None
if 'location' in obj:
location = Location.de_json(obj['location'])
location = Location.de_json(obj.get('location'))
query = obj['query']
offset = obj['offset']
return cls(id, from_user, location, query, offset)
@ -1136,9 +1103,7 @@ class ChosenInlineResult(JsonDeserializable):
result_id = obj['result_id']
from_user = User.de_json(obj['from'])
query = obj['query']
location = None
if 'location' in obj:
location = Location.de_json(obj['location'])
location = Location.de_json(obj.get('location'))
inline_message_id = obj.get('inline_message_id')
return cls(result_id, from_user, query, location, inline_message_id)
@ -1783,6 +1748,7 @@ class InlineQueryResultGame(JsonSerializable):
class Game(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
title = obj['title']
description = obj['description']
@ -1791,9 +1757,7 @@ class Game(JsonDeserializable):
text_entities = None
if 'text_entities' in obj:
text_entities = Game.parse_entities(obj['text_entities'])
animation = None
if 'animation' in obj:
animation = Animation.de_json(obj['animation'])
animation = Animation.de_json(obj.get('animation'))
return cls(title, description, photo, text, text_entities, animation)
@classmethod
@ -1822,11 +1786,10 @@ class Game(JsonDeserializable):
class Animation(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
thumb = None
if 'thumb' in obj:
thumb = PhotoSize.de_json(obj['thumb'])
thumb = PhotoSize.de_json(obj.get('thumb'))
file_name = obj.get('file_name')
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
@ -1843,6 +1806,7 @@ class Animation(JsonDeserializable):
class GameHighScore(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
position = obj['position']
user = User.de_json(obj['user'])
@ -1872,6 +1836,7 @@ class LabeledPrice(JsonSerializable):
class Invoice(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
title = obj['title']
description = obj['description']
@ -1891,6 +1856,7 @@ class Invoice(JsonDeserializable):
class ShippingAddress(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
country_code = obj['country_code']
state = obj['state']
@ -1912,13 +1878,12 @@ class ShippingAddress(JsonDeserializable):
class OrderInfo(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
name = obj.get('name')
phone_number = obj.get('phone_number')
email = obj.get('email')
shipping_address = None
if 'shipping_address' in obj:
shipping_address = ShippingAddress.de_json(obj['shipping_address'])
shipping_address = ShippingAddress.de_json(obj.get('shipping_address'))
return cls(name, phone_number, email, shipping_address)
def __init__(self, name, phone_number, email, shipping_address):
@ -1954,14 +1919,13 @@ class ShippingOption(JsonSerializable):
class SuccessfulPayment(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
currency = obj['currency']
total_amount = obj['total_amount']
invoice_payload = obj['invoice_payload']
shipping_option_id = obj.get('shipping_option_id')
order_info = None
if 'order_info' in obj:
order_info = OrderInfo.de_json(obj['order_info'])
order_info = OrderInfo.de_json(obj.get('order_info'))
telegram_payment_charge_id = obj['telegram_payment_charge_id']
provider_payment_charge_id = obj['provider_payment_charge_id']
return cls(currency, total_amount, invoice_payload, shipping_option_id, order_info,
@ -1981,6 +1945,7 @@ class SuccessfulPayment(JsonDeserializable):
class ShippingQuery(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
id = obj['id']
from_user = User.de_json(obj['from'])
@ -1998,6 +1963,7 @@ class ShippingQuery(JsonDeserializable):
class PreCheckoutQuery(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
id = obj['id']
from_user = User.de_json(obj['from'])
@ -2005,9 +1971,7 @@ class PreCheckoutQuery(JsonDeserializable):
total_amount = obj['total_amount']
invoice_payload = obj['invoice_payload']
shipping_option_id = obj.get('shipping_option_id')
order_info = None
if 'order_info' in obj:
order_info = OrderInfo.de_json(obj['order_info'])
order_info = OrderInfo.de_json(obj.get('order_info'))
return cls(id, from_user, currency, total_amount, invoice_payload, shipping_option_id, order_info)
def __init__(self, id, from_user, currency, total_amount, invoice_payload, shipping_option_id, order_info):
@ -2025,6 +1989,7 @@ class PreCheckoutQuery(JsonDeserializable):
class StickerSet(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
name = obj['name']
title = obj['title']
@ -2044,19 +2009,16 @@ class StickerSet(JsonDeserializable):
class Sticker(JsonDeserializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
width = obj['width']
height = obj['height']
is_animated = obj['is_animated']
thumb = None
if 'thumb' in obj:
thumb = PhotoSize.de_json(obj['thumb'])
thumb = PhotoSize.de_json(obj.get('thumb'))
emoji = obj.get('emoji')
set_name = obj.get('set_name')
mask_position = None
if 'mask_position' in obj:
mask_position = MaskPosition.de_json(obj['mask_position'])
mask_position = MaskPosition.de_json(obj.get('mask_position'))
file_size = obj.get('file_size')
return cls(file_id, width, height, thumb, emoji, set_name, mask_position, file_size, is_animated)
@ -2074,6 +2036,7 @@ class Sticker(JsonDeserializable):
class MaskPosition(JsonDeserializable, JsonSerializable):
@classmethod
def de_json(cls, json_string):
if (json_string is None): return None
obj = cls.check_json(json_string)
point = obj['point']
x_shift = obj['x_shift']
@ -2249,9 +2212,7 @@ class Poll(JsonDeserializable):
is_anonymous = obj['is_anonymous']
poll_type = obj['type']
allows_multiple_answers = obj['allows_multiple_answers']
correct_option_id = None
if 'correct_option_id' in obj:
correct_option_id = obj['correct_option_id']
correct_option_id = obj.get('correct_option_id')
poll.id = poll_id
poll.options = options
poll.total_voter_count = total_voter_count