telekit 2.4.0b1__tar.gz → 2.5.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.
- {telekit-2.4.0b1 → telekit-2.5.0}/PKG-INFO +122 -228
- {telekit-2.4.0b1 → telekit-2.5.0}/README.md +82 -26
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/__init__.py +9 -1
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_buildtext/formatter.py +101 -17
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_buildtext/styles.py +77 -60
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_chain_base.py +0 -1
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_chain_entry_logic.py +4 -4
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_handler.py +10 -1
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_init.py +2 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_inline_buttons.py +99 -11
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_inline_keyboard.py +220 -46
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_reply_keyboard.py +82 -24
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/mixin.py +1 -1
- telekit-2.5.0/telekit/_text_builder.py +529 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_version.py +1 -1
- telekit-2.5.0/telekit/chat.py +101 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/debug.py +1 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/__init__.py +2 -0
- telekit-2.5.0/telekit/example/example_handlers/article.py +66 -0
- telekit-2.5.0/telekit/example/example_handlers/counter.py +84 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/on_text.py +20 -15
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/start.py +4 -2
- telekit-2.5.0/telekit/example/example_handlers/style.py +73 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/text_document.py +1 -1
- telekit-2.5.0/telekit/html_text.py +812 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/inline_buttons.py +6 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/senders.py +29 -6
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/traits/__init__.py +1 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/traits/calendar_pick.py +180 -195
- telekit-2.5.0/telekit/traits/paginated_text.py +378 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/types.py +26 -21
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/utils.py +45 -9
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit.egg-info/PKG-INFO +122 -228
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit.egg-info/SOURCES.txt +6 -0
- telekit-2.4.0b1/telekit/example/example_handlers/counter.py +0 -46
- {telekit-2.4.0b1 → telekit-2.5.0}/LICENSE +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/setup.cfg +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/setup.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_buildtext/__init__.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_callback_query_handler.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_chain.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_chain_inline_keyboards_logic.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_chapters/__init__.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_chapters/chapters.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_input_handler.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_logger.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_on.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_snapvault/__init__.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_snapvault/snapcode.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_snapvault/snapvault.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_state.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/__init__.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/__init__.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/builder.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/canvas_parser.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/lexer.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/nodes.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/parser.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/parser/token.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/telekit_dsl.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_telekit_dsl/telekit_orm.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_timeout.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_trait.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/_user.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/dices.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/__init__.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/calendar.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/complete_hotel.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/dsl.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/entry.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/faq.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/hotel.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/pages.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/pyapi.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/qr.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/quiz.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_handlers/spells.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/example/example_server.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/parameters.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/reply_buttons.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/scheduler.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/server.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/styles.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/traits/paginated_choice.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit/traits/track_handoff_origin.py +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit.egg-info/dependency_links.txt +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/telekit.egg-info/requires.txt +0 -0
- {telekit-2.4.0b1 → telekit-2.5.0}/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.5.0
|
|
4
4
|
Summary: Declarative, developer-friendly library for building Telegram bots
|
|
5
5
|
Home-page: https://github.com/Romashkaa/telekit
|
|
6
6
|
Author: romashka
|
|
@@ -75,7 +75,7 @@ Telekit comes with a [built-in DSL](https://github.com/Romashkaa/telekit/blob/ma
|
|
|
75
75
|
}
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
> See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/
|
|
78
|
+
> See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md)
|
|
79
79
|
|
|
80
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
|
|
|
@@ -133,36 +133,91 @@ The `handle` method sends a message and registers `handle_name` as the next step
|
|
|
133
133
|
|
|
134
134
|
### Inline Keyboards
|
|
135
135
|
|
|
136
|
-
|
|
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:
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
self.
|
|
142
|
-
|
|
143
|
-
choices={
|
|
144
|
-
"Option 1": "Value 1",
|
|
145
|
-
"Option 2": "Value 2",
|
|
146
|
-
"Option 3": [3, "Yes, it's an array"],
|
|
138
|
+
```python
|
|
139
|
+
self.chain.set_inline_keyboard(
|
|
140
|
+
{
|
|
141
|
+
"✏️ Change": self.change_name,
|
|
142
|
+
"❌ Delete": self.delete,
|
|
147
143
|
}
|
|
148
144
|
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`row_width` controls how many buttons appear per row:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
self.chain.set_inline_keyboard(
|
|
151
|
+
{
|
|
152
|
+
"One": self.one,
|
|
153
|
+
"Two": self.two,
|
|
154
|
+
"Three": self.three,
|
|
155
|
+
"Four": self.four,
|
|
156
|
+
"Five": self.five,
|
|
157
|
+
},
|
|
158
|
+
row_width=(3, 2) # first row: 3 buttons, second row: 2
|
|
159
|
+
)
|
|
160
|
+
```
|
|
149
161
|
|
|
150
|
-
|
|
151
|
-
|
|
162
|
+
```
|
|
163
|
+
╭──────────┬──────────┬──────────╮
|
|
164
|
+
│ One │ Two │ Three │
|
|
165
|
+
├──────────┴──┬───────┴──────────┤
|
|
166
|
+
│ Four │ Five │
|
|
167
|
+
╰─────────────┴──────────────────╯
|
|
152
168
|
```
|
|
153
169
|
|
|
154
|
-
|
|
170
|
+
**Need more control?**
|
|
155
171
|
|
|
156
|
-
|
|
172
|
+
When you need precise row layout or conditional buttons, use `InlineKeyboard` — a fluent builder that composes keyboards step by step:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
self.chain.set_keyboard(
|
|
176
|
+
InlineKeyboard()
|
|
177
|
+
.add_callback("-", self.decrement, style="danger")
|
|
178
|
+
.add_callback("+", self.increment, style="success")
|
|
179
|
+
.row()
|
|
180
|
+
.add_callback("↺ Reset", self.reset)
|
|
181
|
+
)
|
|
182
|
+
```
|
|
157
183
|
|
|
158
|
-
```py
|
|
159
|
-
self.chain.set_inline_keyboard({
|
|
160
|
-
"« Back": self.display_previous_page,
|
|
161
|
-
"Next »": self.display_next_page,
|
|
162
|
-
})
|
|
163
184
|
```
|
|
185
|
+
╭──────────┬──────────╮
|
|
186
|
+
│ - │ + │
|
|
187
|
+
├──────────┴──────────┤
|
|
188
|
+
│ ↺ Reset │
|
|
189
|
+
╰─────────────────────╯
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
> `InlineKeyboard` is built by chaining method calls. Just call `.row()` to start a new row.
|
|
193
|
+
|
|
194
|
+
**Not just callback buttons**
|
|
195
|
+
|
|
196
|
+
| **Method** | **Description** |
|
|
197
|
+
| --------------------- | ---------------------------------------------------------------- |
|
|
198
|
+
| `add_callback(...)` | Button that fires a callback function. |
|
|
199
|
+
| `add_link(...)` | Button that opens a URL. |
|
|
200
|
+
| `add_copy(...)` | Button that copies text to the clipboard. |
|
|
201
|
+
| `add_alert(...)` | Button that shows a popup alert dialog. |
|
|
202
|
+
| `add_notification(...)` | Button that shows a brief top-of-chat notification. |
|
|
203
|
+
| `add_static(...)` | Decorative button with no action. |
|
|
204
|
+
| `add_webapp(...)` | Button that opens a Telegram Mini App. |
|
|
205
|
+
| `add_suggest(...)` | Button that simulates the user sending a message. |
|
|
206
|
+
|
|
207
|
+
### Reply Keyboards
|
|
208
|
+
|
|
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.
|
|
164
210
|
|
|
165
|
-
|
|
211
|
+
```python
|
|
212
|
+
self.chain.set_keyboard(
|
|
213
|
+
ReplyKeyboard(one_time_keyboard=True)
|
|
214
|
+
.add_text("Hello!")
|
|
215
|
+
.add_text("Hi")
|
|
216
|
+
.row()
|
|
217
|
+
.add_contact("📱 Share phone")
|
|
218
|
+
.add_location("📍 Share location")
|
|
219
|
+
)
|
|
220
|
+
```
|
|
166
221
|
|
|
167
222
|
### Command Parameters
|
|
168
223
|
|
|
@@ -186,7 +241,7 @@ class GreetHandler(telekit.Handler):
|
|
|
186
241
|
|
|
187
242
|
Now `/greet 64 "Alice Reingold"` or `/greet 128 Dracula` are parsed automatically.
|
|
188
243
|
|
|
189
|
-
> [!
|
|
244
|
+
> [!NOTE]
|
|
190
245
|
> If arguments are invalid or missing, you simply receive `None` and decide how to respond.
|
|
191
246
|
|
|
192
247
|
### Dialogue
|
|
@@ -242,7 +297,7 @@ self.chain.sender.send_chat_action(ChatAction.TYPING) # Send chat action. Use en
|
|
|
242
297
|
```
|
|
243
298
|
|
|
244
299
|
> [!NOTE]
|
|
245
|
-
> Telekit automatically decides whether to use
|
|
300
|
+
> Telekit automatically decides whether to use `bot.send_message` or `bot.send_photo` based on the content
|
|
246
301
|
|
|
247
302
|
### Styles
|
|
248
303
|
|
|
@@ -288,7 +343,7 @@ If you prefer not to write dialog logic in Python, you can use the built-in DSL
|
|
|
288
343
|
```py
|
|
289
344
|
import telekit
|
|
290
345
|
|
|
291
|
-
class QuizHandler(telekit.
|
|
346
|
+
class QuizHandler(telekit.DSLHandler):
|
|
292
347
|
@classmethod
|
|
293
348
|
def init_handler(cls) -> None:
|
|
294
349
|
cls.analyze_string(script)
|
|
@@ -338,7 +393,7 @@ telekit.Server(BOT_TOKEN).polling()
|
|
|
338
393
|
- Jinja template engine
|
|
339
394
|
|
|
340
395
|
<details>
|
|
341
|
-
<summary
|
|
396
|
+
<summary>🎆 Click to see what you can do with the DSL</summary>
|
|
342
397
|
<table>
|
|
343
398
|
<tr>
|
|
344
399
|
<td><img src="./docs/images/telekit_example_7.jpg" alt="Telekit Example 7" width="300"></td>
|
|
@@ -351,7 +406,8 @@ telekit.Server(BOT_TOKEN).polling()
|
|
|
351
406
|
</table>
|
|
352
407
|
</details>
|
|
353
408
|
|
|
354
|
-
|
|
409
|
+
> [!TIP]
|
|
410
|
+
> 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.
|
|
355
411
|
|
|
356
412
|
### Traits
|
|
357
413
|
|
|
@@ -421,204 +477,42 @@ It tries to make Telegram bot development easier.
|
|
|
421
477
|
|
|
422
478
|
---
|
|
423
479
|
|
|
424
|
-
# Changes in version 2.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
| **Method** | **Description** |
|
|
465
|
-
|------------------|----------------------------------------------------------------|
|
|
466
|
-
| `row(when=)` | Finalize the current row and start a new one. |
|
|
467
|
-
| `column_start()` | Enable column mode — every subsequent button gets its own row. |
|
|
468
|
-
| `column_end()` | Disable column mode and flush the current row. |
|
|
469
|
-
|
|
470
|
-
**Button methods**
|
|
471
|
-
|
|
472
|
-
| **Method** | **Description** |
|
|
473
|
-
|------------|-----------------|
|
|
474
|
-
| `add(text, button, when=)` | Attach any `InlineButton` instance. |
|
|
475
|
-
| `add_callback(text, callback, pass_args, pass_kwargs, answer_text, answer_as_alert, style, when=)` | Button that fires a callback function. |
|
|
476
|
-
| `add_link(text, url, style, when=)` | Button that opens a URL or `tg://` link. |
|
|
477
|
-
| `add_webapp(text, url, style, when=)` | Button that opens a Telegram Mini App. |
|
|
478
|
-
| `add_suggest(text, suggestion, style, strict, when=)` | Button that simulates the user sending a message. |
|
|
479
|
-
| `add_copy(text, copy_text, style, strict, when=)` | Button that copies text to the clipboard. |
|
|
480
|
-
| `add_static(text, style, when=)` | Decorative button with no action. |
|
|
481
|
-
| `add_alert(text, alert_text, persistent, style, when=)` | Button that shows a popup alert dialog. |
|
|
482
|
-
| `add_notification(text, notification_text, persistent, style, when=)` | Button that shows a brief top-of-chat notification. |
|
|
483
|
-
| `add_invoke(text, obj, invoke, pass_args, pass_kwargs, answer_text, answer_as_alert, style, when=)` | Button that calls a named method on an arbitrary object. |
|
|
484
|
-
|
|
485
|
-
**Bulk helpers**
|
|
486
|
-
|
|
487
|
-
| **Method** | **Description** |
|
|
488
|
-
|------------|-----------------|
|
|
489
|
-
| `extend(buttons, column=, when=)` | Add multiple buttons from a `dict[str, InlineButton \| None]` or `list[str]`. |
|
|
490
|
-
| `extend_rows(*rows, when=)` | Append one or more pre-built `list[tuple[str, InlineButton]]` rows. |
|
|
491
|
-
|
|
492
|
-
All button methods accept a `style` parameter: `"danger"` (red), `"success"` (green), or `"primary"` (blue).
|
|
493
|
-
|
|
494
|
-
```python
|
|
495
|
-
InlineKeyboard()
|
|
496
|
-
.add_link("YouTube", "https://youtube.com")
|
|
497
|
-
.add_copy("Copy Me", "copied!")
|
|
498
|
-
.add_alert("Info", "This is an alert")
|
|
499
|
-
.row()
|
|
500
|
-
.add_callback("Click Me!", self.handle)
|
|
501
|
-
.column_start()
|
|
502
|
-
.add_link("A", "https://example.com")
|
|
503
|
-
.add_callback("B", self.handle_b)
|
|
504
|
-
.column_end()
|
|
505
|
-
.extend({"Alert": AlertButton("Hi!"), "Notify": NotificationButton("Hey")}, column=True)
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
### `ReplyKeyboard`
|
|
509
|
-
|
|
510
|
-
Fluent builder for Telegram reply keyboards. Mirrors the `InlineKeyboard` layout API (`row`, `column_start`, `column_end`, `extend`, `extend_rows`).
|
|
511
|
-
|
|
512
|
-
**Constructor parameters**
|
|
513
|
-
|
|
514
|
-
| **Parameter** | **Default** | **Description** |
|
|
515
|
-
|---|---|---|
|
|
516
|
-
| `resize_keyboard` | `True` | Shrink the keyboard to fit its buttons. |
|
|
517
|
-
| `one_time_keyboard` | `False` | Hide the keyboard after the first press. |
|
|
518
|
-
| `input_field_placeholder` | `None` | Placeholder text shown while the keyboard is active (max 64 chars). |
|
|
519
|
-
| `selective` | `False` | Show only to mentioned users or the original sender. |
|
|
520
|
-
| `is_persistent` | `False` | Always show the keyboard; do not collapse it to an icon. |
|
|
521
|
-
|
|
522
|
-
**Button methods**
|
|
523
|
-
|
|
524
|
-
| **Method** | **Description** |
|
|
525
|
-
|---|---|
|
|
526
|
-
| `add(text, button, when=)` | Attach any `ReplyButton` instance. |
|
|
527
|
-
| `add_text(text, when=)` | Plain text button — sends the label as a message. |
|
|
528
|
-
| `add_contact(text, when=)` | Prompts the user to share their phone number (private chats only). |
|
|
529
|
-
| `add_location(text, when=)` | Prompts the user to share their geolocation (private chats only). |
|
|
530
|
-
| `add_poll(text, poll_type, when=)` | Opens the poll creation dialog; `poll_type` can be `"quiz"`, `"regular"`, or `None`. |
|
|
531
|
-
| `add_webapp(text, url, when=)` | Opens a Telegram Mini App. |
|
|
532
|
-
| `add_request_user(text, request_id, user_is_bot, user_is_premium, when=)` | Lets the user pick a Telegram user; result returned as a service message. |
|
|
533
|
-
| `add_request_chat(text, request_id, chat_is_channel, chat_is_forum, chat_has_username, chat_is_created, user_administrator_rights, bot_administrator_rights, bot_is_member, when=)` | Lets the user pick a chat; result returned as a service message. |
|
|
534
|
-
|
|
535
|
-
**Layout helpers** — identical to `InlineKeyboard`
|
|
536
|
-
|
|
537
|
-
| **Method** | **Description** |
|
|
538
|
-
|---|---|
|
|
539
|
-
| `row(when=)` | Finalize the current row and start a new one. |
|
|
540
|
-
| `column_start()` | Enable column mode — every subsequent button gets its own row. |
|
|
541
|
-
| `column_end()` | Disable column mode and flush the current row. |
|
|
542
|
-
| `extend(buttons, column=, when=)` | Add multiple buttons from a `dict[str, ReplyButton \| None]` or `list[str]`. |
|
|
543
|
-
| `extend_rows(*rows, when=)` | Append one or more pre-built `list[tuple[str, ReplyButton]]` rows. |
|
|
544
|
-
|
|
545
|
-
```python
|
|
546
|
-
ReplyKeyboard(input_field_placeholder="Choose:", one_time_keyboard=True)
|
|
547
|
-
.add_text("Hello!")
|
|
548
|
-
.add_text("Hi")
|
|
549
|
-
.row()
|
|
550
|
-
.add_contact("📱 Phone")
|
|
551
|
-
.add_location("📍 Location")
|
|
552
|
-
.add_poll("📊 Poll")
|
|
553
|
-
.row()
|
|
554
|
-
.add_request_user("Pick user", request_id=1)
|
|
555
|
-
.add_request_chat("Pick chat", request_id=2)
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
## Telekit DSL
|
|
559
|
-
|
|
560
|
-
### `InstanceDSLHandler`
|
|
561
|
-
|
|
562
|
-
Instance-oriented variant of `DSLHandler` where each instance carries its own
|
|
563
|
-
`executable_model`, `_script_data_factory`, and `_jinja_env` — allowing multiple
|
|
564
|
-
instances to run completely independent scripts simultaneously.
|
|
565
|
-
|
|
566
|
-
Use the `*_locally` instance methods instead of the class-level ones:
|
|
567
|
-
|
|
568
|
-
```python
|
|
569
|
-
class MyHandler(telekit.InstanceDSLHandler):
|
|
570
|
-
@classmethod
|
|
571
|
-
def init_handler(cls) -> None:
|
|
572
|
-
cls.on.message().invoke(cls.handle)
|
|
573
|
-
|
|
574
|
-
def handle(self):
|
|
575
|
-
script = fetch_script_from_db(self.user.id) # per-user DSL
|
|
576
|
-
self.analyze_string_locally(script)
|
|
577
|
-
self.start_script()
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
| **Method** | **Description** |
|
|
581
|
-
| --------------------------------------- | ---------------------------------------------------- |
|
|
582
|
-
| `analyze_file_locally(path, encoding)` | Analyse a script file on this instance. |
|
|
583
|
-
| `analyze_string_locally(script)` | Analyse a DSL string on this instance. |
|
|
584
|
-
| `analyze_canvas_locally(file_path)` | Analyse an Obsidian `.canvas` file on this instance. |
|
|
585
|
-
| `analyze_executable_model_locally(model)` | Load a pre-built model dict on this instance. |
|
|
586
|
-
|
|
587
|
-
**Security**
|
|
588
|
-
|
|
589
|
-
When accepting scripts from untrusted users, restrict dangerous features via the
|
|
590
|
-
`RESTRICTED` class attribute. Set `DEFAULT_TIMEOUT` to control the fallback timeout,
|
|
591
|
-
and `DEFAULT_CONFIG` to provide a safe base config.
|
|
592
|
-
|
|
593
|
-
```python
|
|
594
|
-
class SafeDSL(telekit.InstanceDSLHandler):
|
|
595
|
-
RESTRICTED: list[RestrictedToken] = ["hook", "jinja", "redirect", "handoff", "config"]
|
|
596
|
-
DEFAULT_TIMEOUT = 120
|
|
597
|
-
DEFAULT_CONFIG = {"template": "vars"}
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
| **Token** | **Effect** |
|
|
601
|
-
| -------------- | ----------------------------------------------------------------------------------------------- |
|
|
602
|
-
| `"handoff"` | Disables `handoff` button type (cross-handler transitions). |
|
|
603
|
-
| `"redirect"` | Disables `redirect` button type (simulated user messages). |
|
|
604
|
-
| `"hook"` | Removes all `on_enter`, `on_enter_once`, `on_exit`, `on_timeout` hooks. |
|
|
605
|
-
| `"jinja"` | Forces template engine to `"vars"`; Jinja is never executed. |
|
|
606
|
-
| `"timeout"` | Ignores per-script `timeout_time`; uses `DEFAULT_TIMEOUT` only. |
|
|
607
|
-
| `"config"` | Replaces script config with `DEFAULT_CONFIG`; `vars_*` keys are preserved unless `"vars"` is also set. |
|
|
608
|
-
| `"vars"` | Removes all `vars_*` keys and disables `{{variable}}` substitution. |
|
|
609
|
-
| `"images"` | Strips `image` field from every scene. |
|
|
610
|
-
| `"links"` | Disables `link` button type (external URLs). |
|
|
611
|
-
| `"suggest"` | Disables `suggest` button type (pre-filled entry suggestions). |
|
|
612
|
-
| `"entry"` | Disables entry handlers (free-text input routing). |
|
|
613
|
-
| `"next"` | Disables `next` magic scene navigation. |
|
|
614
|
-
| `"back"` | Disables `back` magic scene navigation. |
|
|
615
|
-
|
|
616
|
-
## Scheduler
|
|
617
|
-
|
|
618
|
-
- Added `every` decorator for scheduling functions in a background daemon thread.
|
|
619
|
-
- Implemented `PeriodicTask` class to manage periodic execution and error handling.
|
|
620
|
-
|
|
621
|
-
## Others
|
|
622
|
-
|
|
623
|
-
- Enhanced `Debug` class with callback query tracing functionality.
|
|
624
|
-
- Refactored `BaseSender` to use `send_or_handle_error`.
|
|
480
|
+
# Changes in version 2.5.0
|
|
481
|
+
|
|
482
|
+
### v2.5.0`b0`
|
|
483
|
+
- Added support for t-strings (PEP 750, Python 3.14+) in `TextEntity`.
|
|
484
|
+
|
|
485
|
+
### v2.5.0`b1`
|
|
486
|
+
- Added `Sender.send_message` method.
|
|
487
|
+
- Added `utils.make_mention` utility for generating `tg://user?id=` mention links.
|
|
488
|
+
- Added new inline button types to `inline_buttons`:
|
|
489
|
+
- `ContactButton` — mentions a user by Telegram ID via `tg://user?id=`.
|
|
490
|
+
- `UserLinkButton` — opens a user profile by username; supports pre-filled message text.
|
|
491
|
+
- `BotLinkButton` — opens a bot by username; supports deep-link `?start=` payload.
|
|
492
|
+
- Added new methods to `InlineKeyboard`:
|
|
493
|
+
- `add_contact` — adds a `ContactButton`.
|
|
494
|
+
- `add_user_link` — adds a `UserLinkButton`.
|
|
495
|
+
- `add_bot_link` — adds a `BotLinkButton`.
|
|
496
|
+
|
|
497
|
+
### v2.5.0`b2`
|
|
498
|
+
- Added the `escape` parameter to `telekit.utils.*`:
|
|
499
|
+
- `make_user_link`
|
|
500
|
+
- `make_bot_link`
|
|
501
|
+
- `Handler.handlers_dict` now excludes private handlers (classes whose names start with `_`).
|
|
502
|
+
- Added `Debug.duplicate_handler_warnings` to warn about duplicate handler names during initialization.
|
|
503
|
+
- Added `Handler.chat` object (BETA)
|
|
504
|
+
|
|
505
|
+
### v2.5.0`b3`
|
|
506
|
+
- Added `utils.Markers` class
|
|
507
|
+
- Added `HTMLText` class for handling Telegram HTML strings with tag-aware indexing and slicing.
|
|
508
|
+
- Added `PaginatedText` trait for displaying long HTML text in a paginated format, supporting navigation and smart splitting.
|
|
509
|
+
- Added `__radd__` to `TextEntity`: `"Regular" + Bold(" and Bold")`
|
|
510
|
+
- Added `__mul__` to `TextEntity`: `Bold("Text") * 3`
|
|
511
|
+
- Added `enabled=` parameter to `TextEntity`: `Bold("bold text", enabled=is_text_bold)`
|
|
512
|
+
- Added `TextBuilder` class – a fluent message composition API mirroring `InlineKeyboard`'s builder pattern
|
|
513
|
+
- Added styles to `telekit.types`
|
|
514
|
+
- Added `utils.CyclicList`
|
|
515
|
+
- Fixed `_answer_callback_query` to always call `bot.answer_callback_query()`, even without a popup text
|
|
516
|
+
|
|
517
|
+
### v2.5.0`rc2`
|
|
518
|
+
- Refactor `CalendarPick` trait to use `set_keyboard`
|
|
@@ -39,7 +39,7 @@ Telekit comes with a [built-in DSL](https://github.com/Romashkaa/telekit/blob/ma
|
|
|
39
39
|
}
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
> See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/
|
|
42
|
+
> See the [full example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md)
|
|
43
43
|
|
|
44
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
|
|
|
@@ -97,36 +97,91 @@ The `handle` method sends a message and registers `handle_name` as the next step
|
|
|
97
97
|
|
|
98
98
|
### Inline Keyboards
|
|
99
99
|
|
|
100
|
-
|
|
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:
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
self.
|
|
106
|
-
|
|
107
|
-
choices={
|
|
108
|
-
"Option 1": "Value 1",
|
|
109
|
-
"Option 2": "Value 2",
|
|
110
|
-
"Option 3": [3, "Yes, it's an array"],
|
|
102
|
+
```python
|
|
103
|
+
self.chain.set_inline_keyboard(
|
|
104
|
+
{
|
|
105
|
+
"✏️ Change": self.change_name,
|
|
106
|
+
"❌ Delete": self.delete,
|
|
111
107
|
}
|
|
112
108
|
)
|
|
109
|
+
```
|
|
113
110
|
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
`row_width` controls how many buttons appear per row:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
self.chain.set_inline_keyboard(
|
|
115
|
+
{
|
|
116
|
+
"One": self.one,
|
|
117
|
+
"Two": self.two,
|
|
118
|
+
"Three": self.three,
|
|
119
|
+
"Four": self.four,
|
|
120
|
+
"Five": self.five,
|
|
121
|
+
},
|
|
122
|
+
row_width=(3, 2) # first row: 3 buttons, second row: 2
|
|
123
|
+
)
|
|
116
124
|
```
|
|
117
125
|
|
|
118
|
-
|
|
126
|
+
```
|
|
127
|
+
╭──────────┬──────────┬──────────╮
|
|
128
|
+
│ One │ Two │ Three │
|
|
129
|
+
├──────────┴──┬───────┴──────────┤
|
|
130
|
+
│ Four │ Five │
|
|
131
|
+
╰─────────────┴──────────────────╯
|
|
132
|
+
```
|
|
119
133
|
|
|
120
|
-
**
|
|
134
|
+
**Need more control?**
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
When you need precise row layout or conditional buttons, use `InlineKeyboard` — a fluent builder that composes keyboards step by step:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
self.chain.set_keyboard(
|
|
140
|
+
InlineKeyboard()
|
|
141
|
+
.add_callback("-", self.decrement, style="danger")
|
|
142
|
+
.add_callback("+", self.increment, style="success")
|
|
143
|
+
.row()
|
|
144
|
+
.add_callback("↺ Reset", self.reset)
|
|
145
|
+
)
|
|
127
146
|
```
|
|
128
147
|
|
|
129
|
-
|
|
148
|
+
```
|
|
149
|
+
╭──────────┬──────────╮
|
|
150
|
+
│ - │ + │
|
|
151
|
+
├──────────┴──────────┤
|
|
152
|
+
│ ↺ Reset │
|
|
153
|
+
╰─────────────────────╯
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> `InlineKeyboard` is built by chaining method calls. Just call `.row()` to start a new row.
|
|
157
|
+
|
|
158
|
+
**Not just callback buttons**
|
|
159
|
+
|
|
160
|
+
| **Method** | **Description** |
|
|
161
|
+
| --------------------- | ---------------------------------------------------------------- |
|
|
162
|
+
| `add_callback(...)` | Button that fires a callback function. |
|
|
163
|
+
| `add_link(...)` | Button that opens a URL. |
|
|
164
|
+
| `add_copy(...)` | Button that copies text to the clipboard. |
|
|
165
|
+
| `add_alert(...)` | Button that shows a popup alert dialog. |
|
|
166
|
+
| `add_notification(...)` | Button that shows a brief top-of-chat notification. |
|
|
167
|
+
| `add_static(...)` | Decorative button with no action. |
|
|
168
|
+
| `add_webapp(...)` | Button that opens a Telegram Mini App. |
|
|
169
|
+
| `add_suggest(...)` | Button that simulates the user sending a message. |
|
|
170
|
+
|
|
171
|
+
### Reply Keyboards
|
|
172
|
+
|
|
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.
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
self.chain.set_keyboard(
|
|
177
|
+
ReplyKeyboard(one_time_keyboard=True)
|
|
178
|
+
.add_text("Hello!")
|
|
179
|
+
.add_text("Hi")
|
|
180
|
+
.row()
|
|
181
|
+
.add_contact("📱 Share phone")
|
|
182
|
+
.add_location("📍 Share location")
|
|
183
|
+
)
|
|
184
|
+
```
|
|
130
185
|
|
|
131
186
|
### Command Parameters
|
|
132
187
|
|
|
@@ -150,7 +205,7 @@ class GreetHandler(telekit.Handler):
|
|
|
150
205
|
|
|
151
206
|
Now `/greet 64 "Alice Reingold"` or `/greet 128 Dracula` are parsed automatically.
|
|
152
207
|
|
|
153
|
-
> [!
|
|
208
|
+
> [!NOTE]
|
|
154
209
|
> If arguments are invalid or missing, you simply receive `None` and decide how to respond.
|
|
155
210
|
|
|
156
211
|
### Dialogue
|
|
@@ -206,7 +261,7 @@ self.chain.sender.send_chat_action(ChatAction.TYPING) # Send chat action. Use en
|
|
|
206
261
|
```
|
|
207
262
|
|
|
208
263
|
> [!NOTE]
|
|
209
|
-
> Telekit automatically decides whether to use
|
|
264
|
+
> Telekit automatically decides whether to use `bot.send_message` or `bot.send_photo` based on the content
|
|
210
265
|
|
|
211
266
|
### Styles
|
|
212
267
|
|
|
@@ -252,7 +307,7 @@ If you prefer not to write dialog logic in Python, you can use the built-in DSL
|
|
|
252
307
|
```py
|
|
253
308
|
import telekit
|
|
254
309
|
|
|
255
|
-
class QuizHandler(telekit.
|
|
310
|
+
class QuizHandler(telekit.DSLHandler):
|
|
256
311
|
@classmethod
|
|
257
312
|
def init_handler(cls) -> None:
|
|
258
313
|
cls.analyze_string(script)
|
|
@@ -302,7 +357,7 @@ telekit.Server(BOT_TOKEN).polling()
|
|
|
302
357
|
- Jinja template engine
|
|
303
358
|
|
|
304
359
|
<details>
|
|
305
|
-
<summary
|
|
360
|
+
<summary>🎆 Click to see what you can do with the DSL</summary>
|
|
306
361
|
<table>
|
|
307
362
|
<tr>
|
|
308
363
|
<td><img src="./docs/images/telekit_example_7.jpg" alt="Telekit Example 7" width="300"></td>
|
|
@@ -315,7 +370,8 @@ telekit.Server(BOT_TOKEN).polling()
|
|
|
315
370
|
</table>
|
|
316
371
|
</details>
|
|
317
372
|
|
|
318
|
-
|
|
373
|
+
> [!TIP]
|
|
374
|
+
> 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.
|
|
319
375
|
|
|
320
376
|
### Traits
|
|
321
377
|
|
|
@@ -24,12 +24,14 @@ from ._callback_query_handler import CallbackQueryHandler
|
|
|
24
24
|
from .server import Server, example
|
|
25
25
|
from ._inline_keyboard import InlineKeyboard
|
|
26
26
|
from ._reply_keyboard import ReplyKeyboard
|
|
27
|
+
from ._text_builder import TextBuilder
|
|
27
28
|
from ._snapvault import Vault
|
|
28
29
|
from ._chapters import chapters
|
|
29
30
|
from ._user import User
|
|
30
31
|
from ._telekit_dsl.telekit_dsl import TelekitDSL
|
|
31
32
|
from ._telekit_dsl.mixin import DSLHandler, InstanceDSLHandler
|
|
32
33
|
from ._logger import enable_file_logging
|
|
34
|
+
from .chat import Chat
|
|
33
35
|
|
|
34
36
|
from . import senders
|
|
35
37
|
from . import types
|
|
@@ -41,6 +43,8 @@ from . import utils
|
|
|
41
43
|
from . import traits
|
|
42
44
|
from . import debug
|
|
43
45
|
from . import scheduler
|
|
46
|
+
from . import chat
|
|
47
|
+
from . import html_text
|
|
44
48
|
|
|
45
49
|
Styles = styles.Styles
|
|
46
50
|
|
|
@@ -56,11 +60,14 @@ __all__ = [
|
|
|
56
60
|
"inline_buttons",
|
|
57
61
|
"dices",
|
|
58
62
|
"scheduler",
|
|
63
|
+
"chat",
|
|
64
|
+
"html_text",
|
|
59
65
|
|
|
60
66
|
"Styles",
|
|
61
67
|
"User",
|
|
62
68
|
|
|
63
|
-
"Server",
|
|
69
|
+
"Server",
|
|
70
|
+
"Chat",
|
|
64
71
|
"Chain",
|
|
65
72
|
"Trait",
|
|
66
73
|
"Handler",
|
|
@@ -68,6 +75,7 @@ __all__ = [
|
|
|
68
75
|
|
|
69
76
|
"InlineKeyboard",
|
|
70
77
|
"ReplyKeyboard",
|
|
78
|
+
"TextBuilder",
|
|
71
79
|
|
|
72
80
|
"TelekitDSL",
|
|
73
81
|
"DSLHandler",
|