telegramify-markdown 1.4.0__tar.gz → 1.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/PKG-INFO +1 -1
  2. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/pyproject.toml +1 -1
  3. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/config.py +1 -1
  4. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/converter.py +4 -2
  5. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/rich.py +4 -1
  6. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_converter.py +30 -2
  7. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_rich.py +15 -2
  8. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/LICENSE +0 -0
  9. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/README.md +0 -0
  10. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/__init__.py +0 -0
  11. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/code_file.py +0 -0
  12. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/content.py +0 -0
  13. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/entity.py +0 -0
  14. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/latex_escape/__init__.py +0 -0
  15. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/latex_escape/const.py +0 -0
  16. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/latex_escape/helper.py +0 -0
  17. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/logger.py +0 -0
  18. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/mdv2.py +0 -0
  19. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/mermaid.py +0 -0
  20. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/pipeline.py +0 -0
  21. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/py.typed +0 -0
  22. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/stream/__init__.py +0 -0
  23. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/stream/core.py +0 -0
  24. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/stream/draft.py +0 -0
  25. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/stream/edit.py +0 -0
  26. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/type.py +0 -0
  27. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/src/telegramify_markdown/word_count.py +0 -0
  28. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/exp1.md +0 -0
  29. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/exp2.md +0 -0
  30. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/send_showcase.py +0 -0
  31. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/showcase_latex.py +0 -0
  32. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_entity.py +0 -0
  33. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_mdv2.py +0 -0
  34. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_mermaid.py +0 -0
  35. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_performance.py +0 -0
  36. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_pipeline.py +0 -0
  37. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_server.py +0 -0
  38. {telegramify_markdown-1.4.0 → telegramify_markdown-1.4.2}/tests/test_stream.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: telegramify-markdown
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Convert Markdown to Telegram plain text + MessageEntity pairs
5
5
  Author-Email: sudoskys <coldlando@hotmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "telegramify-markdown"
3
- version = "1.4.0"
3
+ version = "1.4.2"
4
4
  description = "Convert Markdown to Telegram plain text + MessageEntity pairs"
5
5
  authors = [
6
6
  { name = "sudoskys", email = "coldlando@hotmail.com" },
@@ -28,7 +28,7 @@ class Symbol:
28
28
  self.image: str = "\N{FRAME WITH PICTURE}" # 🖼
29
29
  self.link: str = "\N{LINK SYMBOL}" # 🔗
30
30
  self.task_completed: str = "\N{WHITE HEAVY CHECK MARK}" # ✅
31
- self.task_uncompleted: str = "\N{BALLOT BOX WITH CHECK}" # ☑️
31
+ self.task_uncompleted: str = "\N{BALLOT BOX}" # ☐
32
32
  self.horizontal_rule: str = "————————"
33
33
  # List markers: written after the indent, before the item text.
34
34
  # Always plain text, never covered by an entity.
@@ -171,10 +171,12 @@ def _parse(
171
171
  """
172
172
  text = _escape_latex(markdown) if latex_escape else markdown
173
173
  text = _preprocess_spoilers(text, options)
174
- events = pyromark.events_with_range(text, options=options)
174
+ # pyromark >= 0.10 returns a one-shot iterator; materialize it so the
175
+ # delimiter scan and EventWalker can both iterate.
176
+ events = tuple(pyromark.events_with_range(text, options=options))
175
177
  while offsets := _literal_delimiters(text, events):
176
178
  text = _escape_at(text, offsets)
177
- events = pyromark.events_with_range(text, options=options)
179
+ events = tuple(pyromark.events_with_range(text, options=options))
178
180
  return text, events
179
181
 
180
182
 
@@ -179,7 +179,10 @@ class _RichHtmlWalker:
179
179
  elif "Html" in event:
180
180
  self._write_inline(self._escape_text(event["Html"]))
181
181
  elif "TaskListMarker" in event:
182
- self._write_inline("✅ " if event["TaskListMarker"] else "☑ ")
182
+ # Native Rich HTML checkbox; _emit (not _write_inline) keeps it a
183
+ # direct child of <li> even when a loose item opens a <p>.
184
+ checked = " checked" if event["TaskListMarker"] else ""
185
+ self._emit(f'<input type="checkbox"{checked}/>')
183
186
  elif "FootnoteReference" in event:
184
187
  ref = str(event["FootnoteReference"])
185
188
  href = self._escape_attr(f"#{ref}")
@@ -1,4 +1,5 @@
1
1
  import unittest
2
+ from unittest import mock
2
3
 
3
4
  from telegramify_markdown.converter import convert, convert_with_segments
4
5
  from telegramify_markdown.entity import MessageEntity, utf16_len
@@ -244,7 +245,8 @@ class ListTest(unittest.TestCase):
244
245
  md = "- [x] done\n- [ ] todo"
245
246
  text, entities = convert(md, latex_escape=False)
246
247
  self.assertIn("✅", text)
247
- self.assertIn("☑", text)
248
+ self.assertIn("☐", text)
249
+ self.assertNotIn("☑", text)
248
250
 
249
251
 
250
252
  class SpoilerTest(unittest.TestCase):
@@ -745,7 +747,7 @@ class TaskListMarkerTest(unittest.TestCase):
745
747
  def test_no_redundant_bullet(self):
746
748
  text, _ = convert("- [ ] todo", latex_escape=False)
747
749
  self.assertNotIn("⦁", text) # 无 bullet
748
- self.assertIn("☑", text) # task marker 存在
750
+ self.assertIn("☐", text) # task marker 存在
749
751
 
750
752
  def test_completed_task(self):
751
753
  text, _ = convert("- [x] done", latex_escape=False)
@@ -1074,5 +1076,31 @@ class RenderConfigIsolationTest(unittest.TestCase):
1074
1076
  self.assertEqual(rendered["b"], "• item")
1075
1077
 
1076
1078
 
1079
+ class EventsIteratorTest(unittest.TestCase):
1080
+ """pyromark >= 0.10 returns a one-shot iterator from events_with_range;
1081
+ _parse must materialize it so both the delimiter scan and EventWalker
1082
+ can iterate (issue #129: empty output for text with ~ or $)."""
1083
+
1084
+ def test_convert_with_one_shot_events_iterator(self):
1085
+ import pyromark
1086
+
1087
+ from telegramify_markdown import converter
1088
+
1089
+ real = pyromark.events_with_range
1090
+
1091
+ def one_shot(text, *, options):
1092
+ return iter(real(text, options=options))
1093
+
1094
+ with mock.patch.object(
1095
+ converter.pyromark, "events_with_range", one_shot
1096
+ ):
1097
+ for markdown in ("Hiii~", "A cookie for $2?", r"Hiii\~"):
1098
+ with self.subTest(markdown=markdown):
1099
+ text, _ = convert(markdown, latex_escape=False)
1100
+ expected = markdown.replace("\\", "")
1101
+ self.assertNotEqual(text, "")
1102
+ self.assertIn(expected, text)
1103
+
1104
+
1077
1105
  if __name__ == "__main__":
1078
1106
  unittest.main()
@@ -76,8 +76,21 @@ class RichifyHtmlTest(unittest.TestCase):
76
76
  self.assertEqual(rich.html, "<tg-math-block>E = mc^2</tg-math-block>")
77
77
 
78
78
  def test_lists_and_task_markers(self):
79
- rich = richify("- [x] done\n- item")
80
- self.assertEqual(rich.html, "<ul><li>✅ done</li><li>item</li></ul>")
79
+ rich = richify("- [x] done\n- [ ] open\n- item")
80
+ self.assertEqual(
81
+ rich.html,
82
+ '<ul><li><input type="checkbox" checked/>done</li>'
83
+ '<li><input type="checkbox"/>open</li>'
84
+ "<li>item</li></ul>",
85
+ )
86
+
87
+ def test_loose_task_list_keeps_checkbox_directly_in_item(self):
88
+ rich = richify("- [ ] a\n\n- [x] b")
89
+ self.assertEqual(
90
+ rich.html,
91
+ '<ul><li><input type="checkbox"/><p>a</p></li>'
92
+ '<li><input type="checkbox" checked/><p>b</p></li></ul>',
93
+ )
81
94
 
82
95
  def test_ordered_list_start(self):
83
96
  rich = richify("3. three\n4. four")