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.
- {telekit-2.5.4 → telekit-2.6.0a1}/PKG-INFO +38 -44
- {telekit-2.5.4 → telekit-2.6.0a1}/README.md +36 -42
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_on.py +154 -26
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_version.py +1 -1
- telekit-2.6.0a1/telekit/example/example_handlers/__init__.py +23 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/complete_hotel.py +1 -1
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/hotel.py +1 -1
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/qr.py +1 -1
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/senders.py +22 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/utils.py +44 -1
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/PKG-INFO +38 -44
- telekit-2.5.4/telekit/example/example_handlers/__init__.py +0 -19
- {telekit-2.5.4 → telekit-2.6.0a1}/LICENSE +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/setup.cfg +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/setup.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_buildtext/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_buildtext/formatter.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_buildtext/styles.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_callback_query_handler.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain_base.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain_entry_logic.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chain_inline_keyboards_logic.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chapters/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_chapters/chapters.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_handler.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_init.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_inline_buttons.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_inline_keyboard.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_input_handler.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_logger.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_reply_keyboard.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_snapvault/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_snapvault/snapcode.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_snapvault/snapvault.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_state.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/mixin.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/builder.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/canvas_parser.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/lexer.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/nodes.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/parser.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/parser/token.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/telekit_dsl.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_telekit_dsl/telekit_orm.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_text_builder.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_timeout.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_trait.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/_user.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/chat.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/debug.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/dices.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/article.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/calendar.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/counter.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/dsl.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/entry.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/faq.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/on_text.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/pages.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/pyapi.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/quiz.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/spells.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/start.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/style.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_handlers/text_document.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/example/example_server.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/html_text.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/inline_buttons.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/parameters.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/reply_buttons.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/scheduler.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/server.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/styles.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/__init__.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/calendar_pick.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/paginated_choice.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/paginated_text.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/traits/track_handoff_origin.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit/types.py +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/SOURCES.txt +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/dependency_links.txt +0 -0
- {telekit-2.5.4 → telekit-2.6.0a1}/telekit.egg-info/requires.txt +0 -0
- {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.
|
|
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
|
|
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
|
-
-
|
|
84
|
-
- [Ready-to-use DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) for FAQs and
|
|
85
|
-
- Automatic
|
|
86
|
-
- **Deep Linking**
|
|
87
|
-
- Built-in **Permission** and **Logging** system
|
|
88
|
-
- Reusable **Traits**
|
|
89
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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"
|
|
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`
|
|
278
|
+
- `handle_feeling` closes the flow and adds a "↺ Restart" button that routes back to the start.
|
|
284
279
|
|
|
285
|
-
It
|
|
280
|
+
It reads like regular Python because it is regular Python.
|
|
286
281
|
|
|
287
282
|
### Sender
|
|
288
283
|
|
|
289
|
-
Want to
|
|
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
|
|
295
|
+
> Telekit picks `bot.send_message` or `bot.send_photo` based on the content you attach.
|
|
301
296
|
|
|
302
297
|
### Styles
|
|
303
298
|
|
|
304
|
-
|
|
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
|
|
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
|
-
|
|
332
|
+
You skip manual escaping and the broken formatting one stray character causes.
|
|
338
333
|
|
|
339
334
|
### Telekit DSL
|
|
340
335
|
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
457
|
+
- Chains instead of an FSM.
|
|
463
458
|
- Declarative, behavior-focused bot logic with minimal boilerplate.
|
|
464
|
-
- Automatic
|
|
465
|
-
-
|
|
466
|
-
- Deep linking and
|
|
467
|
-
-
|
|
468
|
-
- Reusable
|
|
469
|
-
-
|
|
470
|
-
-
|
|
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
|
|
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
|
-
>
|
|
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.
|
|
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
|
|
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
|
-
-
|
|
48
|
-
- [Ready-to-use DSL](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) for FAQs and
|
|
49
|
-
- Automatic
|
|
50
|
-
- **Deep Linking**
|
|
51
|
-
- Built-in **Permission** and **Logging** system
|
|
52
|
-
- Reusable **Traits**
|
|
53
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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"
|
|
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`
|
|
242
|
+
- `handle_feeling` closes the flow and adds a "↺ Restart" button that routes back to the start.
|
|
248
243
|
|
|
249
|
-
It
|
|
244
|
+
It reads like regular Python because it is regular Python.
|
|
250
245
|
|
|
251
246
|
### Sender
|
|
252
247
|
|
|
253
|
-
Want to
|
|
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
|
|
259
|
+
> Telekit picks `bot.send_message` or `bot.send_photo` based on the content you attach.
|
|
265
260
|
|
|
266
261
|
### Styles
|
|
267
262
|
|
|
268
|
-
|
|
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
|
|
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
|
-
|
|
296
|
+
You skip manual escaping and the broken formatting one stray character causes.
|
|
302
297
|
|
|
303
298
|
### Telekit DSL
|
|
304
299
|
|
|
305
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
421
|
+
- Chains instead of an FSM.
|
|
427
422
|
- Declarative, behavior-focused bot logic with minimal boilerplate.
|
|
428
|
-
- Automatic
|
|
429
|
-
-
|
|
430
|
-
- Deep linking and
|
|
431
|
-
-
|
|
432
|
-
- Reusable
|
|
433
|
-
-
|
|
434
|
-
-
|
|
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
|
|
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
|
-
>
|
|
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
|
|
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, *
|
|
536
|
-
final_args =
|
|
537
|
-
final_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
|
|
|
@@ -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("
|
|
27
|
+
cls.on.command("complete_hotel").invoke(cls.handle)
|
|
28
28
|
|
|
29
29
|
def handle(self):
|
|
30
30
|
self.start_script()
|