From c13f9a7f98f26d26748591c30d73d290c1a4effa Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Tue, 25 Aug 2020 21:26:28 +0300 Subject: [PATCH 01/14] Add last_update_id parameter for constructor --- telebot/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 3ca0cfe..33c3094 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -92,7 +92,7 @@ class TeleBot: """ def __init__( - self, token, parse_mode=None, threaded=True, skip_pending=False, num_threads=2, + self, token, parse_mode=None, last_update_id=0, threaded=True, skip_pending=False, num_threads=2, next_step_backend=None, reply_backend=None, exception_handler=None ): """ @@ -107,7 +107,7 @@ class TeleBot: self.skip_pending = skip_pending self.__stop_polling = threading.Event() - self.last_update_id = 0 + self.last_update_id = last_update_id self.exc_info = None self.next_step_backend = next_step_backend From 5120650774ec3a321c5532c09256dfc1193cc28e Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Tue, 25 Aug 2020 21:45:30 +0300 Subject: [PATCH 02/14] Move parameter to the end of list --- telebot/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 33c3094..2a98812 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -92,8 +92,8 @@ class TeleBot: """ def __init__( - self, token, parse_mode=None, last_update_id=0, threaded=True, skip_pending=False, num_threads=2, - next_step_backend=None, reply_backend=None, exception_handler=None + self, token, parse_mode=None, threaded=True, skip_pending=False, num_threads=2, + next_step_backend=None, reply_backend=None, exception_handler=None, last_update_id=0 ): """ :param token: bot API token From e811163b5f402fac1eff549480658f41dddb6917 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Sat, 29 Aug 2020 04:29:02 +0800 Subject: [PATCH 03/14] UPG: Added the field `file_unique_id` Added the field file_unique_id to the objects Animation, Audio, Document, PassportFile, PhotoSize, Sticker, Video, VideoNote, Voice, File and the fields small_file_unique_id and big_file_unique_id to the object ChatPhoto. (Bot API 4.5) --- telebot/types.py | 56 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 55689a6..8597101 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -586,13 +586,15 @@ class PhotoSize(JsonDeserializable): if (json_string is None): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] width = obj['width'] height = obj['height'] file_size = obj.get('file_size') - return cls(file_id, width, height, file_size) + return cls(file_id, file_unique_id, width, height, file_size) - def __init__(self, file_id, width, height, file_size=None): + def __init__(self, file_id, file_unique_id, width, height, file_size=None): self.file_size = file_size + self.file_unique_id = file_unique_id self.height = height self.width = width self.file_id = file_id @@ -604,15 +606,17 @@ class Audio(JsonDeserializable): if (json_string is None): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] duration = obj['duration'] performer = obj.get('performer') title = obj.get('title') mime_type = obj.get('mime_type') file_size = obj.get('file_size') - return cls(file_id, duration, performer, title, mime_type, file_size) + return cls(file_id, file_unique_id, duration, performer, title, mime_type, file_size) - def __init__(self, file_id, duration, performer=None, title=None, mime_type=None, file_size=None): + def __init__(self, file_id, file_unique_id, duration, performer=None, title=None, mime_type=None, file_size=None): self.file_id = file_id + self.file_unique_id = file_unique_id self.duration = duration self.performer = performer self.title = title @@ -626,13 +630,15 @@ class Voice(JsonDeserializable): if (json_string is None): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] duration = obj['duration'] mime_type = obj.get('mime_type') file_size = obj.get('file_size') - return cls(file_id, duration, mime_type, file_size) + return cls(file_id, file_unique_id, duration, mime_type, file_size) - def __init__(self, file_id, duration, mime_type=None, file_size=None): + def __init__(self, file_id, file_unique_id, duration, mime_type=None, file_size=None): self.file_id = file_id + self.file_unique_id = file_unique_id self.duration = duration self.mime_type = mime_type self.file_size = file_size @@ -644,16 +650,18 @@ class Document(JsonDeserializable): if (json_string is None): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] thumb = None if 'thumb' in obj and 'file_id' in obj['thumb']: thumb = PhotoSize.de_json(obj['thumb']) file_name = obj.get('file_name') mime_type = obj.get('mime_type') file_size = obj.get('file_size') - return cls(file_id, thumb, file_name, mime_type, file_size) + return cls(file_id, file_unique_id, thumb, file_name, mime_type, file_size) - def __init__(self, file_id, thumb=None, file_name=None, mime_type=None, file_size=None): + def __init__(self, file_id, file_unique_id, thumb=None, file_name=None, mime_type=None, file_size=None): self.file_id = file_id + self.file_unique_id = file_unique_id self.thumb = thumb self.file_name = file_name self.mime_type = mime_type @@ -667,16 +675,18 @@ class Video(JsonDeserializable): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] width = obj['width'] height = obj['height'] duration = obj['duration'] 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) + return cls(file_id, file_unique_id, width, height, duration, thumb, mime_type, file_size) - def __init__(self, file_id, width, height, duration, thumb=None, mime_type=None, file_size=None): + def __init__(self, file_id, file_unique_id, width, height, duration, thumb=None, mime_type=None, file_size=None): self.file_id = file_id + self.file_unique_id = file_unique_id self.width = width self.height = height self.duration = duration @@ -692,14 +702,16 @@ class VideoNote(JsonDeserializable): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] length = obj['length'] duration = obj['duration'] thumb = PhotoSize.de_json(obj.get('thumb')) file_size = obj.get('file_size') - return cls(file_id, length, duration, thumb, file_size) + return cls(file_id, file_unique_id, length, duration, thumb, file_size) - def __init__(self, file_id, length, duration, thumb=None, file_size=None): + def __init__(self, file_id, file_unique_id, length, duration, thumb=None, file_size=None): self.file_id = file_id + self.file_unique_id = file_unique_id self.length = length self.duration = duration self.thumb = thumb @@ -785,12 +797,14 @@ class File(JsonDeserializable): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] file_size = obj.get('file_size') file_path = obj.get('file_path') - return cls(file_id, file_size, file_path) + return cls(file_id, file_unique_id, file_size, file_path) - def __init__(self, file_id, file_size, file_path): + def __init__(self, file_id, file_unique_id, file_size, file_path): self.file_id = file_id + self.file_unique_id = file_unique_id self.file_size = file_size self.file_path = file_path @@ -1085,12 +1099,16 @@ class ChatPhoto(JsonDeserializable): return None obj = cls.check_json(json_string) small_file_id = obj['small_file_id'] + small_file_unique_id = obj['small_file_unique_id'] big_file_id = obj['big_file_id'] - return cls(small_file_id, big_file_id) + big_file_unique_id = obj['big_file_unique_id'] + return cls(small_file_id, small_file_unique_id, big_file_id, big_file_unique_id) - def __init__(self, small_file_id, big_file_id): + def __init__(self, small_file_id, small_file_unique_id, big_file_id, big_file_unique_id): self.small_file_id = small_file_id + self.small_file_unique_id = small_file_unique_id self.big_file_id = big_file_id + self.big_file_unique_id = big_file_unique_id class ChatMember(JsonDeserializable): @@ -2034,14 +2052,16 @@ class Animation(JsonDeserializable): if (json_string is None): return None obj = cls.check_json(json_string) file_id = obj['file_id'] + file_unique_id = obj['file_unique_id'] 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') - return cls(file_id, thumb, file_name, mime_type, file_size) + return cls(file_id, file_unique_id, thumb, file_name, mime_type, file_size) - def __init__(self, file_id, thumb=None, file_name=None, mime_type=None, file_size=None): + def __init__(self, file_id, file_unique_id, thumb=None, file_name=None, mime_type=None, file_size=None): self.file_id = file_id + self.file_unique_id = file_unique_id self.thumb = thumb self.file_name = file_name self.mime_type = mime_type From bdfb793e3421a9e35390937c57117bcd19730576 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Sat, 29 Aug 2020 12:07:38 +0800 Subject: [PATCH 04/14] test: Added file_unique_id from Bot API 4.5 --- tests/test_types.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_types.py b/tests/test_types.py index d8c1403..2f1e698 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -41,14 +41,14 @@ def test_json_GroupChat(): def test_json_Document(): - json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}' + json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}' doc = types.Document.de_json(json_string) assert doc.thumb is None assert doc.file_name == 'Text File' def test_json_Message_Audio(): - json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd","is_bot":true },"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}' + json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd","is_bot":true },"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_unique_id": "AgADawEAAn8VSFY","file_size":20096}}' msg = types.Message.de_json(json_string) assert msg.audio.duration == 1 assert msg.content_type == 'audio' @@ -73,21 +73,21 @@ def test_json_Message_Sticker_without_thumb(): def test_json_Message_Document(): - json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}' + json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}' msg = types.Message.de_json(json_string) assert msg.document.file_name == 'Text File' assert msg.content_type == 'document' def test_json_Message_Photo(): - json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}' + json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":53013,"width":759,"height":570}]}' msg = types.Message.de_json(json_string) assert len(msg.photo) == 3 assert msg.content_type == 'photo' def test_json_Message_Video(): - json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}' + json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}' msg = types.Message.de_json(json_string) assert msg.video assert msg.video.duration == 3 @@ -103,7 +103,7 @@ def test_json_Message_Location(): def test_json_UserProfilePhotos(): - json_string = r'{"total_count":1,"photos":[[{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATZH_SpyZjzIwdVAAIC","file_size":6150,"width":160,"height":160},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATOiTNi_YoJMghVAAIC","file_size":13363,"width":320,"height":320},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAQW4DyFv0-lhglVAAIC","file_size":28347,"width":640,"height":640},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAT50RvJCg0GQApVAAIC","file_size":33953,"width":800,"height":800}]]}' + json_string = r'{"total_count":1,"photos":[[{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATZH_SpyZjzIwdVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":6150,"width":160,"height":160},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATOiTNi_YoJMghVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":13363,"width":320,"height":320},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAQW4DyFv0-lhglVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":28347,"width":640,"height":640},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAT50RvJCg0GQApVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":33953,"width":800,"height":800}]]}' upp = types.UserProfilePhotos.de_json(json_string) assert upp.photos[0][0].width == 160 assert upp.photos[0][-1].height == 800 @@ -117,7 +117,7 @@ def test_json_contact(): def test_json_voice(): - json_string = r'{"duration": 0,"mime_type": "audio/ogg","file_id": "AwcccccccDH1JaB7w_gyFjYQxVAg","file_size": 10481}' + json_string = r'{"duration": 0,"mime_type": "audio/ogg","file_id": "AwcccccccDH1JaB7w_gyFjYQxVAg","file_unique_id": "AgADbAEAAn8VSFY","file_size": 10481}' voice = types.Voice.de_json(json_string) assert voice.duration == 0 assert voice.file_size == 10481 From 81100f249cbec7f89f07c0fd62e02b397399bb96 Mon Sep 17 00:00:00 2001 From: Artem Frantsiian <35114937+ArtemFrantsiian@users.noreply.github.com> Date: Sat, 29 Aug 2020 21:57:41 +0300 Subject: [PATCH 05/14] Fix an error with the is_pil_image function When I've tried to send_photo as shown in detailed_example, I got an error: "AttributeError: module 'PIL' has no attribute 'Image'". This error was described well here: https://stackoverflow.com/a/11911536/9092263. So in accordance to prescriptions, I've made changes and It works fine for me. Steps to reproduce: 1. initiate bot via TeleBot constructor 2. call function bot.send_photo(call.message.chat.id, open("some_image.jpg", "rb")) P.S. Error Environment: - python==3.8.5 - pyTelegramBotAPI==3.7.3 - PIL==7.2.0 --- telebot/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/util.py b/telebot/util.py index 099828a..438e8c1 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -11,7 +11,7 @@ import queue as Queue import logging try: - import PIL + from PIL import Image from io import BytesIO pil_imported = True except: @@ -164,7 +164,7 @@ def is_bytes(var): return isinstance(var, bytes) def is_pil_image(var): - return pil_imported and isinstance(var, PIL.Image.Image) + return pil_imported and isinstance(var, Image.Image) def pil_image_to_file(image, extension='JPEG', quality='web_low'): if pil_imported: From 6832c337333536f39a500c7bccc1b354633189c8 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Mon, 31 Aug 2020 12:00:56 +0000 Subject: [PATCH 06/14] feat: Added the field reply_markup to the Message Added the field `reply_markup` to the Message object --- telebot/types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/telebot/types.py b/telebot/types.py index 8597101..e44d6b5 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -385,6 +385,9 @@ class Message(JsonDeserializable): if 'passport_data' in obj: opts['passport_data'] = obj['passport_data'] content_type = 'passport_data' + if 'reply_markup' in obj: + opts['reply_markup'] = InlineKeyboardMarkup.de_json(obj['reply_markup']) + content_type = 'reply_markup' return cls(message_id, from_user, date, chat, content_type, opts, json_string) @classmethod @@ -455,6 +458,7 @@ class Message(JsonDeserializable): self.invoice = None self.successful_payment = None self.connected_website = None + self.reply_markup = None for key in options: setattr(self, key, options[key]) self.json = json_string From cdae65116b92e1d5dbace592588e9a6b436b66e4 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Tue, 1 Sep 2020 18:03:21 +0800 Subject: [PATCH 07/14] feat: make LoginUrl JsonDeserializable feat: make LoginUrl JsonDeserializable, add de_json func --- telebot/types.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index e44d6b5..7d88a06 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1017,12 +1017,23 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): return json_dict -class LoginUrl(Dictionaryable, JsonSerializable): +class LoginUrl(Dictionaryable, JsonSerializable, JsonDeserializable): def __init__(self, url, forward_text=None, bot_username=None, request_write_access=None): self.url = url self.forward_text = forward_text self.bot_username = bot_username self.request_write_access = request_write_access + + @classmethod + def de_json(cls, json_string): + if (json_string is None): + return None + obj = cls.check_json(json_string) + url = obj['url'] + forward_text = obj.get('forward_text') + bot_username = obj.get('bot_username') + request_write_access = obj.get('request_write_access') + return cls(url, forward_text, bot_username, request_write_access) def to_json(self): return json.dumps(self.to_dict()) From 630a9a5b2ca653193de5b3f31672d45995a53fa4 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Tue, 1 Sep 2020 18:07:45 +0800 Subject: [PATCH 08/14] feat: make InlineKeyboardButton JsonDeserializable feat: make InlineKeyboardButton JsonDeserializable, add de_json func to InlineKeyboardButton Object --- telebot/types.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 7d88a06..adf7e18 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1049,7 +1049,7 @@ class LoginUrl(Dictionaryable, JsonSerializable, JsonDeserializable): return json_dict -class InlineKeyboardButton(Dictionaryable, JsonSerializable): +class InlineKeyboardButton(Dictionaryable, JsonSerializable, JsonDeserializable): def __init__(self, text, url=None, callback_data=None, switch_inline_query=None, switch_inline_query_current_chat=None, callback_game=None, pay=None, login_url=None): self.text = text @@ -1060,6 +1060,21 @@ class InlineKeyboardButton(Dictionaryable, JsonSerializable): self.callback_game = callback_game self.pay = pay self.login_url = login_url + + @classmethod + def de_json(cls, json_string): + if (json_string is None): + return None + obj = cls.check_json(json_string) + text = obj['text'] + url = obj.get('url') + callback_data = obj.get('callback_data') + switch_inline_query = obj.get('switch_inline_query') + switch_inline_query_current_chat = obj.get('switch_inline_query_current_chat') + callback_game = obj.get('callback_game') + pay = obj.get('pay') + login_url = LoginUrl.de_json(obj.get('login_url')) + return cls(text, url, callback_data, switch_inline_query, switch_inline_query_current_chat, callback_game, pay, login_url) def to_json(self): return json.dumps(self.to_dict()) From decad450d0e1fa4433f36cfbd465c7d26aee551d Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Tue, 1 Sep 2020 18:13:22 +0800 Subject: [PATCH 09/14] feat: make InlineKeyboardMarkup JsonDeserializable feat: make InlineKeyboardMarkup JsonDeserializable, add de_json func to InlineKeyboardMarkup object --- telebot/types.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index adf7e18..9ae4ccc 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -941,10 +941,18 @@ class KeyboardButtonPollType(Dictionaryable): return {'type': self.type} -class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): +class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable)): max_row_keys = 8 + + @classmethod + def de_json(cls, json_string): + if (json_string is None): + return None + obj = cls.check_json(json_string) + keyboard = [[button for button in row] for row in obj['inline_keyboard']] + return cls(keyboard) - def __init__(self, row_width=3): + def __init__(self, keyboard=[] ,row_width=3): """ This object represents an inline keyboard that appears right next to the message it belongs to. @@ -957,7 +965,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): row_width = self.max_row_keys self.row_width = row_width - self.keyboard = [] + self.keyboard = keyboard def add(self, *args, row_width=None): """ From 32a9e65ecca3781cf067c81251bd9c13a763b5d1 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Wed, 2 Sep 2020 09:12:49 +0800 Subject: [PATCH 10/14] fix: reply_markup does not change content_type --- telebot/types.py | 1 - 1 file changed, 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 9ae4ccc..45181f3 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -387,7 +387,6 @@ class Message(JsonDeserializable): content_type = 'passport_data' if 'reply_markup' in obj: opts['reply_markup'] = InlineKeyboardMarkup.de_json(obj['reply_markup']) - content_type = 'reply_markup' return cls(message_id, from_user, date, chat, content_type, opts, json_string) @classmethod From a803edd09b70e3ff3636e19f2dbd98c6769c6e47 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Wed, 2 Sep 2020 09:25:23 +0800 Subject: [PATCH 11/14] fix: button in markup should be obj, not json text --- telebot/types.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 45181f3..0c9b99e 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -940,7 +940,7 @@ class KeyboardButtonPollType(Dictionaryable): return {'type': self.type} -class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable)): +class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable): max_row_keys = 8 @classmethod @@ -948,7 +948,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable) if (json_string is None): return None obj = cls.check_json(json_string) - keyboard = [[button for button in row] for row in obj['inline_keyboard']] + keyboard = [[InlineKeyboardButton.de_json(button) for button in row] for row in obj['inline_keyboard']] return cls(keyboard) def __init__(self, keyboard=[] ,row_width=3): @@ -990,7 +990,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable) row_width = self.max_row_keys for row in util.chunks(args, row_width): - button_array = [button.to_dict() for button in row] + button_array = [button for button in row] self.keyboard.append(button_array) return self @@ -1020,7 +1020,8 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable) return json.dumps(self.to_dict()) def to_dict(self): - json_dict = {'inline_keyboard': self.keyboard} + json_dict = dict() + json_dict['inline_keyboard'] = [[json.loads(button.to_json()) for button in row] for row in self.keyboard] return json_dict From 698b4371e6d5aca396fe011de3d9b17ceffbe801 Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Wed, 2 Sep 2020 10:33:32 +0800 Subject: [PATCH 12/14] test: Add tests for InlineKeyboardMarkup and ... Add tests for InlineKeyboardMarkup and InlineKeyboardButton --- tests/test_types.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_types.py b/tests/test_types.py index 2f1e698..173cda9 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -17,6 +17,28 @@ def test_json_message(): assert msg.text == 'HIHI' +def test_json_message_with_reply_markup(): + jsonstring = r'{"message_id":48,"from":{"id":153587469,"is_bot":false,"first_name":"Neko","username":"Neko"},"chat":{"id":153587469,"first_name":"Neko","username":"Neko","type":"private"},"date":1598879570,"text":"test","reply_markup":{"inline_keyboard":[[{"text":"Google","url":"http://www.google.com"},{"text":"Yahoo","url":"http://www.yahoo.com"}]]}}' + msg = types.Message.de_json(jsonstring) + assert msg.content_type == 'text' + assert msg.reply_markup.keyboard[0][0].text == 'Google' + + +def test_json_InlineKeyboardMarkup(): + jsonstring = r'{"inline_keyboard":[[{"text":"Google","url":"http://www.google.com"},{"text":"Yahoo","url":"http://www.yahoo.com"}]]}' + markup = types.InlineKeyboardMarkup.de_json(jsonstring) + assert markup.keyboard[0][0].text == 'Google' + assert markup.keyboard[0][1].url == 'http://www.yahoo.com' + + +def test_json_InlineKeyboardButton(): + jsonstring = r'{"text":"Google","url":"http://www.google.com"}' + button = types.InlineKeyboardButton.de_json(jsonstring) + assert button.text == 'Google' + assert button.url == 'http://www.google.com' + + + def test_json_message_with_dice(): jsonstring = r'{"message_id":5560,"from":{"id":879343317,"is_bot":false,"first_name":"George","last_name":"Forse","username":"dr_fxrse","language_code":"ru"},"chat":{"id":879343317,"first_name":"George","last_name":"Forse","username":"dr_fxrse","type":"private"},"date":1586926330,"dice":{"value": 4, "emoji": "\ud83c\udfaf"}}' msg = types.Message.de_json(jsonstring) From 9ab906e60ccbcba7a445d9dac5d4be215cecdd3b Mon Sep 17 00:00:00 2001 From: meoww-bot <14239840+meoww-bot@users.noreply.github.com> Date: Wed, 2 Sep 2020 18:09:14 +0800 Subject: [PATCH 13/14] fix: simplify code json.loads(button.to_json()) equals to button.to_dict() --- telebot/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 0c9b99e..f1b9af0 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1021,7 +1021,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable) def to_dict(self): json_dict = dict() - json_dict['inline_keyboard'] = [[json.loads(button.to_json()) for button in row] for row in self.keyboard] + json_dict['inline_keyboard'] = [[button.to_dict() for button in row] for row in self.keyboard] return json_dict From 3ae145f206eae4ae1c9f3e7838e80fdff54379ff Mon Sep 17 00:00:00 2001 From: FrankWang Date: Thu, 10 Sep 2020 16:22:50 +0800 Subject: [PATCH 14/14] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7953711..fc6e8b0 100644 --- a/README.md +++ b/README.md @@ -663,5 +663,6 @@ Get help. Discuss. Chat. * [RandomInfoBot](https://t.me/RandomInfoBot) by [@Akash](https://github.com/BLUE-DEVIL1134) - A Telegram Bot Which Generates Random Information Of Humans Scraped From Over 13 Websites. * [TasksListsBot](https://t.me/TasksListsBot) ([source](https://github.com/Pablo-Davila/TasksListsBot)) by [@Pablo-Davila](https://github.com/Pablo-Davila) - A (tasks) lists manager bot for Telegram. * [MyElizaPsychologistBot](https://t.me/TasksListsBot) ([source](https://github.com/Pablo-Davila/MyElizaPsychologistBot)) by [@Pablo-Davila](https://github.com/Pablo-Davila) - An implementation of the famous Eliza psychologist chatbot. +* [Evdembot](https://t.me/Evdembot) by Adem Kavak. A bot that informs you about everything you want. Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.