Skip to content

fix(formatting): make date_time entities work and escape attribute values - #2649

Merged
Badiboy merged 3 commits into
eternnoir:masterfrom
beduldul:fix/apply-html-entities-date-time
Oct 31, 2026
Merged

Badiboy merged 3 commits into
eternnoir:masterfrom
beduldul:fix/apply-html-entities-date-time

Conversation

@beduldul

Copy link
Copy Markdown
Contributor

Description

Three bugs in apply_html_entities, all in the same format_entity branch.

date_time raises. The template declares {unix_time}, but the call formats it with unix=, so the lookup fails:

>>> apply_html_entities("Meeting at 10:00", [entity])
KeyError: 'unix_time'

This reaches users through Message.html_text, so any message with a date_time entity (added in #2570) crashes. It looks like the entity has never worked.

text_link URL is interpolated raw. A URL containing a quote produces broken HTML:

>>> apply_html_entities("link rest", [entity])
'<a href="https://x.test/?a="b">link</a>'

pre language is interpolated raw. Same problem, and it can add attributes:

>>> apply_html_entities("code rest", [entity])
'<pre><code class="language-py" onload="x">code</code></pre>'

hlink and hpre already pass both through escape_html, so this just makes the entity path consistent with them.

Describe your tests

Added four tests to tests/test_formatting.py, reusing the AttributeCollector parser helper that is already there. They assert the date_time output exactly, and feed the link and pre output through an HTML parser to prove no extra attributes appear.

The existing test_apply_html_entities is an integration test that sends real messages, so it never runs without a bot token — these are the first unit tests for this function.

Full suite: 317 passed, 73 skipped.

Python version: 3.12.3

OS: macOS 27.2

Checklist:

  • I added/edited example on new feature/change (if exists)
  • My changes won't break backward compatibility
  • I made changes both for sync and async

…tract_arguments

smart_split compared with `<`, so text whose length is an exact multiple of
chars_per_string went through the split path one last time on the remainder and
appended ''. smart_split("abc", 3) returned ["abc", ""], and sending that empty
part to Telegram fails with "message text is empty".

extract_arguments compiled its regexp and matched before looking at None, so a
non-text message raised TypeError on message.text. is_command and
extract_command already tolerate None, so this now matches them.
…lues

apply_html_entities formatted the date_time template with unix=, but the
template declares {unix_time}, so any message carrying a date_time entity
raised KeyError: 'unix_time' from .html_text. The entity was added in eternnoir#2570
and has never worked.

The text_link URL and the pre language were also interpolated raw. hlink and
hpre already escape both, so a URL or language containing a quote produced
broken HTML and could add attributes.

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.

🟡 Changes recommended

The formatting keyword rename breaks existing custom templates using {unix}, causing KeyError unless both unix and unix_time are supported.

1 open issue
What changed in this PR

This PR fixes HTML entity rendering in the shared formatting layer, including the date_time failure introduced with its support in #2570. It also addresses two utility edge cases.

Changes:

  • Fix the date_time template keyword and escape link URLs and code-language attributes.
  • Handle None in argument extraction and prevent trailing empty chunks in smart_split.
  • Add focused regression tests for formatting and utility behavior.
File Description
tests/​test_util.py Adds splitting and argument-extraction regression tests.
tests/​test_formatting.py Tests date-time rendering, attribute escaping, and content escaping.
telebot/​util.py Handles missing text and exact-length chunk boundaries.
telebot/​formatting.py Fixes date-time formatting and escapes HTML attribute values.

Review effort: Balanced

Comment thread telebot/formatting.py Resolved
Comment thread telebot/util.py
:rtype: :obj:`str` or :obj:`None`
"""
regexp = re.compile(r"/\w*(@\w*)*\s*([\s\S]*)", re.IGNORECASE)
if text is None: return None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I propose to move it before "re.compile" because compile bacame useless.

Formatting the date_time template with unix_time= broke custom submissions that
were written against the old {unix} placeholder, raising KeyError: 'unix'. Pass
both names so existing templates keep working.

extract_arguments also compiled its regexp before the None check, so the
compile was wasted on the early return. Move it below.
@beduldul

Copy link
Copy Markdown
Contributor Author

Good catch on the {unix} regression. Fixed in 5988ec8: the template is now formatted with both unix and unix_time, so custom submissions written against the old placeholder keep working. There is a regression test that fails with KeyError: 'unix' without the fix.

Also moved the re.compile in extract_arguments below the None check as Badiboy suggested, so it is not compiled on the early return.

Full suite: 319 passed, 72 skipped.

@Badiboy
Badiboy merged commit f16ba49 into eternnoir:master Oct 31, 2026
7 checks passed
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.

3 participants