telekit 2.0.1a0__tar.gz → 2.2.0__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 (75) hide show
  1. telekit-2.2.0/PKG-INFO +432 -0
  2. telekit-2.2.0/README.md +341 -0
  3. {telekit-2.0.1a0 → telekit-2.2.0}/setup.py +1 -1
  4. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/__init__.py +2 -0
  5. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_buildtext/styles.py +9 -24
  6. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_chain.py +3 -5
  7. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_chain_base.py +20 -17
  8. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_chain_entry_logic.py +12 -0
  9. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_chain_inline_keyboards_logic.py +43 -22
  10. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_handler.py +2 -2
  11. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_inline_buttons.py +251 -10
  12. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_logger.py +29 -28
  13. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_on.py +84 -70
  14. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/mixin.py +17 -5
  15. telekit-2.2.0/telekit/_user.py +199 -0
  16. telekit-2.2.0/telekit/_version.py +6 -0
  17. telekit-2.2.0/telekit/dices.py +390 -0
  18. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/__init__.py +2 -1
  19. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/complete_hotel.py +10 -13
  20. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/counter.py +3 -0
  21. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/entry.py +1 -3
  22. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/on_text.py +2 -0
  23. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/pages.py +12 -5
  24. telekit-2.2.0/telekit/example/example_handlers/qr.py +86 -0
  25. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/quiz.py +1 -1
  26. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/spells.py +3 -3
  27. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/start.py +5 -1
  28. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/inline_buttons.py +8 -0
  29. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/senders.py +686 -152
  30. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/types.py +45 -28
  31. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/utils.py +166 -1
  32. telekit-2.2.0/telekit.egg-info/PKG-INFO +432 -0
  33. {telekit-2.0.1a0 → telekit-2.2.0}/telekit.egg-info/SOURCES.txt +2 -0
  34. telekit-2.0.1a0/PKG-INFO +0 -479
  35. telekit-2.0.1a0/README.md +0 -375
  36. telekit-2.0.1a0/telekit/_user.py +0 -138
  37. telekit-2.0.1a0/telekit/_version.py +0 -1
  38. telekit-2.0.1a0/telekit.egg-info/PKG-INFO +0 -479
  39. {telekit-2.0.1a0 → telekit-2.2.0}/LICENSE +0 -0
  40. {telekit-2.0.1a0 → telekit-2.2.0}/setup.cfg +0 -0
  41. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_buildtext/__init__.py +0 -0
  42. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_buildtext/formatter.py +0 -0
  43. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_callback_query_handler.py +0 -0
  44. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_chapters/__init__.py +0 -0
  45. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_chapters/chapters.py +0 -0
  46. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_init.py +0 -0
  47. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_input_handler.py +0 -0
  48. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_snapvault/__init__.py +0 -0
  49. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_snapvault/snapcode.py +0 -0
  50. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_snapvault/snapvault.py +0 -0
  51. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_state.py +0 -0
  52. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/__init__.py +0 -0
  53. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/__init__.py +0 -0
  54. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/builder.py +0 -0
  55. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/canvas_parser.py +0 -0
  56. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/lexer.py +0 -0
  57. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/nodes.py +0 -0
  58. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/parser.py +0 -0
  59. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/parser/token.py +0 -0
  60. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/telekit_dsl.py +0 -0
  61. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_telekit_dsl/telekit_orm.py +0 -0
  62. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/_timeout.py +0 -0
  63. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/__init__.py +0 -0
  64. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/dsl.py +0 -0
  65. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/faq.py +0 -0
  66. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/hotel.py +0 -0
  67. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/pyapi.py +0 -0
  68. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_handlers/text_document.py +0 -0
  69. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/example/example_server.py +0 -0
  70. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/parameters.py +0 -0
  71. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/server.py +0 -0
  72. {telekit-2.0.1a0 → telekit-2.2.0}/telekit/styles.py +0 -0
  73. {telekit-2.0.1a0 → telekit-2.2.0}/telekit.egg-info/dependency_links.txt +0 -0
  74. {telekit-2.0.1a0 → telekit-2.2.0}/telekit.egg-info/requires.txt +0 -0
  75. {telekit-2.0.1a0 → telekit-2.2.0}/telekit.egg-info/top_level.txt +0 -0
telekit-2.2.0/PKG-INFO ADDED
@@ -0,0 +1,432 @@
1
+ Metadata-Version: 2.4
2
+ Name: telekit
3
+ Version: 2.2.0
4
+ Summary: Declarative, developer-friendly library for building Telegram bots
5
+ Home-page: https://github.com/Romashkaa/telekit
6
+ Author: romashka
7
+ Author-email: notromashka@gmail.com
8
+ License: GPLv3
9
+ Project-URL: GitHub, https://github.com/Romashkaa/telekit
10
+ Project-URL: Telegram, https://t.me/TelekitLib
11
+ Keywords: telegram bot api declarative tools bot-api
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
17
+ Classifier: Operating System :: OS Independent
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: charset_normalizer==3.4.2
22
+ Requires-Dist: Jinja2==3.1.6
23
+ Requires-Dist: pyTelegramBotAPI==4.31.0
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: description-content-type
29
+ Dynamic: home-page
30
+ Dynamic: keywords
31
+ Dynamic: license-file
32
+ Dynamic: project-url
33
+ Dynamic: requires-dist
34
+ Dynamic: requires-python
35
+ Dynamic: summary
36
+
37
+ ![TeleKit](https://github.com/Romashkaa/images/blob/main/TeleKitWide.png?raw=true)
38
+
39
+ [![PyPI](https://img.shields.io/pypi/v/telekit.svg)](https://pypi.org/project/telekit/)
40
+ [![Python](https://img.shields.io/pypi/pyversions/telekit.svg)](https://pypi.org/project/telekit/)
41
+ [![PyPI Downloads](https://static.pepy.tech/badge/telekit)](https://pepy.tech/project/telekit)
42
+
43
+ # Telekit
44
+
45
+ **Telekit** is a declarative, developer-friendly library for building Telegram bots. It gives developers a dedicated Sender for composing and sending messages and a Chain for handling dialogue between the user and the bot. The library also handles inline keyboards and callback routing automatically, letting you focus on the bot's behavior instead of repetitive tasks.
46
+
47
+ ```py
48
+ import telekit
49
+
50
+ class MyStartHandler(telekit.Handler):
51
+ @classmethod
52
+ def init_handler(cls):
53
+ cls.on.command('start').invoke(cls.handle_start)
54
+
55
+ def handle_start(self):
56
+ self.chain.sender.set_text("Hello!")
57
+ self.chain.sender.set_photo("robot.png")
58
+ self.chain.send()
59
+
60
+ telekit.Server("BOT_TOKEN").polling()
61
+ ```
62
+
63
+ > Send "Hello!" with a photo on `/start`
64
+
65
+ Telekit comes with a [built-in DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md), allowing developers to create fully interactive bots with minimal code. It also integrates [**Jinja**](https://github.com/Romashkaa/telekit/blob/main/docs/examples/jinja_engine.md), giving you loops, conditionals, expressions, and filters to generate dynamic content.
66
+
67
+ ```js
68
+ @ main {
69
+ title = "🎉 Fun Facts Quiz";
70
+ message = "Test your knowledge with 10 fun questions!";
71
+
72
+ buttons {
73
+ question_1("Start Quiz");
74
+ }
75
+ }
76
+ ```
77
+
78
+ > See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/quiz.md)
79
+
80
+ Even in its beta stage, Telekit accelerates bot development, offering typed command parameters, text styling via `Bold()`, `Italic()`, built-in emoji game results for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
81
+
82
+ **Key features:**
83
+ - Declarative bot logic with **chains** for effortless handling of complex conversations
84
+ - [Ready-to-use DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) for FAQs and other interactive scripts
85
+ - Automatic handling of [message formatting](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/6_styles.md) via [Sender](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/5_senders.md) and **callback routing**
86
+ - **Deep Linking** support with type-checked [Command Parameters](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/command_trigger_parameters.md) for flexible user input
87
+ - Built-in **Permission** and **Logging** system for user management
88
+ - Seamless integration with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
89
+ - Fast to develop and easy-to-extend code
90
+
91
+ [GitHub](https://github.com/Romashkaa/telekit)
92
+ [PyPI](https://pypi.org/project/telekit/)
93
+ [Telegram](https://t.me/NotRomashka)
94
+ [Community](https://t.me/+wu-dFrOBFIwyNzc0)
95
+
96
+ ## Contents
97
+
98
+ - 🌟 [Tutorial](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/0_tutorial.md)
99
+ - 🎆 [Gallery](https://github.com/Romashkaa/telekit/blob/main/docs/documentation/gallery.md)
100
+ - 👀 [Examples](https://github.com/Romashkaa/telekit/blob/main/docs/examples/examples.md)
101
+ - [Dialogue](https://github.com/Romashkaa/telekit/blob/main/docs/examples/dialogue.md)
102
+ - [Risk Game](https://github.com/Romashkaa/telekit/blob/main/docs/examples/risk_game.md)
103
+ - [Counter](https://github.com/Romashkaa/telekit/blob/main/docs/examples/counter.md)
104
+ - [Quiz (Telekit DSL)](https://github.com/Romashkaa/telekit/blob/main/docs/examples/quiz.md)
105
+ - [More...](https://github.com/Romashkaa/telekit/blob/main/docs/examples/examples.md)
106
+
107
+ ## Overview
108
+
109
+ **Telekit** is a library for building Telegram bots where dialogs look like normal method calls. No bulky state machines. No scattered handlers.
110
+
111
+ The idea is simple: you point to the next step — Telekit calls it when the user replies.
112
+
113
+ ### Entries
114
+
115
+ No state machines. Just tell Telekit which method should handle the next user message.
116
+
117
+ ```py
118
+ def handle(self):
119
+ self.chain.sender.set_text("👋 Hello! What is your name?")
120
+ self.chain.set_entry_text(self.handle_name)
121
+ self.chain.send()
122
+
123
+ def handle_name(self, name: str):
124
+ self.chain.sender.set_text(f"Nice to meet you, {name}!")
125
+ self.chain.send()
126
+ ```
127
+
128
+ The `handle` method sends a message and registers `handle_name` as the next step using `set_entry_text`. When the user replies, Telekit automatically calls `handle_name` and passes the user's message as a plain `str` argument.
129
+
130
+ > That's it. No enums. No manual state tracking. No boilerplate.
131
+
132
+ ### Inline Keyboards
133
+
134
+ Buttons can either **return a value** or **call a method directly**.
135
+
136
+ **Choice keyboard** — map button labels to values. The selected value is passed straight into your handler:
137
+
138
+ ```py
139
+ self.chain.set_inline_choice(
140
+ self.on_choice,
141
+ choices={
142
+ "Option 1": "Value 1",
143
+ "Option 2": "Value 2",
144
+ "Option 3": [3, "Yes, it's an array"],
145
+ }
146
+ )
147
+
148
+ def on_choice(self, choice: str | list):
149
+ print(f"{choice!r}") # "Value 1", "Value 2" or [3, "Yes, it's an array"]
150
+ ```
151
+
152
+ Inside `on_choice`, you receive exactly what you defined in `choices`: a string, list, number, function — anything.
153
+
154
+ **Callback keyboard** — each button calls its own method:
155
+
156
+ ```py
157
+ self.chain.set_inline_keyboard({
158
+ "« Back": self.display_previous_page,
159
+ "Next »": self.display_next_page,
160
+ })
161
+ ```
162
+
163
+ Useful for pagination, navigation, or menus.
164
+
165
+ ### Command Parameters
166
+
167
+ Telekit can parse and validate command parameters for you.
168
+
169
+ ```py
170
+ from telekit.parameters import *
171
+
172
+ class GreetHandler(telekit.Handler):
173
+ @classmethod
174
+ def init_handler(cls) -> None:
175
+ cls.on.command("greet", params=[Int(), Str()]).invoke(cls.handle)
176
+
177
+ def handle(self, age: int | None = None, name: str | None = None):
178
+ if age is None or name is None:
179
+ self.chain.sender.set_text("Usage: /greet <age> <name>")
180
+ else:
181
+ self.chain.sender.set_text(f"Hello, {name}! You are {age} years old. Next year you'll turn {age + 1} 😅")
182
+ self.chain.send()
183
+ ```
184
+
185
+ Now `/greet 64 "Alice Reingold"` or `/greet 128 Dracula` are parsed automatically.
186
+
187
+ > [!INFO]
188
+ > If arguments are invalid or missing, you simply receive `None` and decide how to respond.
189
+
190
+ ### Dialogue
191
+
192
+ Dialogs are built as a chain of steps. Each method waits for the user before continuing.
193
+
194
+ ```py
195
+ class DialogueHandler(telekit.Handler):
196
+
197
+ @classmethod
198
+ def init_handler(cls) -> None:
199
+ cls.on.text("hello", "hi", "hey").invoke(cls.handle_hello)
200
+
201
+ def handle_hello(self) -> None:
202
+ self.chain.sender.set_text("👋 Hello! What is your name?")
203
+ if self.user.first_name:
204
+ self.chain.set_entry_suggestions([self.user.first_name])
205
+ self.chain.set_entry_text(self.handle_name)
206
+ self.chain.send()
207
+
208
+ def handle_name(self, name: str) -> None:
209
+ self.user_name = name
210
+ self.chain.sender.set_text("Nice! How are you feeling today?")
211
+ self.chain.set_entry_text(self.handle_feeling)
212
+ self.chain.send()
213
+
214
+ def handle_feeling(self, feeling: str) -> None:
215
+ self.chain.sender.set_text(f"Got it, {self.user_name.title()}! You feel: {feeling}")
216
+ self.chain.set_inline_keyboard({"↺ Restart": self.handle_hello})
217
+ self.chain.send()
218
+ ```
219
+
220
+ How it works:
221
+
222
+ - The handler reacts to "hello", "hi", or "hey" (lowercase, UPPERCASE, or mixed).
223
+ - `handle_hello` asks for the user's name.
224
+ - `set_entry_suggestions` attaches the user's Telegram `first_name` as a suggestion button.
225
+ - `handle_name` stores the name in `self.user_name`.
226
+ - `handle_feeling` completes the flow and adds a `"↺ Restart"` button that routes back to the beginning.
227
+
228
+ It looks like regular Python. And reads like it too.
229
+
230
+ ### Sender
231
+
232
+ Want to add an image, document or an effect in a single line?
233
+
234
+ ```python
235
+ self.chain.sender.set_effect(Effect.HEART) # Add effect to message. Use enum or string
236
+ self.chain.sender.set_photo("robot.png") # Attach photo. URL, file_id, or path
237
+ self.chain.sender.set_document("README.md") # Attach document. URL, file_id, or path
238
+ self.chain.sender.set_text_as_document("Hello, this is a text document!") # Convert string to text document
239
+ self.chain.sender.send_chat_action(ChatAction.TYPING) # Send chat action. Use enum or string
240
+ ```
241
+
242
+ > [!NOTE]
243
+ > Telekit automatically decides whether to use 'bot.send_message' or 'bot.send_photo' based on the content
244
+
245
+ ### Styles
246
+
247
+ Telekit lets you describe formatting as objects instead of writing raw HTML or Markdown.
248
+
249
+ ```py
250
+ from telekit.styles import *
251
+
252
+ def handle(self) -> None:
253
+ self.chain.sender.set_text(
254
+ Bold("Text style examples:\n"),
255
+ Stack(
256
+ Bold("Bold text"),
257
+ Italic("Italic text"),
258
+ Bold(Italic("Bold + italic")),
259
+ Link("Link", url="https://example.com"),
260
+ BotLink("Deep link", username="MyBot", start="promo_42"),
261
+ start="- {{index}}. ",
262
+ sep=".\n",
263
+ )
264
+ )
265
+ self.chain.send()
266
+ ```
267
+
268
+ You describe structure. Telekit generates HTML or MarkdownV2 automatically:
269
+
270
+ ```html
271
+ <b>Text style examples:</b>
272
+
273
+ - 1. <b>Bold text</b>.
274
+ - 2. <i>Italic text</i>.
275
+ - 3. <b><i>Bold + italic</i></b>.
276
+ - 4. <a href="https://example.com">Link</a>.
277
+ - 5. <a href="https://t.me/MyBot?start=promo_42">Deep link</a>
278
+ ```
279
+
280
+ No manual escaping. No broken formatting because of one missing character.
281
+
282
+ ### Telekit DSL
283
+
284
+ If you prefer not to write dialog logic in Python, you can use the built-in DSL with Jinja support.
285
+
286
+ ```py
287
+ import telekit
288
+
289
+ class QuizHandler(telekit.TelekitDSL.Mixin):
290
+ @classmethod
291
+ def init_handler(cls) -> None:
292
+ cls.analyze_string(script)
293
+ cls.on.command("start").invoke(cls.start_script)
294
+
295
+ script = """
296
+ $ timeout {
297
+ time = 20; // 20 sec.
298
+ }
299
+
300
+ @ main {
301
+ title = "🎉 Fun Facts Quiz";
302
+ message = "Test your knowledge with 10 fun questions!";
303
+
304
+ buttons {
305
+ next("Start Quiz");
306
+ }
307
+ }
308
+
309
+ @ question_1 {
310
+ title = "🐶 Question 1";
311
+ message = "Which animal is the fastest on land?";
312
+ buttons {
313
+ _lose("Elephant");
314
+ next("Cheetah"); // correct answer
315
+ _lose("Horse");
316
+ _lose("Lion");
317
+ }
318
+ }
319
+
320
+ /* ... */
321
+ """
322
+
323
+ telekit.Server(BOT_TOKEN).polling()
324
+ ```
325
+
326
+ **Key features of the Telekit DSL:**
327
+
328
+ - Scene-based architecture
329
+ - Anonymous scenes
330
+ - Automatic navigation stack management
331
+ - Input handling
332
+ - Images support and link buttons
333
+ - Template variables
334
+ - Custom variables
335
+ - Hooks (Python API integration)
336
+ - Jinja template engine
337
+
338
+ <details>
339
+ <summary>Click to see what you can do with the DSL</summary>
340
+ <table>
341
+ <tr>
342
+ <td><img src="../images/telekit_example_7.jpg" alt="Telekit Example 7" width="300"></td>
343
+ <td><img src="../images/telekit_example_8.jpg" alt="Telekit Example 8" width="300"></td>
344
+ </tr>
345
+ </table>
346
+ </details>
347
+
348
+ You can find a [full quiz example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md) and [DSL reference](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) in the repository.
349
+
350
+ ### Example Bot
351
+
352
+ You can launch an example bot by **running the following code**:
353
+
354
+ ```py
355
+ import telekit
356
+
357
+ telekit.example(YOUR_BOT_TOKEN)
358
+ ```
359
+
360
+ It includes example commands, dialogs, keyboards, and style usage.
361
+
362
+ ## Why Telekit
363
+
364
+ - No FSM — just **chains**.
365
+ - Declarative, behavior-focused bot logic with minimal boilerplate.
366
+ - Automatic **callback routing** and **input handling**.
367
+ - **Styles API** for rich text (`Bold`, `Italic`, `Links`) with **automatic escaping**.
368
+ - Deep linking and **typed command parameters**.
369
+ - **Built-in DSL** for menus, FAQs, and simple bots.
370
+ - **Zero-code** [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
371
+ - Seamless integration with **pyTelegramBotAPI**.
372
+
373
+ Telekit doesn't try to be everything.
374
+ It tries to make Telegram bot development easier.
375
+
376
+ > [!TIP]
377
+ > If you're interested and want to learn more, check out the [Tutorial](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/0_tutorial.md)
378
+
379
+ ---
380
+
381
+ # Changes in version 2.2.0
382
+
383
+ ## New Button Types
384
+
385
+ | **Name** | **Description** |
386
+ |----------------------|----------------------------------------------------------|
387
+ | `AlertButton` | A callback button that shows a popup alert when pressed. |
388
+ | `NotificationButton` | A callback button that shows a notification. |
389
+ | `InvokeButton` | A callback button that calls the object method. |
390
+
391
+ ## User Improvements
392
+
393
+ | **Name** | **Description** |
394
+ | ---------------------- | --------------------------------------------------------- |
395
+ | `bio` | Bio of the user or description of the chat. |
396
+ | `birthdate` | Birthdate of the user, if set and visible. |
397
+ | `description` | Description of the group or channel. |
398
+ | `mention` | `tg://user?id=` deep link, works even without a username. |
399
+ | `is_private` | Whether the message was sent in a private chat. |
400
+ | `is_group` | Whether the message was sent in a group. |
401
+ | `is_supergroup` | Whether the message was sent in a supergroup. |
402
+ | `is_channel` | Whether the message was sent in a channel. |
403
+ | `avatar` | File ID of the user's most recent profile photo. |
404
+ | `profile_photos_count` | Total number of profile photos the user has set. |
405
+
406
+ - Refactor: `User` now accepts a `Message` object instead of `chat_id` + `from_user`. All properties are derived from `_sender` (`from_user` or `chat`) and migrated to `cached_property`. Fixed broken `get_id` and `get_full_name` references.
407
+ - Added `__repr__`.
408
+
409
+ ## Sender Improvements
410
+
411
+ | **Name** | **Description** |
412
+ | -------------------------- | ------------------------------------------------------ |
413
+ | `sent_message` | The last message sent by this sender instance. |
414
+ | `disable_notification` | Disables notification sound when the message is sent. |
415
+ | `protect_content` | Protects the message contents from forwarding and saving. |
416
+ | `reply_parameters` | Reply parameters for the message to be sent. |
417
+ | `link_preview_options` | Link preview options for the message to be sent. |
418
+ | `show_caption_above_media` | Shows the caption above the media instead of below. |
419
+
420
+ - Refactored sending system.
421
+
422
+ ## Chain Improvements
423
+
424
+ | **Name** | **Description** |
425
+ | ----------- | ------------------------------------------------------------ |
426
+ | `received` | The message received from the user during entry processing. |
427
+
428
+ ## Bug Fixes
429
+ | **Name** | **Description** |
430
+ | -------- | --------------- |
431
+ | Media edit fallback | Fixed a bug where editing a text message with a new attachment (photo, audio, document, etc.) would only update the text, ignoring the attachment entirely. |
432
+ | Callback answer order | Fixed a bug where `answer_callback_query` was not always displayed. |