Skip to content

Make RichText Dictionaryable - #2610

Open
Badiboy wants to merge 6 commits into
eternnoir:masterfrom
Badiboy:master
Open

Make RichText Dictionaryable#2610
Badiboy wants to merge 6 commits into
eternnoir:masterfrom
Badiboy:master

Conversation

@Badiboy

@Badiboy Badiboy commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Make RichText Dictionaryable
Conform the fact that RichText can be str or list also.

Address #2609

Make RichText Dictionaryable
Conform the fact that RichText can be str or list also.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds recursive dictionary serialization for rich text values used in outgoing rich messages.

Changes:

  • Makes RichText dictionary-serializable.
  • Serializes strings, lists, and nested rich-text objects.
  • Updates input rich blocks to use recursive serialization.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread telebot/types.py
Comment thread telebot/types.py
@All-The-Foxes

All-The-Foxes commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

It needs the same fix for captions too.

  File "/usr/local/lib/python3.14/dist-packages/telebot/types.py", line 16628, in to_json
    return json.dumps(self.to_dict())
                      ~~~~~~~~~~~~^^
  File "/usr/local/lib/python3.14/dist-packages/telebot/types.py", line 16624, in to_dict
    data['blocks'] = [b.to_dict() for b in self.blocks]
                      ~~~~~~~~~^^
  File "/usr/local/lib/python3.14/dist-packages/telebot/types.py", line 17380, in to_dict
    data['caption'] = self.caption.to_dict()
                      ^^^^^^^^^^^^^^^^^^^^
AttributeError: 'RichBlockCaption' object has no attribute 'to_dict'

@Badiboy

Badiboy commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

I saw RichBlockxxx, but I did not found, where it is used. I'll re-check, thank you.

@All-The-Foxes

Copy link
Copy Markdown
Contributor

It's used in the rich block InputMedia types (InputRichBlockAudio, InputRichBlockPhoto, InputRichBlockVideo, etc). The caption is a RichBlockCaption class and both fields are RichText as well.

@Badiboy

Badiboy commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

RichBlockCaption

Done

@All-The-Foxes

Copy link
Copy Markdown
Contributor
  File "/usr/local/lib/python3.14/dist-packages/telebot/types.py", line 16636, in to_json
    return json.dumps(self.to_dict())
                      ~~~~~~~~~~~~^^
  File "/usr/local/lib/python3.14/dist-packages/telebot/types.py", line 16632, in to_dict
    data['blocks'] = [b.to_dict() for b in self.blocks]
                      ~~~~~~~~~^^
  File "/usr/local/lib/python3.14/dist-packages/telebot/types.py", line 17193, in to_dict
    data['cells'] = [[cell.to_dict() for cell in row] for row in self.cells]
                      ^^^^^^^^^^^^
AttributeError: 'RichBlockTableCell' object has no attribute 'to_dict'

@Badiboy

Badiboy commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

RichBlockTableCell +

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (2)

telebot/types.py:14797

  • The new recursive serialization path has no regression coverage. Please add tests/test_types.py cases for a plain string, a nested list containing a RichText subtype, and a deserialized RichText object passed through an InputRichBlock; these are the failure modes described by issue #2609 and would also catch missing subtype fields.
    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()

telebot/types.py:15762

  • Optional text is currently serialized as null when omitted. InputRichMessage.to_json() dumps this dictionary directly, but the field contract says omission makes the cell invisible and null is not a valid RichText value. Build the required fields first and add text only when it is not None.
            'text': RichText.richtext_to_dict(self.text),

@All-The-Foxes

Copy link
Copy Markdown
Contributor

I did a bunch of testing and everything I tried sending as a rich message seems to work. There's a chance I might have missed something but it seems okay now.

@All-The-Foxes

All-The-Foxes commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

When setting horizontal_accuracy to None in InputRichBlockMap.location, it gets passed to the API as None (I'm guessing). I just took the location received and sent it right back out without modifying it, then got an error.

Edit: Even when I don't set horizontal_accuracy at all I still get the error.

  File "/usr/local/lib/python3.14/dist-packages/telebot/async_telebot.py", line 6310, in send_rich_message
    await asyncio_helper.send_rich_message(
    ...<2 lines>...
        , reply_parameters=reply_parameters, reply_markup=reply_markup)
  File "/usr/local/lib/python3.14/dist-packages/telebot/asyncio_helper.py", line 362, in send_rich_message
    return await _process_request(token, method_url, params=payload, method='post')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.14/dist-packages/telebot/asyncio_helper.py", line 107, in _process_request
    raise e
  File "/usr/local/lib/python3.14/dist-packages/telebot/asyncio_helper.py", line 103, in _process_request
    json_result = await _check_result(url, resp)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.14/dist-packages/telebot/asyncio_helper.py", line 286, in _check_result
    raise ApiTelegramException(method_name, result, result_json)
telebot.asyncio_helper.ApiTelegramException: A request to the Telegram API was unsuccessful. Error code: 400. Description: Bad Request: can't parse InputRichBlock: Field "horizontal_accuracy" must be of type Number

@coder2020official

Copy link
Copy Markdown
Collaborator

InputRichBlockMap.location cannot be none, no?
image

@coder2020official

Copy link
Copy Markdown
Collaborator

A big mess from my side, sorry @Badiboy

@All-The-Foxes

Copy link
Copy Markdown
Contributor

The location is not None, only the horizontal_accuracy of it.

@coder2020official

Copy link
Copy Markdown
Collaborator

I must be drunk sorry

@coder2020official

coder2020official commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator
image

Yeah for some reason there's no traditional if-checking at Location.to_dict

@Badiboy

Badiboy commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

A big mess from my side, sorry @Badiboy

It's not a problem at all. It was a huge update, you made huge work, I made a review. It's normal working process )

@Badiboy

Badiboy commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

When setting horizontal_accuracy to None in InputRichBlockMap.location, it gets passed to the API as None (I'm guessing). I just took the location received and sent it right back out without modifying it, then got an error.

Fixed optional field in Location. It looks like an long-time bug, thank you! )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants