telekit 2.2.0a3__tar.gz → 2.3.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.2.0a3/telekit.egg-info → telekit-2.3.0}/PKG-INFO +44 -48
- {telekit-2.2.0a3 → telekit-2.3.0}/README.md +41 -2
- {telekit-2.2.0a3 → telekit-2.3.0}/setup.py +1 -2
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/__init__.py +6 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_callback_query_handler.py +18 -6
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_chain.py +2 -1
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_chain_base.py +3 -3
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_chain_inline_keyboards_logic.py +1 -5
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_handler.py +7 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_init.py +1 -1
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_inline_buttons.py +114 -11
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_logger.py +42 -41
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_state.py +15 -2
- telekit-2.3.0/telekit/_trait.py +10 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_version.py +1 -1
- telekit-2.3.0/telekit/debug.py +8 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/__init__.py +2 -1
- telekit-2.3.0/telekit/example/example_handlers/calendar.py +155 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/entry.py +5 -1
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/spells.py +12 -13
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/start.py +2 -1
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/text_document.py +6 -2
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/inline_buttons.py +8 -2
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/senders.py +141 -41
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/server.py +7 -5
- telekit-2.3.0/telekit/traits/__init__.py +3 -0
- telekit-2.3.0/telekit/traits/calendar_pick.py +807 -0
- telekit-2.3.0/telekit/traits/paginated_choice.py +145 -0
- telekit-2.3.0/telekit/traits/track_handoff_origin.py +99 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/utils.py +190 -15
- {telekit-2.2.0a3 → telekit-2.3.0/telekit.egg-info}/PKG-INFO +44 -48
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit.egg-info/SOURCES.txt +8 -1
- {telekit-2.2.0a3 → telekit-2.3.0}/LICENSE +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/setup.cfg +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_buildtext/__init__.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_buildtext/formatter.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_buildtext/styles.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_chain_entry_logic.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_chapters/__init__.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_chapters/chapters.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_input_handler.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_on.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_snapvault/__init__.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_snapvault/snapcode.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_snapvault/snapvault.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/__init__.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/mixin.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/__init__.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/builder.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/canvas_parser.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/lexer.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/nodes.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/parser.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/parser/token.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/telekit_dsl.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_telekit_dsl/telekit_orm.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_timeout.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/_user.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/dices.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/__init__.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/complete_hotel.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/counter.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/dsl.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/faq.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/hotel.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/on_text.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/pages.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/pyapi.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/qr.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_handlers/quiz.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/example/example_server.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/parameters.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/styles.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit/types.py +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit.egg-info/dependency_links.txt +0 -0
- {telekit-2.2.0a3 → telekit-2.3.0}/telekit.egg-info/requires.txt +0 -0
- {telekit-2.2.0a3 → telekit-2.3.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.3.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
|
|
@@ -77,7 +77,7 @@ 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/quiz.md)
|
|
79
79
|
|
|
80
|
-
Even in its beta stage, Telekit accelerates bot development, offering typed command parameters, text styling via `Bold()`, `Italic()`, built-in emoji game results for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
|
|
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
83
|
- Declarative bot logic with **chains** for effortless handling of complex conversations
|
|
@@ -85,6 +85,7 @@ Even in its beta stage, Telekit accelerates bot development, offering typed comm
|
|
|
85
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
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
87
|
- Built-in **Permission** and **Logging** system for user management
|
|
88
|
+
- Reusable **Traits** system for pluggable, self-contained behavior modules
|
|
88
89
|
- Seamless integration with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
|
|
89
90
|
- Fast to develop and easy-to-extend code
|
|
90
91
|
|
|
@@ -101,7 +102,8 @@ Even in its beta stage, Telekit accelerates bot development, offering typed comm
|
|
|
101
102
|
- [Dialogue](https://github.com/Romashkaa/telekit/blob/main/docs/examples/dialogue.md)
|
|
102
103
|
- [Risk Game](https://github.com/Romashkaa/telekit/blob/main/docs/examples/risk_game.md)
|
|
103
104
|
- [Counter](https://github.com/Romashkaa/telekit/blob/main/docs/examples/counter.md)
|
|
104
|
-
- [Quiz (
|
|
105
|
+
- [Quiz (DSL)](https://github.com/Romashkaa/telekit/blob/main/docs/examples/quiz.md)
|
|
106
|
+
- [Hotel (DSL)](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md)
|
|
105
107
|
- [More...](https://github.com/Romashkaa/telekit/blob/main/docs/examples/examples.md)
|
|
106
108
|
|
|
107
109
|
## Overview
|
|
@@ -347,6 +349,42 @@ telekit.Server(BOT_TOKEN).polling()
|
|
|
347
349
|
|
|
348
350
|
You can find a [full quiz example](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md) and [DSL reference](https://github.com/Romashkaa/telekit/blob/main/docs/tutorial/11_telekit_dsl.md) in the repository.
|
|
349
351
|
|
|
352
|
+
### Traits
|
|
353
|
+
|
|
354
|
+
Traits are reusable behavior modules you can mix into any handler.
|
|
355
|
+
|
|
356
|
+
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.
|
|
357
|
+
|
|
358
|
+
```py
|
|
359
|
+
from telekit.traits import CalendarPick
|
|
360
|
+
|
|
361
|
+
class CalendarHandler(CalendarPick, telekit.Handler):
|
|
362
|
+
|
|
363
|
+
@classmethod
|
|
364
|
+
def init_handler(cls) -> None:
|
|
365
|
+
cls.on.command("calendar").invoke(cls.handle)
|
|
366
|
+
|
|
367
|
+
def handle(self) -> None:
|
|
368
|
+
self.chain.sender.set_title("📅 Choose a date")
|
|
369
|
+
self.chain.sender.set_message("Select any date — past or future:")
|
|
370
|
+
self.chain.sender.set_remove_text(False)
|
|
371
|
+
|
|
372
|
+
self.calendar_pick(self.handle_date) # HERE
|
|
373
|
+
|
|
374
|
+
def handle_date(self, date: datetime.date) -> None:
|
|
375
|
+
self.chain.sender.set_text(f"You picked: {date}")
|
|
376
|
+
self.chain.send()
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
<details>
|
|
380
|
+
<summary>Result</summary>
|
|
381
|
+
<table>
|
|
382
|
+
<tr>
|
|
383
|
+
<td><img src="./docs/images/calendar.png" alt="Telekit Calendar Example" width="500"></td>
|
|
384
|
+
</tr>
|
|
385
|
+
</table>
|
|
386
|
+
</details>
|
|
387
|
+
|
|
350
388
|
### Example Bot
|
|
351
389
|
|
|
352
390
|
You can launch an example bot by **running the following code**:
|
|
@@ -367,6 +405,7 @@ It includes example commands, dialogs, keyboards, and style usage.
|
|
|
367
405
|
- **Styles API** for rich text (`Bold`, `Italic`, `Links`) with **automatic escaping**.
|
|
368
406
|
- Deep linking and **typed command parameters**.
|
|
369
407
|
- **Built-in DSL** for menus, FAQs, and simple bots.
|
|
408
|
+
- Reusable **Traits** for composable, plug-and-play behavior (for example, a built-in declarative calendar picker).
|
|
370
409
|
- **Zero-code** [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
|
|
371
410
|
- Seamless integration with **pyTelegramBotAPI**.
|
|
372
411
|
|
|
@@ -378,49 +417,6 @@ It tries to make Telegram bot development easier.
|
|
|
378
417
|
|
|
379
418
|
---
|
|
380
419
|
|
|
381
|
-
# Changes in version 2.
|
|
382
|
-
|
|
383
|
-
## New Button Types
|
|
384
|
-
|
|
385
|
-
| **Name** | **Description** |
|
|
386
|
-
|----------------------|----------------------------------------------------------|
|
|
387
|
-
| `AlertButton` | A callback button that shows a popup alert when pressed. |
|
|
388
|
-
| `NotificationButton` | A callback button that shows a notification. |
|
|
389
|
-
| `InvokeButton` | A callback button that calls the object method. |
|
|
390
|
-
|
|
391
|
-
## User Improvements
|
|
392
|
-
|
|
393
|
-
| **Name** | **Description** |
|
|
394
|
-
| ---------------------- | --------------------------------------------------------- |
|
|
395
|
-
| `bio` | Bio of the user or description of the chat. |
|
|
396
|
-
| `birthdate` | Birthdate of the user, if set and visible. |
|
|
397
|
-
| `description` | Description of the group or channel. |
|
|
398
|
-
| `mention` | `tg://user?id=` deep link, works even without a username. |
|
|
399
|
-
| `is_private` | Whether the message was sent in a private chat. |
|
|
400
|
-
| `is_group` | Whether the message was sent in a group. |
|
|
401
|
-
| `is_supergroup` | Whether the message was sent in a supergroup. |
|
|
402
|
-
| `is_channel` | Whether the message was sent in a channel. |
|
|
403
|
-
| `avatar` | File ID of the user's most recent profile photo. |
|
|
404
|
-
| `profile_photos_count` | Total number of profile photos the user has set. |
|
|
405
|
-
|
|
406
|
-
- Refactor: `User` now accepts a `Message` object instead of `chat_id` + `from_user`. All properties are derived from `_sender` (`from_user` or `chat`) and migrated to `cached_property`. Fixed broken `get_id` and `get_full_name` references.
|
|
407
|
-
- Added `__repr__`.
|
|
408
|
-
|
|
409
|
-
## Sender Improvements
|
|
410
|
-
|
|
411
|
-
| **Name** | **Description** |
|
|
412
|
-
| -------------------------- | ------------------------------------------------------ |
|
|
413
|
-
| `sent_message` | The last message sent by this sender instance. |
|
|
414
|
-
| `disable_notification` | Disables notification sound when the message is sent. |
|
|
415
|
-
| `protect_content` | Protects the message contents from forwarding and saving. |
|
|
416
|
-
| `reply_parameters` | Reply parameters for the message to be sent. |
|
|
417
|
-
| `link_preview_options` | Link preview options for the message to be sent. |
|
|
418
|
-
| `show_caption_above_media` | Shows the caption above the media instead of below. |
|
|
419
|
-
|
|
420
|
-
- Refactored sending system.
|
|
421
|
-
|
|
422
|
-
## Chain Improvements
|
|
420
|
+
# Changes in version 2.3.0
|
|
423
421
|
|
|
424
|
-
|
|
425
|
-
| ----------- | ------------------------------------------------------------ |
|
|
426
|
-
| `received` | The message received from the user during entry processing. |
|
|
422
|
+
[View changelog on GitHub](https://github.com/Romashkaa/telekit/blob/main/CHANGELOG.md)
|
|
@@ -41,7 +41,7 @@ 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/quiz.md)
|
|
43
43
|
|
|
44
|
-
Even in its beta stage, Telekit accelerates bot development, offering typed command parameters, text styling via `Bold()`, `Italic()`, built-in emoji game results for `🎲 🎯 🏀 ⚽ 🎳 🎰`, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.
|
|
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
47
|
- Declarative bot logic with **chains** for effortless handling of complex conversations
|
|
@@ -49,6 +49,7 @@ Even in its beta stage, Telekit accelerates bot development, offering typed comm
|
|
|
49
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
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
51
|
- Built-in **Permission** and **Logging** system for user management
|
|
52
|
+
- Reusable **Traits** system for pluggable, self-contained behavior modules
|
|
52
53
|
- Seamless integration with [pyTelegramBotAPI](https://github.com/eternnoir/pyTelegramBotAPI)
|
|
53
54
|
- Fast to develop and easy-to-extend code
|
|
54
55
|
|
|
@@ -65,7 +66,8 @@ Even in its beta stage, Telekit accelerates bot development, offering typed comm
|
|
|
65
66
|
- [Dialogue](https://github.com/Romashkaa/telekit/blob/main/docs/examples/dialogue.md)
|
|
66
67
|
- [Risk Game](https://github.com/Romashkaa/telekit/blob/main/docs/examples/risk_game.md)
|
|
67
68
|
- [Counter](https://github.com/Romashkaa/telekit/blob/main/docs/examples/counter.md)
|
|
68
|
-
- [Quiz (
|
|
69
|
+
- [Quiz (DSL)](https://github.com/Romashkaa/telekit/blob/main/docs/examples/quiz.md)
|
|
70
|
+
- [Hotel (DSL)](https://github.com/Romashkaa/telekit/blob/main/docs/examples/complete_hotel.md)
|
|
69
71
|
- [More...](https://github.com/Romashkaa/telekit/blob/main/docs/examples/examples.md)
|
|
70
72
|
|
|
71
73
|
## Overview
|
|
@@ -311,6 +313,42 @@ telekit.Server(BOT_TOKEN).polling()
|
|
|
311
313
|
|
|
312
314
|
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.
|
|
313
315
|
|
|
316
|
+
### Traits
|
|
317
|
+
|
|
318
|
+
Traits are reusable behavior modules you can mix into any handler.
|
|
319
|
+
|
|
320
|
+
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.
|
|
321
|
+
|
|
322
|
+
```py
|
|
323
|
+
from telekit.traits import CalendarPick
|
|
324
|
+
|
|
325
|
+
class CalendarHandler(CalendarPick, telekit.Handler):
|
|
326
|
+
|
|
327
|
+
@classmethod
|
|
328
|
+
def init_handler(cls) -> None:
|
|
329
|
+
cls.on.command("calendar").invoke(cls.handle)
|
|
330
|
+
|
|
331
|
+
def handle(self) -> None:
|
|
332
|
+
self.chain.sender.set_title("📅 Choose a date")
|
|
333
|
+
self.chain.sender.set_message("Select any date — past or future:")
|
|
334
|
+
self.chain.sender.set_remove_text(False)
|
|
335
|
+
|
|
336
|
+
self.calendar_pick(self.handle_date) # HERE
|
|
337
|
+
|
|
338
|
+
def handle_date(self, date: datetime.date) -> None:
|
|
339
|
+
self.chain.sender.set_text(f"You picked: {date}")
|
|
340
|
+
self.chain.send()
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
<details>
|
|
344
|
+
<summary>Result</summary>
|
|
345
|
+
<table>
|
|
346
|
+
<tr>
|
|
347
|
+
<td><img src="./docs/images/calendar.png" alt="Telekit Calendar Example" width="500"></td>
|
|
348
|
+
</tr>
|
|
349
|
+
</table>
|
|
350
|
+
</details>
|
|
351
|
+
|
|
314
352
|
### Example Bot
|
|
315
353
|
|
|
316
354
|
You can launch an example bot by **running the following code**:
|
|
@@ -331,6 +369,7 @@ It includes example commands, dialogs, keyboards, and style usage.
|
|
|
331
369
|
- **Styles API** for rich text (`Bold`, `Italic`, `Links`) with **automatic escaping**.
|
|
332
370
|
- Deep linking and **typed command parameters**.
|
|
333
371
|
- **Built-in DSL** for menus, FAQs, and simple bots.
|
|
372
|
+
- Reusable **Traits** for composable, plug-and-play behavior (for example, a built-in declarative calendar picker).
|
|
334
373
|
- **Zero-code** [Obsidian Canvas](https://github.com/Romashkaa/telekit/blob/main/docs/examples/canvas_faq.md) mode.
|
|
335
374
|
- Seamless integration with **pyTelegramBotAPI**.
|
|
336
375
|
|
|
@@ -28,8 +28,7 @@ def readme():
|
|
|
28
28
|
return f.read()
|
|
29
29
|
|
|
30
30
|
def changelog():
|
|
31
|
-
|
|
32
|
-
return f.read()
|
|
31
|
+
return f"[View changelog on GitHub](https://github.com/Romashkaa/telekit/blob/main/CHANGELOG.md)"
|
|
33
32
|
|
|
34
33
|
def install_requires():
|
|
35
34
|
with open('telekit/requirements.txt', 'r') as f:
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#
|
|
19
19
|
|
|
20
20
|
from ._handler import Handler
|
|
21
|
+
from ._trait import Trait
|
|
21
22
|
from ._chain import Chain
|
|
22
23
|
from ._callback_query_handler import CallbackQueryHandler
|
|
23
24
|
from .server import Server, example
|
|
@@ -35,12 +36,15 @@ from . import parameters
|
|
|
35
36
|
from . import inline_buttons
|
|
36
37
|
from . import dices
|
|
37
38
|
from . import utils
|
|
39
|
+
from . import traits
|
|
40
|
+
from . import debug
|
|
38
41
|
|
|
39
42
|
Styles = styles.Styles
|
|
40
43
|
|
|
41
44
|
from ._version import __version__
|
|
42
45
|
|
|
43
46
|
__all__ = [
|
|
47
|
+
"traits",
|
|
44
48
|
"utils",
|
|
45
49
|
"senders",
|
|
46
50
|
"types",
|
|
@@ -54,6 +58,7 @@ __all__ = [
|
|
|
54
58
|
|
|
55
59
|
"Server",
|
|
56
60
|
"Chain",
|
|
61
|
+
"Trait",
|
|
57
62
|
"Handler",
|
|
58
63
|
"CallbackQueryHandler",
|
|
59
64
|
|
|
@@ -64,4 +69,5 @@ __all__ = [
|
|
|
64
69
|
"enable_file_logging",
|
|
65
70
|
"chapters",
|
|
66
71
|
"example",
|
|
72
|
+
"debug",
|
|
67
73
|
]
|
|
@@ -40,15 +40,17 @@ class CallbackQueryHandler:
|
|
|
40
40
|
bot (TeleBot): The Telegram bot instance to be used for sending messages.
|
|
41
41
|
"""
|
|
42
42
|
cls.bot = bot
|
|
43
|
-
cls.user_button_callbacks: dict[int, dict[str, Callable[[
|
|
43
|
+
cls.user_button_callbacks: dict[int, dict[str, Callable[[CallbackQuery], None]]] = {}
|
|
44
44
|
|
|
45
45
|
@bot.callback_query_handler(func=lambda call: True)
|
|
46
|
-
def handle(call:
|
|
46
|
+
def handle(call: CallbackQuery) -> None:
|
|
47
47
|
if not call.data:
|
|
48
48
|
return
|
|
49
49
|
|
|
50
50
|
if call.data.startswith(cls.INLINE_BUTTON):
|
|
51
51
|
cls._handle_inline_button(call)
|
|
52
|
+
elif call.data.startswith(cls.STATIC_BUTTON):
|
|
53
|
+
cls._handle_static_button(call)
|
|
52
54
|
elif call.data.startswith(cls.SUGGEST):
|
|
53
55
|
cls._handle_suggestion(call)
|
|
54
56
|
else:
|
|
@@ -59,7 +61,7 @@ class CallbackQueryHandler:
|
|
|
59
61
|
# –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
60
62
|
|
|
61
63
|
@classmethod
|
|
62
|
-
def _handle_inline_button(cls, call:
|
|
64
|
+
def _handle_inline_button(cls, call: CallbackQuery):
|
|
63
65
|
if not call.data:
|
|
64
66
|
cls.bot.answer_callback_query(call.id, text=cls._invalid_data_answer[0], show_alert=cls._invalid_data_answer[1])
|
|
65
67
|
return
|
|
@@ -76,10 +78,19 @@ class CallbackQueryHandler:
|
|
|
76
78
|
cls.bot.answer_callback_query(call.id, text=cls._button_is_no_active_answer[0], show_alert=cls._button_is_no_active_answer[1])
|
|
77
79
|
return
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
if not getattr(callback, "_persistent", False):
|
|
82
|
+
cls.remove_user_button_callbacks(call.from_user.id)
|
|
80
83
|
|
|
81
84
|
callback(call)
|
|
82
85
|
|
|
86
|
+
# –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
87
|
+
# Static Buttons Handling
|
|
88
|
+
# –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def _handle_static_button(cls, call: CallbackQuery):
|
|
92
|
+
cls.bot.answer_callback_query(call.id, text="")
|
|
93
|
+
|
|
83
94
|
# –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
84
95
|
# Suggestion Handling
|
|
85
96
|
# –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
@@ -87,7 +98,7 @@ class CallbackQueryHandler:
|
|
|
87
98
|
@classmethod
|
|
88
99
|
def _handle_suggestion(cls, call: CallbackQuery):
|
|
89
100
|
text: str = str(call.data)[len(cls.SUGGEST):]
|
|
90
|
-
cls.simulate(call.message, text, from_user=call.from_user)
|
|
101
|
+
cls.simulate(call.message, text, from_user=call.from_user) # pyright: ignore[reportArgumentType]
|
|
91
102
|
cls.bot.answer_callback_query(call.id)
|
|
92
103
|
|
|
93
104
|
@classmethod
|
|
@@ -126,9 +137,10 @@ class CallbackQueryHandler:
|
|
|
126
137
|
# Query Types
|
|
127
138
|
# –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
128
139
|
|
|
140
|
+
STATIC_BUTTON: str = "static_button"
|
|
129
141
|
INLINE_BUTTON: str = "inline_button:"
|
|
130
142
|
SUGGEST: str = "suggest:"
|
|
131
|
-
|
|
143
|
+
|
|
132
144
|
@classmethod
|
|
133
145
|
def suggest(cls, suggestion: str):
|
|
134
146
|
return f"{cls.SUGGEST}{suggestion}"
|
|
@@ -26,6 +26,7 @@ from telebot.types import Message
|
|
|
26
26
|
|
|
27
27
|
# Local modules
|
|
28
28
|
from . import senders
|
|
29
|
+
from .debug import Debug
|
|
29
30
|
from .styles import TextEntity
|
|
30
31
|
|
|
31
32
|
# Chain modules
|
|
@@ -154,7 +155,7 @@ class Chain(ChainInlineKeyboardLogic, ChainEntryLogic):
|
|
|
154
155
|
self.sender.set_edit_message(None)
|
|
155
156
|
self._previous_message = message
|
|
156
157
|
|
|
157
|
-
if
|
|
158
|
+
if Debug.timeout_warnings and _handler and not _timeout:
|
|
158
159
|
library.warning(
|
|
159
160
|
"Next-message handler is active, but no timeout was set for the chain. "
|
|
160
161
|
"This may cause the bot to wait indefinitely."
|
|
@@ -31,14 +31,13 @@ from . import _input_handler
|
|
|
31
31
|
from . import _timeout
|
|
32
32
|
|
|
33
33
|
# Logging
|
|
34
|
+
from .debug import Debug
|
|
34
35
|
from ._logger import logger
|
|
35
36
|
library = logger.library
|
|
36
37
|
|
|
37
38
|
class ChainBase:
|
|
38
39
|
|
|
39
40
|
bot: telebot.TeleBot
|
|
40
|
-
|
|
41
|
-
_timeout_warnings_enabled: bool = True
|
|
42
41
|
|
|
43
42
|
@classmethod
|
|
44
43
|
def _init(cls, bot: telebot.TeleBot):
|
|
@@ -206,4 +205,5 @@ class ChainBase:
|
|
|
206
205
|
# Timeout API
|
|
207
206
|
|
|
208
207
|
def disable_timeout_warnings(self, value: bool = True) -> None:
|
|
209
|
-
|
|
208
|
+
""".. deprecated:: Set ``Debug.timeout_warnings`` directly."""
|
|
209
|
+
Debug.timeout_warnings = not value
|
|
@@ -40,8 +40,7 @@ if typing.TYPE_CHECKING:
|
|
|
40
40
|
class ChainInlineKeyboardLogic(ChainBase):
|
|
41
41
|
def set_inline_keyboard(
|
|
42
42
|
self,
|
|
43
|
-
keyboard: dict[str,
|
|
44
|
-
*,
|
|
43
|
+
keyboard: dict[str, Any],
|
|
45
44
|
row_width: int | Iterable[int] = 1
|
|
46
45
|
) -> None:
|
|
47
46
|
"""
|
|
@@ -118,7 +117,6 @@ class ChainInlineKeyboardLogic(ChainBase):
|
|
|
118
117
|
def inline_keyboard[Caption: str, Value](
|
|
119
118
|
self,
|
|
120
119
|
keyboard: dict[Caption, Value],
|
|
121
|
-
*,
|
|
122
120
|
row_width: int | Iterable[int] = 1,
|
|
123
121
|
enable_special_buttons: bool = True
|
|
124
122
|
) -> Callable[[Callable[[Value], None]], None]:
|
|
@@ -183,7 +181,6 @@ class ChainInlineKeyboardLogic(ChainBase):
|
|
|
183
181
|
def inline_choice(
|
|
184
182
|
self,
|
|
185
183
|
choices: list[Any] | tuple[Any, ...] | dict[str, Any | InlineButton],
|
|
186
|
-
*,
|
|
187
184
|
row_width: int | Iterable[int] = 1,
|
|
188
185
|
enable_special_buttons: bool = True
|
|
189
186
|
) -> Callable[[Callable[[Any], None]], None]:
|
|
@@ -219,7 +216,6 @@ class ChainInlineKeyboardLogic(ChainBase):
|
|
|
219
216
|
self,
|
|
220
217
|
func: Callable[[Any], None],
|
|
221
218
|
choices: list[Any] | tuple[Any, ...] | dict[str, Any | InlineButton],
|
|
222
|
-
*,
|
|
223
219
|
row_width: int | Iterable[int] = 1,
|
|
224
220
|
enable_special_buttons: bool = True
|
|
225
221
|
) -> None:
|
|
@@ -225,9 +225,16 @@ class Handler:
|
|
|
225
225
|
|
|
226
226
|
handler_instance = handler(self.message)
|
|
227
227
|
handler_instance.chain._set_previous_message(self.chain.get_previous_message())
|
|
228
|
+
handler_instance._on_handoff(self)
|
|
228
229
|
|
|
229
230
|
return handler_instance
|
|
230
231
|
|
|
232
|
+
|
|
233
|
+
def _on_handoff(self, origin: "Handler") -> None:
|
|
234
|
+
"""Called when this handler is reached via handoff(). Override to customize."""
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
|
|
231
238
|
def freeze(self, func, *args):
|
|
232
239
|
"""
|
|
233
240
|
Return a zero-argument callback that invokes the given function
|
|
@@ -26,14 +26,18 @@ from telebot.types import InlineKeyboardButton, CallbackQuery
|
|
|
26
26
|
from telebot import TeleBot
|
|
27
27
|
from ._callback_query_handler import CallbackQueryHandler
|
|
28
28
|
|
|
29
|
+
from ._state import TelekitState
|
|
30
|
+
|
|
29
31
|
__all__ = [
|
|
30
|
-
"InlineButton",
|
|
32
|
+
"InlineButton",
|
|
31
33
|
|
|
34
|
+
"StaticButton",
|
|
32
35
|
"LinkButton",
|
|
33
36
|
"WebAppButton",
|
|
34
37
|
"SuggestButton",
|
|
35
38
|
"CopyTextButton",
|
|
36
39
|
"CallbackButton",
|
|
40
|
+
"AnswerButton",
|
|
37
41
|
"AlertButton",
|
|
38
42
|
"NotificationButton",
|
|
39
43
|
"InvokeButton",
|
|
@@ -57,9 +61,11 @@ class InlineButton:
|
|
|
57
61
|
- `SuggestButton`
|
|
58
62
|
- `CopyTextButton`
|
|
59
63
|
- `CallbackButton`
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
- `InvokeButton`
|
|
65
|
+
- `AnswerButton`
|
|
66
|
+
- `AlertButton`
|
|
67
|
+
- `NotificationButton`
|
|
68
|
+
- `StaticButton`
|
|
63
69
|
"""
|
|
64
70
|
|
|
65
71
|
_bot: TeleBot
|
|
@@ -70,12 +76,14 @@ class InlineButton:
|
|
|
70
76
|
|
|
71
77
|
MAX_SIZE: int | None = None
|
|
72
78
|
MIN_SIZE: int | None = None
|
|
73
|
-
|
|
79
|
+
|
|
80
|
+
Static: type["StaticButton"]
|
|
74
81
|
Link: type["LinkButton"]
|
|
75
82
|
WebApp: type["WebAppButton"]
|
|
76
83
|
Suggest: type["SuggestButton"]
|
|
77
84
|
CopyText: type["CopyTextButton"]
|
|
78
85
|
Callback: type["CallbackButton"]
|
|
86
|
+
Answer: type["AnswerButton"]
|
|
79
87
|
Alert: type["AlertButton"]
|
|
80
88
|
Notification: type["NotificationButton"]
|
|
81
89
|
Invoke: type["InvokeButton"]
|
|
@@ -115,7 +123,29 @@ class InlineButton:
|
|
|
115
123
|
return normalized
|
|
116
124
|
raise ValueError(f"Unknown style: {style!r}. Must be one of {_BUTTON_STYLES_LIST}")
|
|
117
125
|
raise TypeError(f"Style must be str, ButtonStyle, or None, got {type(style)}")
|
|
126
|
+
|
|
127
|
+
def _normalize_custom_emoji_id(self, custom_emoji_id: int | str | None) -> str | None:
|
|
128
|
+
if not custom_emoji_id:
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
if not TelekitState.is_premium():
|
|
132
|
+
return None
|
|
118
133
|
|
|
134
|
+
return str(custom_emoji_id)
|
|
135
|
+
|
|
136
|
+
class StaticButton(InlineButton):
|
|
137
|
+
|
|
138
|
+
def __init__(self, *, style: str | None | ButtonStyle = None, **kwargs):
|
|
139
|
+
self._style = self._normalize_style(style)
|
|
140
|
+
self._kwargs = kwargs
|
|
141
|
+
|
|
142
|
+
def _compile(self, caption: str) -> InlineKeyboardButton:
|
|
143
|
+
return InlineKeyboardButton(
|
|
144
|
+
text=caption,
|
|
145
|
+
callback_data=CallbackQueryHandler.STATIC_BUTTON,
|
|
146
|
+
style=self._style,
|
|
147
|
+
**self._kwargs,
|
|
148
|
+
)
|
|
119
149
|
|
|
120
150
|
class LinkButton(InlineButton):
|
|
121
151
|
"""
|
|
@@ -339,8 +369,8 @@ class CallbackButton(InlineButton):
|
|
|
339
369
|
|
|
340
370
|
def __call__(self, call: CallbackQuery):
|
|
341
371
|
self._invoke_chain_callback()
|
|
342
|
-
self._invoke_callback()
|
|
343
372
|
self._answer_callback_query(call)
|
|
373
|
+
self._invoke_callback()
|
|
344
374
|
|
|
345
375
|
def __init__(
|
|
346
376
|
self,
|
|
@@ -387,7 +417,77 @@ class CallbackButton(InlineButton):
|
|
|
387
417
|
callback=callback,
|
|
388
418
|
)
|
|
389
419
|
|
|
390
|
-
class
|
|
420
|
+
class AnswerButton(CallbackButton):
|
|
421
|
+
|
|
422
|
+
class _CallbackInvoker(CallbackButton._CallbackInvoker):
|
|
423
|
+
def __init__(
|
|
424
|
+
self,
|
|
425
|
+
chain_callback: Callable[[], None],
|
|
426
|
+
|
|
427
|
+
answer_text: str | None = None,
|
|
428
|
+
answer_as_alert: bool = True,
|
|
429
|
+
|
|
430
|
+
persistent: bool = True,
|
|
431
|
+
|
|
432
|
+
style: str | None | ButtonStyle = None,
|
|
433
|
+
|
|
434
|
+
kwargs: dict[str, Any] = {}
|
|
435
|
+
):
|
|
436
|
+
self._answer_text = answer_text
|
|
437
|
+
self._answer_as_alert = answer_as_alert
|
|
438
|
+
|
|
439
|
+
self._persistent = persistent
|
|
440
|
+
|
|
441
|
+
self._style = style
|
|
442
|
+
|
|
443
|
+
self._kwargs = {"style": style} | kwargs
|
|
444
|
+
|
|
445
|
+
self._chain_callback: Callable[[], None] = chain_callback
|
|
446
|
+
|
|
447
|
+
def _answer_callback_query(self, call: CallbackQuery):
|
|
448
|
+
if self._answer_text:
|
|
449
|
+
InlineButton._bot.answer_callback_query(
|
|
450
|
+
call.id,
|
|
451
|
+
self._answer_text,
|
|
452
|
+
self._answer_as_alert
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
def __call__(self, call: CallbackQuery):
|
|
456
|
+
if not self._persistent:
|
|
457
|
+
self._invoke_chain_callback()
|
|
458
|
+
self._answer_callback_query(call)
|
|
459
|
+
|
|
460
|
+
def __init__(
|
|
461
|
+
self,
|
|
462
|
+
answer_text: str | None = None,
|
|
463
|
+
answer_as_alert: bool = True,
|
|
464
|
+
|
|
465
|
+
persistent: bool = True,
|
|
466
|
+
|
|
467
|
+
style: str | None | ButtonStyle = None,
|
|
468
|
+
|
|
469
|
+
**kwargs
|
|
470
|
+
):
|
|
471
|
+
self._answer_text = answer_text
|
|
472
|
+
self._answer_as_alert = answer_as_alert
|
|
473
|
+
|
|
474
|
+
self._persistent = persistent
|
|
475
|
+
|
|
476
|
+
self._style = self._normalize_style(style)
|
|
477
|
+
|
|
478
|
+
self._kwargs = kwargs
|
|
479
|
+
|
|
480
|
+
def build_invoker(self, chain_callback: Callable[[], None]) -> _CallbackInvoker:
|
|
481
|
+
return self._CallbackInvoker(
|
|
482
|
+
chain_callback=chain_callback,
|
|
483
|
+
answer_text=self._answer_text,
|
|
484
|
+
answer_as_alert=self._answer_as_alert,
|
|
485
|
+
persistent=self._persistent,
|
|
486
|
+
style=self._style,
|
|
487
|
+
kwargs=self._kwargs
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
class AlertButton(AnswerButton):
|
|
391
491
|
"""
|
|
392
492
|
An inline keyboard button that shows a popup alert when pressed and terminates the chain.
|
|
393
493
|
|
|
@@ -424,19 +524,19 @@ class AlertButton(CallbackButton):
|
|
|
424
524
|
def __init__(
|
|
425
525
|
self,
|
|
426
526
|
text: str | None = None,
|
|
427
|
-
|
|
527
|
+
persistent: bool = True,
|
|
428
528
|
style: str | None | ButtonStyle = None,
|
|
429
529
|
**kwargs
|
|
430
530
|
):
|
|
431
531
|
super().__init__(
|
|
432
|
-
callback=None,
|
|
433
532
|
answer_text=text,
|
|
434
533
|
answer_as_alert=True,
|
|
534
|
+
persistent=persistent,
|
|
435
535
|
style=style,
|
|
436
536
|
**kwargs
|
|
437
537
|
)
|
|
438
538
|
|
|
439
|
-
class NotificationButton(
|
|
539
|
+
class NotificationButton(AnswerButton):
|
|
440
540
|
"""
|
|
441
541
|
An inline keyboard button that shows a brief notification at the top of the chat screen
|
|
442
542
|
when pressed and terminates the chain.
|
|
@@ -475,13 +575,14 @@ class NotificationButton(CallbackButton):
|
|
|
475
575
|
self,
|
|
476
576
|
text: str | None = None,
|
|
477
577
|
*,
|
|
578
|
+
persistent: bool = True,
|
|
478
579
|
style: str | None | ButtonStyle = None,
|
|
479
580
|
**kwargs
|
|
480
581
|
):
|
|
481
582
|
super().__init__(
|
|
482
|
-
callback=None,
|
|
483
583
|
answer_text=text,
|
|
484
584
|
answer_as_alert=False,
|
|
585
|
+
persistent=persistent,
|
|
485
586
|
style=style,
|
|
486
587
|
**kwargs
|
|
487
588
|
)
|
|
@@ -611,10 +712,12 @@ class InvokeButton(CallbackButton):
|
|
|
611
712
|
)
|
|
612
713
|
|
|
613
714
|
InlineButton.Link = LinkButton
|
|
715
|
+
InlineButton.Static = StaticButton
|
|
614
716
|
InlineButton.WebApp = WebAppButton
|
|
615
717
|
InlineButton.Suggest = SuggestButton
|
|
616
718
|
InlineButton.CopyText = CopyTextButton
|
|
617
719
|
InlineButton.Callback = CallbackButton
|
|
720
|
+
InlineButton.Answer = AnswerButton
|
|
618
721
|
InlineButton.Alert = AlertButton
|
|
619
722
|
InlineButton.Notification = NotificationButton
|
|
620
723
|
InlineButton.Invoke = InvokeButton
|