telekit 2.5.4__tar.gz → 2.6.0a1__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 (88) hide show
  1. {telekit-2.5.4 → telekit-2.6.0a1}/PKG-INFO +38 -44
  2. {telekit-2.5.4 → telekit-2.6.0a1}/README.md +36 -42
  3. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_on.py +154 -26
  4. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_version.py +1 -1
  5. telekit-2.6.0a1/telekit/example/example_handlers/__init__.py +23 -0
  6. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/complete_hotel.py +1 -1
  7. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/hotel.py +1 -1
  8. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/qr.py +1 -1
  9. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/senders.py +22 -0
  10. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/utils.py +44 -1
  11. {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/PKG-INFO +38 -44
  12. telekit-2.5.4/telekit/example/example_handlers/__init__.py +0 -19
  13. {telekit-2.5.4 → telekit-2.6.0a1}/LICENSE +0 -0
  14. {telekit-2.5.4 → telekit-2.6.0a1}/setup.cfg +0 -0
  15. {telekit-2.5.4 → telekit-2.6.0a1}/setup.py +0 -0
  16. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/__init__.py +0 -0
  17. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_buildtext/__init__.py +0 -0
  18. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_buildtext/formatter.py +0 -0
  19. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_buildtext/styles.py +0 -0
  20. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_callback_query_handler.py +0 -0
  21. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain.py +0 -0
  22. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain_base.py +0 -0
  23. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain_entry_logic.py +0 -0
  24. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain_inline_keyboards_logic.py +0 -0
  25. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chapters/__init__.py +0 -0
  26. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chapters/chapters.py +0 -0
  27. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_handler.py +0 -0
  28. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_init.py +0 -0
  29. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_inline_buttons.py +0 -0
  30. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_inline_keyboard.py +0 -0
  31. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_input_handler.py +0 -0
  32. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_logger.py +0 -0
  33. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_reply_keyboard.py +0 -0
  34. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_snapvault/__init__.py +0 -0
  35. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_snapvault/snapcode.py +0 -0
  36. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_snapvault/snapvault.py +0 -0
  37. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_state.py +0 -0
  38. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/__init__.py +0 -0
  39. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/mixin.py +0 -0
  40. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/__init__.py +0 -0
  41. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/builder.py +0 -0
  42. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/canvas_parser.py +0 -0
  43. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/lexer.py +0 -0
  44. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/nodes.py +0 -0
  45. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/parser.py +0 -0
  46. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/token.py +0 -0
  47. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/telekit_dsl.py +0 -0
  48. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/telekit_orm.py +0 -0
  49. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_text_builder.py +0 -0
  50. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_timeout.py +0 -0
  51. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_trait.py +0 -0
  52. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_user.py +0 -0
  53. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/chat.py +0 -0
  54. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/debug.py +0 -0
  55. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/dices.py +0 -0
  56. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/__init__.py +0 -0
  57. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/article.py +0 -0
  58. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/calendar.py +0 -0
  59. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/counter.py +0 -0
  60. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/dsl.py +0 -0
  61. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/entry.py +0 -0
  62. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/faq.py +0 -0
  63. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/on_text.py +0 -0
  64. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/pages.py +0 -0
  65. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/pyapi.py +0 -0
  66. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/quiz.py +0 -0
  67. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/spells.py +0 -0
  68. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/start.py +0 -0
  69. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/style.py +0 -0
  70. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/text_document.py +0 -0
  71. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_server.py +0 -0
  72. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/html_text.py +0 -0
  73. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/inline_buttons.py +0 -0
  74. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/parameters.py +0 -0
  75. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/reply_buttons.py +0 -0
  76. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/scheduler.py +0 -0
  77. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/server.py +0 -0
  78. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/styles.py +0 -0
  79. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/__init__.py +0 -0
  80. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/calendar_pick.py +0 -0
  81. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/paginated_choice.py +0 -0
  82. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/paginated_text.py +0 -0
  83. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/track_handoff_origin.py +0 -0
  84. {telekit-2.5.4 → telekit-2.6.0a1}/telekit/types.py +0 -0
  85. {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/SOURCES.txt +0 -0
  86. {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/dependency_links.txt +0 -0
  87. {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/requires.txt +0 -0
  88. {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: telekit
3
- Version: 2.5.4
3
+ Version: 2.6.0a1
4
4
  Summary: Declarative, developer-friendly library for building Telegram bots
5
5
  Home-page: https://github.com/Romashkaa/telekit
6
6
  Author: romashka
@@ -77,17 +77,16 @@ Telekit comes with a [built-in DSL](https://github.com/Romashkaa/telekit/blob/ma
77
77
 
78
78
  > See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md)
79
79
 
80
- Even in its beta stage, Telekit accelerates bot development, offering typed **command parameters**, **text styling** via `Bold()`, `Italic()`, a built-in declarative **calendar picker**, emoji **game results** for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
80
+ Even in its beta stage, Telekit accelerates bot development, offering typed **command parameters**, **text styling** via `Bold()`, `Italic()`, a built-in declarative **calendar picker** (!), emoji **game results** for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
81
81
 
82
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
- - Reusable **Traits** system for pluggable, self-contained behavior modules
89
- - Seamless integration with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
90
- - Fast to develop and easy-to-extend code
83
+ - **Chains** handle complex conversations without state machines
84
+ - [Ready-to-use DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) for FAQs and interactive scripts
85
+ - Automatic [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** with type-checked [Command Parameters](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/command_trigger_parameters.md)
87
+ - Built-in **Permission** and **Logging** system
88
+ - Reusable **Traits** for pluggable behavior modules
89
+ - Works with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
91
90
 
92
91
  [GitHub](https://github.com/Romashkaa/telekit)
93
92
  [PyPI](https://pypi.org/project/telekit/)
@@ -108,9 +107,7 @@ Even in its beta stage, Telekit accelerates bot development, offering typed **co
108
107
 
109
108
  ## Overview
110
109
 
111
- **Telekit** is a library for building Telegram bots where dialogs look like normal method calls. No bulky state machines. No scattered handlers.
112
-
113
- The idea is simple: you point to the next step — Telekit calls it when the user replies.
110
+ In **Telekit**, dialogs read like normal method calls. You point to the next step. Telekit calls it when the user replies.
114
111
 
115
112
  ### Entries
116
113
 
@@ -127,13 +124,13 @@ def handle_name(self, name: str):
127
124
  self.chain.send()
128
125
  ```
129
126
 
130
- 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.
127
+ `handle` sends a message and registers `handle_name` as the next step with `set_entry_text`. When the user replies, Telekit calls `handle_name` and passes the reply as a plain `str`.
131
128
 
132
129
  > That's it. No enums. No manual state tracking. No boilerplate.
133
130
 
134
131
  ### Inline Keyboards
135
132
 
136
- The fastest way to add buttons to a message. Pass a plain `dict` where each key is the button label and each value is the callback to invoke when pressed:
133
+ The fastest way to add buttons to a message. Pass a `dict` where each key is the button label and each value is the callback to run when pressed:
137
134
 
138
135
  ```python
139
136
  self.chain.set_inline_keyboard(
@@ -167,9 +164,7 @@ self.chain.set_inline_keyboard(
167
164
  ╰─────────────┴──────────────────╯
168
165
  ```
169
166
 
170
- **Need more control?**
171
-
172
- When you need precise row layout or conditional buttons, use `InlineKeyboard` — a fluent builder that composes keyboards step by step:
167
+ For precise row layout or conditional buttons, use `InlineKeyboard`, a builder you compose step by step:
173
168
 
174
169
  ```python
175
170
  self.chain.set_keyboard(
@@ -206,7 +201,7 @@ self.chain.set_keyboard(
206
201
 
207
202
  ### Reply Keyboards
208
203
 
209
- Unlike inline keyboards, reply keyboards replace the user's system keyboard with buttons shown at the bottom of the chat. Tapping a button either sends its text as a regular message or triggers a system action, such as sharing a phone number or location.
204
+ Reply keyboards replace the system keyboard with buttons at the bottom of the chat. Tapping one sends its text as a message, or triggers a system action like sharing a phone number or location.
210
205
 
211
206
  ```python
212
207
  self.chain.set_keyboard(
@@ -239,7 +234,7 @@ class GreetHandler(telekit.Handler):
239
234
  self.chain.send()
240
235
  ```
241
236
 
242
- Now `/greet 64 "Alice Reingold"` or `/greet 128 Dracula` are parsed automatically.
237
+ Now `/greet 128 Dracula` or even `/greet 64 "Alice Reingold"` are parsed automatically.
243
238
 
244
239
  > [!NOTE]
245
240
  > If arguments are invalid or missing, you simply receive `None` and decide how to respond.
@@ -276,17 +271,17 @@ class DialogueHandler(telekit.Handler):
276
271
 
277
272
  How it works:
278
273
 
279
- - The handler reacts to "hello", "hi", or "hey" (lowercase, UPPERCASE, or mixed).
280
- - `handle_hello` asks for the user's name.
274
+ - The handler reacts to `"hello"`, `"hi"`, or `"hey"` in any case.
275
+ - `handle_hello` asks for the user's name.ч
281
276
  - `set_entry_suggestions` attaches the user's Telegram `first_name` as a suggestion button.
282
277
  - `handle_name` stores the name in `self.user_name`.
283
- - `handle_feeling` completes the flow and adds a `"↺ Restart"` button that routes back to the beginning.
278
+ - `handle_feeling` closes the flow and adds a "↺ Restart" button that routes back to the start.
284
279
 
285
- It looks like regular Python. And reads like it too.
280
+ It reads like regular Python because it is regular Python.
286
281
 
287
282
  ### Sender
288
283
 
289
- Want to add an image, document or an effect in a single line?
284
+ Want to attach an image, document or add an effect in a single line?
290
285
 
291
286
  ```python
292
287
  self.chain.sender.set_effect(Effect.HEART) # Add effect to message. Use enum or string
@@ -297,11 +292,11 @@ self.chain.sender.send_chat_action(ChatAction.TYPING) # Send chat action. Use en
297
292
  ```
298
293
 
299
294
  > [!NOTE]
300
- > Telekit automatically decides whether to use `bot.send_message` or `bot.send_photo` based on the content
295
+ > Telekit picks `bot.send_message` or `bot.send_photo` based on the content you attach.
301
296
 
302
297
  ### Styles
303
298
 
304
- Telekit lets you describe formatting as objects instead of writing raw HTML or Markdown.
299
+ Describe formatting as objects instead of writing raw HTML or Markdown.
305
300
 
306
301
  ```py
307
302
  from telekit.styles import *
@@ -322,7 +317,7 @@ def handle(self) -> None:
322
317
  self.chain.send()
323
318
  ```
324
319
 
325
- You describe structure. Telekit generates HTML or MarkdownV2 automatically:
320
+ You describe structure. Telekit turns that structure into HTML or MarkdownV2:
326
321
 
327
322
  ```html
328
323
  <b>Text style examples:</b>
@@ -334,11 +329,11 @@ You describe structure. Telekit generates HTML or MarkdownV2 automatically:
334
329
  - 5. <a href="https://t.me/MyBot?start=promo_42">Deep link</a>
335
330
  ```
336
331
 
337
- No manual escaping. No broken formatting because of one missing character.
332
+ You skip manual escaping and the broken formatting one stray character causes.
338
333
 
339
334
  ### Telekit DSL
340
335
 
341
- If you prefer not to write dialog logic in Python, you can use the built-in DSL with Jinja support.
336
+ Prefer not to write dialog logic in Python? Use the built-in DSL with Jinja support.
342
337
 
343
338
  ```py
344
339
  import telekit
@@ -413,7 +408,7 @@ telekit.Server(BOT_TOKEN).polling()
413
408
 
414
409
  Traits are reusable behavior modules you can mix into any handler.
415
410
 
416
- This example demonstrates the simplest way to use the built-in CalendarPick trait. It allows a user to pick a date from an inline calendar and handles the result via a callback.
411
+ Here's the built-in `CalendarPick` trait: a user picks a date from an inline calendar, and a callback handles the result.
417
412
 
418
413
  ```py
419
414
  from telekit.traits import CalendarPick
@@ -447,7 +442,7 @@ class CalendarHandler(CalendarPick, telekit.Handler):
447
442
 
448
443
  ### Example Bot
449
444
 
450
- You can launch an example bot by **running the following code**:
445
+ Run this to launch an example bot:
451
446
 
452
447
  ```py
453
448
  import telekit
@@ -459,25 +454,24 @@ It includes example commands, dialogs, keyboards, and style usage.
459
454
 
460
455
  ## Why Telekit
461
456
 
462
- - No FSM — just **chains**.
457
+ - Chains instead of an FSM.
463
458
  - Declarative, behavior-focused bot logic with minimal boilerplate.
464
- - Automatic **callback routing** and **input handling**.
465
- - **Styles API** for rich text (`Bold`, `Italic`, `Links`) with **automatic escaping**.
466
- - Deep linking and **typed command parameters**.
467
- - **Built-in DSL** for menus, FAQs, and simple bots.
468
- - Reusable **Traits** for composable, plug-and-play behavior (for example, a built-in declarative calendar picker).
469
- - **Zero-code** [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
470
- - Seamless integration with **pyTelegramBotAPI**.
459
+ - Automatic callback routing and input handling.
460
+ - A Styles API for rich text (`Bold`, `Italic`, links) with automatic escaping.
461
+ - Deep linking and typed command parameters.
462
+ - A built-in DSL for menus, FAQs, and simple bots.
463
+ - Reusable Traits for composable behavior, including a built-in calendar picker.
464
+ - Zero-code mode [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
465
+ - Works with `pyTelegramBotAPI`.
471
466
 
472
- Telekit doesn't try to be everything.
473
- It tries to make Telegram bot development easier.
467
+ Telekit focuses on one job: making Telegram bot development easier.
474
468
 
475
469
  > [!TIP]
476
- > 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)
470
+ > Interested? Start with the [Tutorial](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/0_tutorial.md).
477
471
 
478
472
  ---
479
473
 
480
- # Changes in version 2.5.4
474
+ # Changes in version 2.6.0a1
481
475
 
482
476
  ### v2.5.4 `(bug-fix)`
483
477
  - Fix: Update condition to check for `None` instead of truthy value in `DSLHandler`
@@ -41,17 +41,16 @@ Telekit comes with a [built-in DSL](https://github.com/Romashkaa/telekit/blob/ma
41
41
 
42
42
  > See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md)
43
43
 
44
- Even in its beta stage, Telekit accelerates bot development, offering typed **command parameters**, **text styling** via `Bold()`, `Italic()`, a built-in declarative **calendar picker**, emoji **game results** for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
44
+ Even in its beta stage, Telekit accelerates bot development, offering typed **command parameters**, **text styling** via `Bold()`, `Italic()`, a built-in declarative **calendar picker** (!), emoji **game results** for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
45
45
 
46
46
  **Key features:**
47
- - Declarative bot logic with **chains** for effortless handling of complex conversations
48
- - [Ready-to-use DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) for FAQs and other interactive scripts
49
- - 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**
50
- - **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
51
- - Built-in **Permission** and **Logging** system for user management
52
- - Reusable **Traits** system for pluggable, self-contained behavior modules
53
- - Seamless integration with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
54
- - Fast to develop and easy-to-extend code
47
+ - **Chains** handle complex conversations without state machines
48
+ - [Ready-to-use DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) for FAQs and interactive scripts
49
+ - Automatic [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**
50
+ - **Deep Linking** with type-checked [Command Parameters](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/command_trigger_parameters.md)
51
+ - Built-in **Permission** and **Logging** system
52
+ - Reusable **Traits** for pluggable behavior modules
53
+ - Works with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
55
54
 
56
55
  [GitHub](https://github.com/Romashkaa/telekit)
57
56
  [PyPI](https://pypi.org/project/telekit/)
@@ -72,9 +71,7 @@ Even in its beta stage, Telekit accelerates bot development, offering typed **co
72
71
 
73
72
  ## Overview
74
73
 
75
- **Telekit** is a library for building Telegram bots where dialogs look like normal method calls. No bulky state machines. No scattered handlers.
76
-
77
- The idea is simple: you point to the next step — Telekit calls it when the user replies.
74
+ In **Telekit**, dialogs read like normal method calls. You point to the next step. Telekit calls it when the user replies.
78
75
 
79
76
  ### Entries
80
77
 
@@ -91,13 +88,13 @@ def handle_name(self, name: str):
91
88
  self.chain.send()
92
89
  ```
93
90
 
94
- 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.
91
+ `handle` sends a message and registers `handle_name` as the next step with `set_entry_text`. When the user replies, Telekit calls `handle_name` and passes the reply as a plain `str`.
95
92
 
96
93
  > That's it. No enums. No manual state tracking. No boilerplate.
97
94
 
98
95
  ### Inline Keyboards
99
96
 
100
- The fastest way to add buttons to a message. Pass a plain `dict` where each key is the button label and each value is the callback to invoke when pressed:
97
+ The fastest way to add buttons to a message. Pass a `dict` where each key is the button label and each value is the callback to run when pressed:
101
98
 
102
99
  ```python
103
100
  self.chain.set_inline_keyboard(
@@ -131,9 +128,7 @@ self.chain.set_inline_keyboard(
131
128
  ╰─────────────┴──────────────────╯
132
129
  ```
133
130
 
134
- **Need more control?**
135
-
136
- When you need precise row layout or conditional buttons, use `InlineKeyboard` — a fluent builder that composes keyboards step by step:
131
+ For precise row layout or conditional buttons, use `InlineKeyboard`, a builder you compose step by step:
137
132
 
138
133
  ```python
139
134
  self.chain.set_keyboard(
@@ -170,7 +165,7 @@ self.chain.set_keyboard(
170
165
 
171
166
  ### Reply Keyboards
172
167
 
173
- Unlike inline keyboards, reply keyboards replace the user's system keyboard with buttons shown at the bottom of the chat. Tapping a button either sends its text as a regular message or triggers a system action, such as sharing a phone number or location.
168
+ Reply keyboards replace the system keyboard with buttons at the bottom of the chat. Tapping one sends its text as a message, or triggers a system action like sharing a phone number or location.
174
169
 
175
170
  ```python
176
171
  self.chain.set_keyboard(
@@ -203,7 +198,7 @@ class GreetHandler(telekit.Handler):
203
198
  self.chain.send()
204
199
  ```
205
200
 
206
- Now `/greet 64 "Alice Reingold"` or `/greet 128 Dracula` are parsed automatically.
201
+ Now `/greet 128 Dracula` or even `/greet 64 "Alice Reingold"` are parsed automatically.
207
202
 
208
203
  > [!NOTE]
209
204
  > If arguments are invalid or missing, you simply receive `None` and decide how to respond.
@@ -240,17 +235,17 @@ class DialogueHandler(telekit.Handler):
240
235
 
241
236
  How it works:
242
237
 
243
- - The handler reacts to "hello", "hi", or "hey" (lowercase, UPPERCASE, or mixed).
244
- - `handle_hello` asks for the user's name.
238
+ - The handler reacts to `"hello"`, `"hi"`, or `"hey"` in any case.
239
+ - `handle_hello` asks for the user's name.ч
245
240
  - `set_entry_suggestions` attaches the user's Telegram `first_name` as a suggestion button.
246
241
  - `handle_name` stores the name in `self.user_name`.
247
- - `handle_feeling` completes the flow and adds a `"↺ Restart"` button that routes back to the beginning.
242
+ - `handle_feeling` closes the flow and adds a "↺ Restart" button that routes back to the start.
248
243
 
249
- It looks like regular Python. And reads like it too.
244
+ It reads like regular Python because it is regular Python.
250
245
 
251
246
  ### Sender
252
247
 
253
- Want to add an image, document or an effect in a single line?
248
+ Want to attach an image, document or add an effect in a single line?
254
249
 
255
250
  ```python
256
251
  self.chain.sender.set_effect(Effect.HEART) # Add effect to message. Use enum or string
@@ -261,11 +256,11 @@ self.chain.sender.send_chat_action(ChatAction.TYPING) # Send chat action. Use en
261
256
  ```
262
257
 
263
258
  > [!NOTE]
264
- > Telekit automatically decides whether to use `bot.send_message` or `bot.send_photo` based on the content
259
+ > Telekit picks `bot.send_message` or `bot.send_photo` based on the content you attach.
265
260
 
266
261
  ### Styles
267
262
 
268
- Telekit lets you describe formatting as objects instead of writing raw HTML or Markdown.
263
+ Describe formatting as objects instead of writing raw HTML or Markdown.
269
264
 
270
265
  ```py
271
266
  from telekit.styles import *
@@ -286,7 +281,7 @@ def handle(self) -> None:
286
281
  self.chain.send()
287
282
  ```
288
283
 
289
- You describe structure. Telekit generates HTML or MarkdownV2 automatically:
284
+ You describe structure. Telekit turns that structure into HTML or MarkdownV2:
290
285
 
291
286
  ```html
292
287
  <b>Text style examples:</b>
@@ -298,11 +293,11 @@ You describe structure. Telekit generates HTML or MarkdownV2 automatically:
298
293
  - 5. <a href="https://t.me/MyBot?start=promo_42">Deep link</a>
299
294
  ```
300
295
 
301
- No manual escaping. No broken formatting because of one missing character.
296
+ You skip manual escaping and the broken formatting one stray character causes.
302
297
 
303
298
  ### Telekit DSL
304
299
 
305
- If you prefer not to write dialog logic in Python, you can use the built-in DSL with Jinja support.
300
+ Prefer not to write dialog logic in Python? Use the built-in DSL with Jinja support.
306
301
 
307
302
  ```py
308
303
  import telekit
@@ -377,7 +372,7 @@ telekit.Server(BOT_TOKEN).polling()
377
372
 
378
373
  Traits are reusable behavior modules you can mix into any handler.
379
374
 
380
- This example demonstrates the simplest way to use the built-in CalendarPick trait. It allows a user to pick a date from an inline calendar and handles the result via a callback.
375
+ Here's the built-in `CalendarPick` trait: a user picks a date from an inline calendar, and a callback handles the result.
381
376
 
382
377
  ```py
383
378
  from telekit.traits import CalendarPick
@@ -411,7 +406,7 @@ class CalendarHandler(CalendarPick, telekit.Handler):
411
406
 
412
407
  ### Example Bot
413
408
 
414
- You can launch an example bot by **running the following code**:
409
+ Run this to launch an example bot:
415
410
 
416
411
  ```py
417
412
  import telekit
@@ -423,18 +418,17 @@ It includes example commands, dialogs, keyboards, and style usage.
423
418
 
424
419
  ## Why Telekit
425
420
 
426
- - No FSM — just **chains**.
421
+ - Chains instead of an FSM.
427
422
  - Declarative, behavior-focused bot logic with minimal boilerplate.
428
- - Automatic **callback routing** and **input handling**.
429
- - **Styles API** for rich text (`Bold`, `Italic`, `Links`) with **automatic escaping**.
430
- - Deep linking and **typed command parameters**.
431
- - **Built-in DSL** for menus, FAQs, and simple bots.
432
- - Reusable **Traits** for composable, plug-and-play behavior (for example, a built-in declarative calendar picker).
433
- - **Zero-code** [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
434
- - Seamless integration with **pyTelegramBotAPI**.
423
+ - Automatic callback routing and input handling.
424
+ - A Styles API for rich text (`Bold`, `Italic`, links) with automatic escaping.
425
+ - Deep linking and typed command parameters.
426
+ - A built-in DSL for menus, FAQs, and simple bots.
427
+ - Reusable Traits for composable behavior, including a built-in calendar picker.
428
+ - Zero-code mode [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
429
+ - Works with `pyTelegramBotAPI`.
435
430
 
436
- Telekit doesn't try to be everything.
437
- It tries to make Telegram bot development easier.
431
+ Telekit focuses on one job: making Telegram bot development easier.
438
432
 
439
433
  > [!TIP]
440
- > 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)
434
+ > Interested? Start with the [Tutorial](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/0_tutorial.md).
@@ -1,23 +1,25 @@
1
- #
1
+ # –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
2
+ #
2
3
  # Copyright (C) 2026 Romashka
3
- #
4
+ #
4
5
  # This file is part of Telekit.
5
- #
6
- # Telekit is free software: you can redistribute it and/or modify it
7
- # under the terms of the GNU General Public License as published by
8
- # the Free Software Foundation, either version 3 of the License, or
6
+ #
7
+ # Telekit is free software: you can redistribute it and/or modify it
8
+ # under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
9
10
  # (at your option) any later version.
10
- #
11
- # Telekit is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty
13
- # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
11
+ #
12
+ # Telekit is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty
14
+ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14
15
  # the GNU General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU General Public License
16
+ #
17
+ # You should have received a copy of the GNU General Public License
17
18
  # along with Telekit. If not, see <https://www.gnu.org/licenses/>.
18
19
  #
20
+ # –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
19
21
 
20
- from typing import Callable
22
+ from typing import Callable, Iterable
21
23
  import typing
22
24
  import shlex
23
25
  import re
@@ -464,7 +466,139 @@ class On:
464
466
  return trigger
465
467
 
466
468
  return Invoker(register, self.handler)
467
-
469
+
470
+ def document(
471
+ self,
472
+ chat_types: list[str] | None = None,
473
+ whitelist: list[int] | None = None,
474
+ **kwargs
475
+ ):
476
+ """
477
+ Handles new incoming document (file) messages of any kind. All message handlers are tested in the order they were added.
478
+
479
+ • [See Documentation on GitHub](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/3_triggers.md)
480
+
481
+ ---
482
+ ## Example:
483
+ ```
484
+ class MyHandler(telekit.Handler):
485
+ @classmethod
486
+ def init_handler(cls) -> None:
487
+ cls.on.document().invoke(cls.handle)
488
+
489
+ # Or define the handler manually:
490
+ @cls.on.document()
491
+ def handler(message: telebot.types.Message) -> None:
492
+ cls(message).handle()
493
+ ```
494
+ ---
495
+
496
+ Triggers when receive a document (content_type="document"), regardless of its file type.
497
+
498
+ Filters:
499
+ - By chat type(s) (via `chat_types` argument)
500
+ - By whitelist (via `whitelist` argument)
501
+ - Additional filters can be applied via chat_types and whitelist.
502
+
503
+ Args:
504
+ chat_types (list[str] | None): List of chat types, e.g., ['private', 'group'].
505
+ whitelist (list[int] | None): List of chat IDs allowed to trigger the handler.
506
+ **kwargs: Any other keyword arguments supported by `telebot.TeleBot.message_handler`.
507
+
508
+ Returns:
509
+ Invoker: An invoker object allowing `.invoke()` or decorator-style usage.
510
+ """
511
+ def register(handler: Callable[..., typing.Any]):
512
+ @self.bot.message_handler(
513
+ content_types=["document"],
514
+ chat_types=chat_types,
515
+ **kwargs
516
+ )
517
+ def trigger(message):
518
+ if whitelist is not None and message.chat.id not in whitelist:
519
+ return
520
+ return handler(message)
521
+
522
+ return trigger
523
+
524
+ return Invoker(register, self.handler)
525
+
526
+ def text_document(
527
+ self,
528
+ chat_types: list[str] | None = None,
529
+ whitelist: list[int] | None = None,
530
+ extensions: tuple[str, ...] = (".txt", ".md", ".log", ".csv", ".json", ".py", ".ini", ".yaml", ".yml"),
531
+ **kwargs
532
+ ):
533
+ """
534
+ Handles incoming documents that are plain text files: mime type starting
535
+ with "text/", or a filename ending in a common text extension. Useful for
536
+ catching `.txt`/`.md`/`.log`/`.csv`/`.py` uploads, or files produced by
537
+ `Sender.set_text_as_document`.
538
+
539
+ • [See Documentation on GitHub](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial2/3_triggers.md)
540
+
541
+ ---
542
+ ## Example:
543
+ ```
544
+ class MyHandler(telekit.Handler):
545
+ @classmethod
546
+ def init_handler(cls) -> None:
547
+ cls.on.text_document().invoke(cls.handle)
548
+
549
+ # Or define the handler manually:
550
+ @cls.on.text_document()
551
+ def handler(message: telebot.types.Message) -> None:
552
+ cls(message).handle()
553
+ ```
554
+ ---
555
+
556
+ Triggers when receive a document (content_type="document") whose mime_type
557
+ starts with "text/" or whose filename ends with a known text extension.
558
+
559
+ Filters:
560
+ - By chat type(s) (via `chat_types` argument)
561
+ - By whitelist (via `whitelist` argument)
562
+ - Additional filters can be applied via chat_types and whitelist.
563
+
564
+ Args:
565
+ chat_types (list[str] | None): List of chat types, e.g., ['private', 'group'].
566
+ whitelist (list[int] | None): List of chat IDs allowed to trigger the handler.
567
+ **kwargs: Any other keyword arguments supported by `telebot.TeleBot.message_handler`.
568
+
569
+ Returns:
570
+ Invoker: An invoker object allowing `.invoke()` or decorator-style usage.
571
+ """
572
+
573
+ def _is_text_document(message: telebot.types.Message) -> bool:
574
+ document = message.document
575
+ if document is None:
576
+ return False
577
+
578
+ if document.mime_type and document.mime_type.startswith("text/"):
579
+ return True
580
+
581
+ if document.file_name and document.file_name.lower().endswith(extensions):
582
+ return True
583
+
584
+ return False
585
+
586
+ def register(handler: Callable[..., typing.Any]):
587
+ @self.bot.message_handler(
588
+ content_types=["document"],
589
+ func=_is_text_document,
590
+ chat_types=chat_types,
591
+ **kwargs
592
+ )
593
+ def trigger(message):
594
+ if whitelist is not None and message.chat.id not in whitelist:
595
+ return
596
+ return handler(message)
597
+
598
+ return trigger
599
+
600
+ return Invoker(register, self.handler)
601
+
468
602
  def func(
469
603
  self,
470
604
  func: Callable[[telebot.types.Message], bool],
@@ -504,8 +638,8 @@ class On:
504
638
 
505
639
  Args:
506
640
  func (Callable[[telebot.types.Message], bool]): Custom filter function that must return True for messages to trigger the handler.
507
- invoke_args (list | tuple | None): Optional positional arguments to pass to the handler function when invoked.
508
- invoke_kwargs (dict[str, Any] | None): Optional keyword arguments to pass to the handler function when invoked.
641
+ invoke_args (list | tuple | None): Optional positional arguments to pass to the handler function when invoked. If provided (including an empty list/tuple), it overrides any args telebot would otherwise pass.
642
+ invoke_kwargs (dict[str, Any] | None): Optional keyword arguments to pass to the handler function when invoked. If provided (including an empty dict), it overrides any kwargs telebot would otherwise pass.
509
643
  chat_types (list[str] | None): List of chat types, e.g., ['private', 'group'].
510
644
  whitelist (list[int] | None): List of chat IDs allowed to trigger the handler.
511
645
  **kwargs: Any other keyword arguments supported by `telebot.TeleBot.message_handler`.
@@ -520,7 +654,7 @@ class On:
520
654
  return bool(func(message))
521
655
 
522
656
  def decorator(handler: Callable[..., typing.Any]):
523
- if not invoke_args and not invoke_kwargs:
657
+ if invoke_args is None and invoke_kwargs is None:
524
658
  return self.bot.message_handler(
525
659
  func=_filter,
526
660
  chat_types=chat_types,
@@ -532,15 +666,9 @@ class On:
532
666
  chat_types=chat_types,
533
667
  **kwargs
534
668
  )
535
- def trigger(message, *args, **kwargs):
536
- final_args = args
537
- final_kwargs = kwargs
538
-
539
- if invoke_args is not None:
540
- final_args = invoke_args
541
-
542
- if invoke_kwargs is not None:
543
- final_kwargs = invoke_kwargs
669
+ def trigger(message, *trigger_args, **trigger_kwargs):
670
+ final_args = invoke_args if invoke_args is not None else trigger_args
671
+ final_kwargs = invoke_kwargs if invoke_kwargs is not None else trigger_kwargs
544
672
 
545
673
  return handler(message, *final_args, **final_kwargs)
546
674
 
@@ -3,4 +3,4 @@
3
3
  # PyPI history: https://pypi.org/project/telekit/#history
4
4
  # ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
5
5
 
6
- __version__ = "2.5.4"
6
+ __version__ = "2.6.0a1"
@@ -0,0 +1,23 @@
1
+ import telekit
2
+
3
+ telekit.utils.load_modules(__name__)
4
+
5
+ # from . import (
6
+ # counter,
7
+ # entry,
8
+ # pages,
9
+ # on_text,
10
+ # spells,
11
+ # start,
12
+ # dsl,
13
+ # faq,
14
+ # pyapi,
15
+ # quiz,
16
+ # hotel,
17
+ # complete_hotel,
18
+ # text_document,
19
+ # qr,
20
+ # calendar,
21
+ # article,
22
+ # style,
23
+ # )
@@ -24,7 +24,7 @@ class CompleteHotelHandler(telekit.TelekitDSL.Mixin):
24
24
  @classmethod
25
25
  def init_handler(cls) -> None:
26
26
  cls.analyze_string(script)
27
- cls.on.command("start").invoke(cls.handle)
27
+ cls.on.command("complete_hotel").invoke(cls.handle)
28
28
 
29
29
  def handle(self):
30
30
  self.start_script()