From 5823ca5613e29e28b881693da19301961eeaafb8 Mon Sep 17 00:00:00 2001 From: mrpes <68982655+mrpes@users.noreply.github.com> Date: Sat, 1 Aug 2020 01:28:56 +0500 Subject: [PATCH 1/4] Minor keyboard code redesign --- telebot/types.py | 96 ++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index b2d250e..4b2c8df 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -66,9 +66,9 @@ class JsonDeserializable(object): :param json_type: :return: """ - if isinstance(json_type, dict): + if util.is_dict(json_type): return json_type - elif isinstance(json_type, str): + elif util.is_string(json_type): return json.loads(json_type) else: raise ValueError("json_type should be a json dict or string.") @@ -806,36 +806,44 @@ class ReplyKeyboardRemove(JsonSerializable): class ReplyKeyboardMarkup(JsonSerializable): def __init__(self, resize_keyboard=None, one_time_keyboard=None, selective=None, row_width=3): + if row_width>12: + raise ValueError('Telegram does not support reply keyboard row width over 12') + self.resize_keyboard = resize_keyboard self.one_time_keyboard = one_time_keyboard self.selective = selective self.row_width = row_width self.keyboard = [] - def add(self, *args): + def add(self, *args, row_width=None): """ This function adds strings to the keyboard, while not exceeding row_width. E.g. ReplyKeyboardMarkup#add("A", "B", "C") yields the json result {keyboard: [["A"], ["B"], ["C"]]} when row_width is set to 1. When row_width is set to 2, the following is the result of this function: {keyboard: [["A", "B"], ["C"]]} See https://core.telegram.org/bots/api#replykeyboardmarkup + :raises ValueError: If row_width > 12 :param args: KeyboardButton to append to the keyboard + :param row_width: width of row + :return: self, to allow function chaining. """ - i = 1 - row = [] - for button in args: - if util.is_string(button): - row.append({'text': button}) - elif isinstance(button, bytes): - row.append({'text': button.decode('utf-8')}) - else: - row.append(button.to_dict()) - if i % self.row_width == 0: - self.keyboard.append(row) - row = [] - i += 1 - if len(row) > 0: - self.keyboard.append(row) + row_width = row_width or self.row_width + + if row_width>12: + raise ValueError('Telegram does not support reply keyboard row width over 12') + + for row in util.chunks(args, row_width): + button_array = [] + for button in row: + if util.is_string(button): + button_array.append({'text': button}) + elif util.is_bytes(button): + button_array.append({'text': button.decode('utf-8')}) + else: + button_array.append(button.to_dict()) + self.keyboard.append(button_array) + + return self def row(self, *args): """ @@ -845,14 +853,8 @@ class ReplyKeyboardMarkup(JsonSerializable): :param args: strings :return: self, to allow function chaining. """ - btn_array = [] - for button in args: - if util.is_string(button): - btn_array.append({'text': button}) - else: - btn_array.append(button.to_dict()) - self.keyboard.append(btn_array) - return self + + return self.add(args, 12) def to_json(self): """ @@ -904,13 +906,17 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): """ This object represents an inline keyboard that appears right next to the message it belongs to. - + + :raises ValueError: If row_width > 8 :return: """ + if row_width>8: + raise ValueError('Telegram does not support inline keyboard row width over 8') + self.row_width = row_width self.keyboard = [] - def add(self, *args): + def add(self, *args, row_width=None): """ This method adds buttons to the keyboard without exceeding row_width. @@ -920,20 +926,23 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): When row_width is set to 2, the result: {keyboard: [["A", "B"], ["C"]]} See https://core.telegram.org/bots/api#inlinekeyboardmarkup - + + :raises ValueError: If row_width > 8 :param args: Array of InlineKeyboardButton to append to the keyboard + :param row_width: width of row + :return: self, to allow function chaining. """ - i = 1 - row = [] - for button in args: - row.append(button.to_dict()) - if i % self.row_width == 0: - self.keyboard.append(row) - row = [] - i += 1 - if len(row) > 0: - self.keyboard.append(row) - + row_width = row_width or self.row_width + + if row_width>8: + raise ValueError('Telegram does not support inline keyboard row width over 8') + + for row in util.chunks(args, row_width): + button_array = [button.to_dict() for button in row] + self.keyboard.append(button_array) + + return self + def row(self, *args): """ Adds a list of InlineKeyboardButton to the keyboard. @@ -942,13 +951,12 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): InlineKeyboardMarkup.row("A").row("B", "C").to_json() outputs: '{keyboard: [["A"], ["B", "C"]]}' See https://core.telegram.org/bots/api#inlinekeyboardmarkup - + :param args: Array of InlineKeyboardButton to append to the keyboard :return: self, to allow function chaining. """ - button_array = [button.to_dict() for button in args] - self.keyboard.append(button_array) - return self + + return self.add(args, 8) def to_json(self): """ From 317a490cf04ea5fe0a6a0ff675ee62c590b82ed6 Mon Sep 17 00:00:00 2001 From: mrpes <68982655+mrpes@users.noreply.github.com> Date: Sat, 1 Aug 2020 01:30:38 +0500 Subject: [PATCH 2/4] Type checking moved to utils --- telebot/util.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/telebot/util.py b/telebot/util.py index b4589d4..7612ec4 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -166,6 +166,12 @@ def async_dec(): def is_string(var): return isinstance(var, string_types) +def is_dict(var): + return isinstance(var, dict) + +def is_bytes(var): + return isinstance(var, bytes) + def is_pil_image(var): return pil_imported and isinstance(var, PIL.Image.Image) @@ -278,6 +284,11 @@ def per_thread(key, construct_value, reset=False): return getattr(thread_local, key) +def chunks(lst, n): + """Yield successive n-sized chunks from lst.""" + # https://stackoverflow.com/a/312464/9935473 + for i in range(0, len(lst), n): + yield lst[i:i + n] def generate_random_token(): return ''.join(random.sample(string.ascii_letters, 16)) From 4e5fb59fc01dc50b64730f861ed5a21c06d57400 Mon Sep 17 00:00:00 2001 From: "Mr. Dog" <68982655+mrpes@users.noreply.github.com> Date: Sun, 2 Aug 2020 20:20:33 +0500 Subject: [PATCH 3/4] Replace exceptions with warnings Also further PIL support added --- telebot/types.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 4b2c8df..4e33277 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +import logging + try: import ujson as json except ImportError: @@ -9,6 +11,7 @@ import six from telebot import util +logger = logging.getLogger('TeleBot') class JsonSerializable(object): """ @@ -807,7 +810,8 @@ class ReplyKeyboardRemove(JsonSerializable): class ReplyKeyboardMarkup(JsonSerializable): def __init__(self, resize_keyboard=None, one_time_keyboard=None, selective=None, row_width=3): if row_width>12: - raise ValueError('Telegram does not support reply keyboard row width over 12') + logger.warning('Telegram does not support reply keyboard row width over 12') + row_width=12 self.resize_keyboard = resize_keyboard self.one_time_keyboard = one_time_keyboard @@ -822,15 +826,16 @@ class ReplyKeyboardMarkup(JsonSerializable): when row_width is set to 1. When row_width is set to 2, the following is the result of this function: {keyboard: [["A", "B"], ["C"]]} See https://core.telegram.org/bots/api#replykeyboardmarkup - :raises ValueError: If row_width > 12 :param args: KeyboardButton to append to the keyboard :param row_width: width of row :return: self, to allow function chaining. """ row_width = row_width or self.row_width + if row_width>12: - raise ValueError('Telegram does not support reply keyboard row width over 12') + logger.warning('Telegram does not support reply keyboard row width over 12') + row_width=12 for row in util.chunks(args, row_width): button_array = [] @@ -907,12 +912,12 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): This object represents an inline keyboard that appears right next to the message it belongs to. - :raises ValueError: If row_width > 8 :return: """ if row_width>8: - raise ValueError('Telegram does not support inline keyboard row width over 8') - + logger.warning('Telegram does not support inline keyboard row width over 8') + row_width=8 + self.row_width = row_width self.keyboard = [] @@ -927,7 +932,6 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): {keyboard: [["A", "B"], ["C"]]} See https://core.telegram.org/bots/api#inlinekeyboardmarkup - :raises ValueError: If row_width > 8 :param args: Array of InlineKeyboardButton to append to the keyboard :param row_width: width of row :return: self, to allow function chaining. @@ -935,7 +939,8 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable): row_width = row_width or self.row_width if row_width>8: - raise ValueError('Telegram does not support inline keyboard row width over 8') + logger.warning('Telegram does not support inline keyboard row width over 8') + row_width=8 for row in util.chunks(args, row_width): button_array = [button.to_dict() for button in row] @@ -2299,6 +2304,9 @@ class InputMedia(Dictionaryable, JsonSerializable): class InputMediaPhoto(InputMedia): def __init__(self, media, caption=None, parse_mode=None): + if util.is_pil_image(media): + media = util.pil_image_to_file(media) + super(InputMediaPhoto, self).__init__(type="photo", media=media, caption=caption, parse_mode=parse_mode) def to_dict(self): From 1ba093cb02f40168afe61161a05d1908620c5414 Mon Sep 17 00:00:00 2001 From: "Mr. Dog" <68982655+mrpes@users.noreply.github.com> Date: Sun, 2 Aug 2020 20:30:58 +0500 Subject: [PATCH 4/4] Change logger level to warning --- telebot/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 44119ba..ce41c6d 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -18,7 +18,7 @@ console_output_handler = logging.StreamHandler(sys.stderr) console_output_handler.setFormatter(formatter) logger.addHandler(console_output_handler) -logger.setLevel(logging.ERROR) +logger.setLevel(logging.WARNING) from telebot import apihelper, types, util from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend