From 91ffcd099e747d0b5add955d6458afeb8818247f Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 9 Aug 2026 16:06:51 +0300 Subject: [PATCH 1/6] Make RichText Dictionaryable Make RichText Dictionaryable Conform the fact that RichText can be str or list also. --- telebot/types.py | 206 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 188 insertions(+), 18 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 1089d111b..1bab43194 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -14679,7 +14679,7 @@ def de_json(cls, json_string): return cls(**obj) -class RichText(JsonDeserializable): +class RichText(JsonDeserializable, Dictionaryable): """ This object represents a rich formatted text. Currently, it can be either a String for plain text, an Array of :class:`RichText`, or any of the following types: @@ -14721,9 +14721,12 @@ def __init__(self, type: str, **kwargs): def de_json(cls, json_string): if json_string is None: return None if isinstance(json_string, str): + # "...can be either a String for plain text..." return json_string if isinstance(json_string, list): + # "...an Array of :class:`RichText`..." return [RichText.de_json(item) for item in json_string] + # "...or any of the following types..." obj = cls.check_json(json_string) type = obj.pop('type', None) if type == 'bold': @@ -14777,7 +14780,24 @@ def de_json(cls, json_string): elif type == 'reference_link': return RichTextReferenceLink.de_json(obj) return None - + + def to_dict(self): + data = { + 'type': self.type + } + return data + + @staticmethod + def richtext_to_dict(richtext: Union[str, List[RichText], RichText]): + if isinstance(richtext, str): + return richtext + elif isinstance(richtext, list): + return [RichText.richtext_to_dict(item) for item in richtext] + elif isinstance(richtext, RichText): + return richtext.to_dict() + return None + + class RichTextBold(RichText): """ A bold text. @@ -14804,6 +14824,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextItalic(RichText): """ An italicized text. @@ -14830,6 +14856,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextUnderline(RichText): """ An underlined text. @@ -14856,6 +14888,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextStrikethrough(RichText): """ A strikethrough text. @@ -14882,6 +14920,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextSpoiler(RichText): """ A text covered by a spoiler. @@ -14908,6 +14952,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextDateTime(RichText): """ Formatted date and time. @@ -14942,6 +14992,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextTextMention(RichText): """ A mention of a Telegram user by their identifier. @@ -14973,6 +15029,12 @@ def de_json(cls, json_string): obj['user'] = User.de_json(obj['user']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['user'] = self.user.to_dict() + return data + class RichTextSubscript(RichText): """ @@ -15000,6 +15062,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextSuperscript(RichText): """ A superscript text. @@ -15026,6 +15094,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextMarked(RichText): """ A marked text. @@ -15052,6 +15126,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextCode(RichText): """ A monowidth text. @@ -15078,6 +15158,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + return data + + class RichTextCustomEmoji(RichText): """ A custom emoji. @@ -15107,6 +15193,13 @@ def de_json(cls, json_string): obj = cls.check_json(json_string) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['custom_emoji_id'] = self.custom_emoji_id + data['alternative_text'] = self.alternative_text + return data + + class RichTextMathematicalExpression(RichText): """ A mathematical expression. @@ -15132,6 +15225,12 @@ def de_json(cls, json_string): obj = cls.check_json(json_string) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['expression'] = self.expression + return data + + class RichTextUrl(RichText): """ A text with a link. @@ -15162,6 +15261,13 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['url'] = self.url + return data + + class RichTextEmailAddress(RichText): """ A text with an email address. @@ -15192,6 +15298,13 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['email_address'] = self.email_address + return data + + class RichTextPhoneNumber(RichText): """ A text with a phone number. @@ -15222,6 +15335,13 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['phone_number'] = self.phone_number + return data + + class RichTextBankCardNumber(RichText): """ A text with a bank card number. @@ -15252,6 +15372,13 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['bank_card_number'] = self.bank_card_number + return data + + class RichTextMention(RichText): """ A mention by a username. @@ -15270,7 +15397,6 @@ class RichTextMention(RichText): :return: Instance of the class :rtype: :class:`RichTextMention` """ - def __init__(self, text: RichText, username: str, **kwargs): super().__init__(type='mention', **kwargs) self.text: RichText = text @@ -15283,6 +15409,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['username'] = self.username + return data + class RichTextHashtag(RichText): """ @@ -15314,6 +15446,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['hashtag'] = self.hashtag + return data + class RichTextCashtag(RichText): """ @@ -15345,6 +15483,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['cashtag'] = self.cashtag + return data + class RichTextBotCommand(RichText): """ @@ -15376,6 +15520,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['bot_command'] = self.bot_command + return data + class RichTextAnchor(RichText): """ @@ -15402,6 +15552,11 @@ def de_json(cls, json_string): obj = cls.check_json(json_string) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['name'] = self.name + return data + class RichTextAnchorLink(RichText): """ @@ -15432,7 +15587,13 @@ def de_json(cls, json_string): obj = cls.check_json(json_string) obj['text'] = RichText.de_json(obj['text']) return cls(**obj) - + + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['anchor_name'] = self.anchor_name + return data + class RichTextReference(RichText): """ @@ -15452,7 +15613,6 @@ class RichTextReference(RichText): :return: Instance of the class :rtype: :class:`RichTextReference` """ - def __init__(self, text: RichText, name: str, **kwargs): super().__init__(type='reference', **kwargs) self.text: RichText = text @@ -15464,7 +15624,13 @@ def de_json(cls, json_string): obj = cls.check_json(json_string) obj['text'] = RichText.de_json(obj['text']) return cls(**obj) - + + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['name'] = self.name + return data + class RichTextReferenceLink(RichText): """ @@ -15483,9 +15649,7 @@ class RichTextReferenceLink(RichText): :return: Instance of the class :rtype: :class:`RichTextReferenceLink` - """ - def __init__(self, text: RichText, reference_name: str, **kwargs): super().__init__(type='reference_link', **kwargs) self.text: RichText = text @@ -15498,6 +15662,12 @@ def de_json(cls, json_string): obj['text'] = RichText.de_json(obj['text']) return cls(**obj) + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + data['reference_name'] = self.reference_name + return data + class RichBlockCaption(JsonDeserializable): """ @@ -16664,7 +16834,7 @@ def __init__(self, text: RichText, **kwargs): def to_dict(self) -> dict: data = super().to_dict() - data['text'] = self.text.to_dict() + data['text'] = RichText.richtext_to_dict(self.text) return data @@ -16693,7 +16863,7 @@ def __init__(self, text: RichText, size: int, **kwargs): def to_dict(self) -> dict: data = super().to_dict() - data['text'] = self.text.to_dict() + data['text'] = RichText.richtext_to_dict(self.text) data['size'] = self.size return data @@ -16723,7 +16893,7 @@ def __init__(self, text: RichText, language: Optional[str] = None, **kwargs): def to_dict(self) -> dict: data = super().to_dict() - data['text'] = self.text.to_dict() + data['text'] = RichText.richtext_to_dict(self.text) if self.language is not None: data['language'] = self.language return data @@ -16750,7 +16920,7 @@ def __init__(self, text: RichText, **kwargs): def to_dict(self) -> dict: data = super().to_dict() - data['text'] = self.text.to_dict() + data['text'] = RichText.richtext_to_dict(self.text) return data @@ -16873,7 +17043,7 @@ def to_dict(self) -> dict: data = super().to_dict() data['blocks'] = [block.to_dict() for block in self.blocks] if self.credit is not None: - data['credit'] = self.credit.to_dict() + data['credit'] = RichText.richtext_to_dict(self.credit) return data @@ -16902,9 +17072,9 @@ def __init__(self, text: RichText, credit: Optional[RichText] = None, **kwargs): def to_dict(self) -> dict: data = super().to_dict() - data['text'] = self.text.to_dict() + data['text'] = RichText.richtext_to_dict(self.text) if self.credit is not None: - data['credit'] = self.credit.to_dict() + data['credit'] = RichText.richtext_to_dict(self.credit) return data @@ -17016,7 +17186,7 @@ def to_dict(self) -> dict: if self.is_striped is not None: data['is_striped'] = self.is_striped if self.caption is not None: - data['caption'] = self.caption.to_dict() + data['caption'] = RichText.richtext_to_dict(self.caption) return data @@ -17055,7 +17225,7 @@ def __init__( def to_dict(self) -> dict: data = super().to_dict() - data['summary'] = self.summary.to_dict() + data['summary'] = RichText.richtext_to_dict(self.summary) data['blocks'] = [block.to_dict() for block in self.blocks] if self.is_open is not None: data['is_open'] = self.is_open @@ -17292,7 +17462,7 @@ def __init__(self, text: RichText, **kwargs): def to_dict(self) -> dict: data = super().to_dict() - data['text'] = self.text.to_dict() + data['text'] = RichText.richtext_to_dict(self.text) return data From d89ba0c27237fa76ead20e48c641b53069a6c042 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 9 Aug 2026 16:11:27 +0300 Subject: [PATCH 2/6] Fix for RichTextDateTime --- telebot/types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telebot/types.py b/telebot/types.py index 1bab43194..910c253b6 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -14995,6 +14995,8 @@ def de_json(cls, json_string): def to_dict(self): data = super().to_dict() data['text'] = RichText.richtext_to_dict(self.text) + data['unix_time'] = self.unix_time + data['date_time_format'] = self.date_time_format return data From 5528eda28cde466d114518847d4a2128ead69045 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 9 Aug 2026 16:56:25 +0300 Subject: [PATCH 3/6] RichBlockCaption made Dictionaryable --- telebot/types.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 910c253b6..1d443714b 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -15671,7 +15671,7 @@ def to_dict(self): return data -class RichBlockCaption(JsonDeserializable): +class RichBlockCaption(JsonDeserializable, Dictionaryable): """ This object represents the caption of a rich formatted block. @@ -15701,6 +15701,14 @@ def de_json(cls, json_string): obj['credit'] = RichText.de_json(obj['credit']) return cls(**obj) + def to_dict(self): + data = { + 'text': RichText.richtext_to_dict(self.text), + } + if self.credit is not None: + data['credit'] = RichText.richtext_to_dict(self.credit) + return data + class RichBlockTableCell(JsonDeserializable): """ From be32cfd83b4a7a7ff33c2974472bd20793cd95b6 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 9 Aug 2026 17:45:23 +0300 Subject: [PATCH 4/6] RichBlockTableCell to Dictionaryable --- telebot/types.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 1d443714b..c3e68b4ed 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -15710,7 +15710,7 @@ def to_dict(self): return data -class RichBlockTableCell(JsonDeserializable): +class RichBlockTableCell(JsonDeserializable, Dictionaryable): """ This object represents a cell of a table. @@ -15753,7 +15753,21 @@ def de_json(cls, json_string): if 'text' in obj: obj['text'] = RichText.de_json(obj['text']) return cls(**obj) - + + def to_dict(self): + data = { + 'text': RichText.richtext_to_dict(self.text), + 'align': self.align, + 'valign': self.valign, + } + if self.is_header is not None: + data['is_header'] = self.is_header + if self.colspan is not None: + data['colspan'] = self.colspan + if self.rowspan is not None: + data['rowspan'] = self.rowspan + return data + class RichBlockListItem(JsonDeserializable): """ @@ -16697,9 +16711,9 @@ def to_dict(self) -> dict: if self.duration is not None: data['duration'] = self.duration return data - -class InputRichMessageMedia(Dictionaryable): + +class InputRichMessageMedia(Dictionaryable, JsonSerializable): """ This object represents a media element embedded in an outgoing rich message. @@ -16725,12 +16739,12 @@ def to_dict(self) -> dict: 'media': self.media.to_dict() } return data - + def to_json(self) -> str: return json.dumps(self.to_dict()) - -class InputRichBlockListItem(Dictionaryable): + +class InputRichBlockListItem(Dictionaryable, JsonSerializable): """ An item of a list to be sent. @@ -16780,6 +16794,7 @@ def to_dict(self) -> dict: def to_json(self) -> str: return json.dumps(self.to_dict()) + class InputRichBlock(Dictionaryable, JsonSerializable): """ This object represents a block in a rich formatted message to be sent. From cb9b9bcee4a43a638fdc066674503a12b30d4529 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 9 Aug 2026 19:04:06 +0300 Subject: [PATCH 5/6] RichBlockTableCell fix --- telebot/types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index c3e68b4ed..91a704e01 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -15756,10 +15756,11 @@ def de_json(cls, json_string): def to_dict(self): data = { - 'text': RichText.richtext_to_dict(self.text), 'align': self.align, 'valign': self.valign, } + if self.text is not None: + data['text'] = RichText.richtext_to_dict(self.text) if self.is_header is not None: data['is_header'] = self.is_header if self.colspan is not None: From 427e8953f001bb1b9f22e3c6a276c3f3e54a5f9c Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 9 Aug 2026 21:40:42 +0300 Subject: [PATCH 6/6] location-s optional parameters fix --- telebot/types.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 91a704e01..f67afed7d 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -2526,14 +2526,19 @@ def to_json(self): return json.dumps(self.to_dict()) def to_dict(self): - return { + data = { "longitude": self.longitude, "latitude": self.latitude, - "horizontal_accuracy": self.horizontal_accuracy, - "live_period": self.live_period, - "heading": self.heading, - "proximity_alert_radius": self.proximity_alert_radius, } + if self.horizontal_accuracy is not None: + data["horizontal_accuracy"] = self.horizontal_accuracy + if self.live_period is not None: + data["live_period"] = self.live_period + if self.heading is not None: + data["heading"] = self.heading + if self.proximity_alert_radius is not None: + data["proximity_alert_radius"] = self.proximity_alert_radius + return data class Venue(JsonDeserializable): @@ -4454,14 +4459,17 @@ def __init__(self, latitude, longitude, horizontal_accuracy=None, live_period=No self.proximity_alert_radius: Optional[int] = proximity_alert_radius def to_dict(self): - json_dict = {'latitude': self.latitude, 'longitude': self.longitude} - if self.horizontal_accuracy: + json_dict = { + 'latitude': self.latitude, + 'longitude': self.longitude + } + if self.horizontal_accuracy is not None: json_dict['horizontal_accuracy'] = self.horizontal_accuracy - if self.live_period: + if self.live_period is not None: json_dict['live_period'] = self.live_period - if self.heading: + if self.heading is not None: json_dict['heading'] = self.heading - if self.proximity_alert_radius: + if self.proximity_alert_radius is not None: json_dict['proximity_alert_radius'] = self.proximity_alert_radius return json_dict @@ -5665,19 +5673,19 @@ def to_dict(self): json_dict = super().to_dict() json_dict['latitude'] = self.latitude json_dict['longitude'] = self.longitude - if self.horizontal_accuracy: + if self.horizontal_accuracy is not None: json_dict['horizontal_accuracy'] = self.horizontal_accuracy - if self.live_period: + if self.live_period is not None: json_dict['live_period'] = self.live_period - if self.heading: + if self.heading is not None: json_dict['heading'] = self.heading - if self.proximity_alert_radius: + if self.proximity_alert_radius is not None: json_dict['proximity_alert_radius'] = self.proximity_alert_radius if self.thumbnail_url: json_dict['thumbnail_url'] = self.thumbnail_url - if self.thumbnail_width: + if self.thumbnail_width is not None: json_dict['thumbnail_width'] = self.thumbnail_width - if self.thumbnail_height: + if self.thumbnail_height is not None: json_dict['thumbnail_height'] = self.thumbnail_height return json_dict