telekit 2.2.0a1__tar.gz → 2.2.0a2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {telekit-2.2.0a1/telekit.egg-info → telekit-2.2.0a2}/PKG-INFO +24 -10
  2. telekit-2.2.0a2/telekit/_user.py +199 -0
  3. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_version.py +1 -1
  4. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/entry.py +1 -3
  5. {telekit-2.2.0a1 → telekit-2.2.0a2/telekit.egg-info}/PKG-INFO +24 -10
  6. telekit-2.2.0a1/telekit/_user.py +0 -116
  7. {telekit-2.2.0a1 → telekit-2.2.0a2}/LICENSE +0 -0
  8. {telekit-2.2.0a1 → telekit-2.2.0a2}/README.md +0 -0
  9. {telekit-2.2.0a1 → telekit-2.2.0a2}/setup.cfg +0 -0
  10. {telekit-2.2.0a1 → telekit-2.2.0a2}/setup.py +0 -0
  11. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/__init__.py +0 -0
  12. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_buildtext/__init__.py +0 -0
  13. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_buildtext/formatter.py +0 -0
  14. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_buildtext/styles.py +0 -0
  15. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_callback_query_handler.py +0 -0
  16. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_chain.py +0 -0
  17. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_chain_base.py +0 -0
  18. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_chain_entry_logic.py +0 -0
  19. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_chain_inline_keyboards_logic.py +0 -0
  20. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_chapters/__init__.py +0 -0
  21. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_chapters/chapters.py +0 -0
  22. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_handler.py +0 -0
  23. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_init.py +0 -0
  24. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_inline_buttons.py +0 -0
  25. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_input_handler.py +0 -0
  26. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_logger.py +0 -0
  27. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_on.py +0 -0
  28. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_snapvault/__init__.py +0 -0
  29. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_snapvault/snapcode.py +0 -0
  30. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_snapvault/snapvault.py +0 -0
  31. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_state.py +0 -0
  32. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/__init__.py +0 -0
  33. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/mixin.py +0 -0
  34. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/__init__.py +0 -0
  35. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/builder.py +0 -0
  36. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/canvas_parser.py +0 -0
  37. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/lexer.py +0 -0
  38. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/nodes.py +0 -0
  39. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/parser.py +0 -0
  40. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/parser/token.py +0 -0
  41. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/telekit_dsl.py +0 -0
  42. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_telekit_dsl/telekit_orm.py +0 -0
  43. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/_timeout.py +0 -0
  44. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/dices.py +0 -0
  45. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/__init__.py +0 -0
  46. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/__init__.py +0 -0
  47. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/complete_hotel.py +0 -0
  48. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/counter.py +0 -0
  49. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/dsl.py +0 -0
  50. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/faq.py +0 -0
  51. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/hotel.py +0 -0
  52. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/on_text.py +0 -0
  53. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/pages.py +0 -0
  54. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/pyapi.py +0 -0
  55. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/qr.py +0 -0
  56. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/quiz.py +0 -0
  57. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/spells.py +0 -0
  58. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/start.py +0 -0
  59. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_handlers/text_document.py +0 -0
  60. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/example/example_server.py +0 -0
  61. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/inline_buttons.py +0 -0
  62. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/parameters.py +0 -0
  63. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/senders.py +0 -0
  64. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/server.py +0 -0
  65. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/styles.py +0 -0
  66. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/types.py +0 -0
  67. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit/utils.py +0 -0
  68. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit.egg-info/SOURCES.txt +0 -0
  69. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit.egg-info/dependency_links.txt +0 -0
  70. {telekit-2.2.0a1 → telekit-2.2.0a2}/telekit.egg-info/requires.txt +0 -0
  71. {telekit-2.2.0a1 → telekit-2.2.0a2}/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.2.0a1
3
+ Version: 2.2.0a2
4
4
  Summary: Declarative, developer-friendly library for building Telegram bots
5
5
  Home-page: https://github.com/Romashkaa/telekit
6
6
  Author: romashka
@@ -378,15 +378,29 @@ It tries to make Telegram bot development easier.
378
378
 
379
379
  ---
380
380
 
381
- # Changes in version 2.2.0a1
381
+ # Changes in version 2.2.0a2
382
382
 
383
383
  ## New Button Types
384
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 brief notification at the top of the chat screen. |
389
-
390
- ## User Refactor
391
-
392
- `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.
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
+
390
+ ## User Improvements
391
+
392
+ | **Name** | **Description** |
393
+ | ---------------------- | --------------------------------------------------------- |
394
+ | `bio` | Bio of the user or description of the chat. |
395
+ | `birthdate` | Birthdate of the user, if set and visible. |
396
+ | `description` | Description of the group or channel. |
397
+ | `mention` | `tg://user?id=` deep link, works even without a username. |
398
+ | `is_private` | Whether the message was sent in a private chat. |
399
+ | `is_group` | Whether the message was sent in a group. |
400
+ | `is_supergroup` | Whether the message was sent in a supergroup. |
401
+ | `is_channel` | Whether the message was sent in a channel. |
402
+ | `avatar` | File ID of the user's most recent profile photo. |
403
+ | `profile_photos_count` | Total number of profile photos the user has set. |
404
+
405
+ - 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.
406
+ - Added `__repr__`.
@@ -0,0 +1,199 @@
1
+ #
2
+ # Copyright (C) 2026 Romashka
3
+ #
4
+ # 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
9
+ # (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
14
+ # the GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Telekit. If not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+ from functools import cached_property
20
+ from typing import Literal
21
+
22
+ import telebot
23
+ import telebot.types
24
+
25
+ from ._logger import logger
26
+
27
+ __all__ = ["User"]
28
+
29
+
30
+ class User:
31
+
32
+ bot: telebot.TeleBot
33
+
34
+ @classmethod
35
+ def _init(cls, bot: telebot.TeleBot) -> None:
36
+ cls.bot = bot
37
+
38
+ def __init__(self, message: telebot.types.Message) -> None:
39
+ self._message: telebot.types.Message = message
40
+ self._chat_id: int = message.chat.id
41
+ self.logger = logger.users(self._chat_id)
42
+
43
+ # ── Internal ──────────────────────────────────────────────────
44
+
45
+ @cached_property
46
+ def _sender(self) -> telebot.types.User | telebot.types.Chat:
47
+ """Resolves to `from_user` if available, otherwise falls back to `chat`."""
48
+ return self._message.from_user or self._message.chat
49
+
50
+ # ── Logging ───────────────────────────────────────────────────
51
+
52
+ def enable_logging(self, *user_ids: int | str) -> None:
53
+ """
54
+ Enable logging for this user or for additional user IDs.
55
+ If no arguments are passed, enables logging for this instance's chat ID.
56
+ """
57
+ logger.enable_user_logging(*(user_ids or (self._chat_id,)))
58
+
59
+ # ── Telegram native fields ────────────────────────────────────
60
+
61
+ @property
62
+ def id(self) -> int:
63
+ """Unique identifier of the user or chat."""
64
+ return self._sender.id
65
+
66
+ @property
67
+ def username(self) -> str | None:
68
+ """Telegram username without the leading `@`, or `None` if not set."""
69
+ return self._sender.username
70
+
71
+ @cached_property
72
+ def first_name(self) -> str | None:
73
+ """First name of the user, or the group/channel title as a fallback."""
74
+ if isinstance(self._sender, telebot.types.User):
75
+ return self._sender.first_name
76
+ return self._sender.first_name or self._sender.title
77
+
78
+ @property
79
+ def last_name(self) -> str | None:
80
+ """Last name of the user, or `None` for chats and users without one."""
81
+ return self._sender.last_name
82
+
83
+ @cached_property
84
+ def is_bot(self) -> bool:
85
+ """Whether the sender is a bot. Always `False` for chats."""
86
+ if isinstance(self._sender, telebot.types.User):
87
+ return self._sender.is_bot
88
+ return False
89
+
90
+ @cached_property
91
+ def language_code(self) -> str | None:
92
+ """
93
+ IETF language code of the user's Telegram client (e.g. `"en"`, `"uk"`).
94
+ Always `None` for chats.
95
+ """
96
+ if isinstance(self._sender, telebot.types.User):
97
+ return self._sender.language_code
98
+ return None
99
+
100
+ @cached_property
101
+ def is_premium(self) -> bool:
102
+ """Whether the user has an active Telegram Premium subscription.
103
+ Always `False` for chats and bots.
104
+ """
105
+ if isinstance(self._sender, telebot.types.User):
106
+ return bool(self._sender.is_premium)
107
+ return False
108
+
109
+ @cached_property
110
+ def added_to_attachment_menu(self) -> bool:
111
+ """Whether this bot has been added to the user's attachment menu.
112
+ Always `False` for chats.
113
+ """
114
+ if isinstance(self._sender, telebot.types.User):
115
+ return bool(self._sender.added_to_attachment_menu)
116
+ return False
117
+
118
+ @property
119
+ def chat_type(self) -> Literal["private", "group", "supergroup", "channel"]:
120
+ """Type of the chat the message was sent in."""
121
+ return self._message.chat.type # pyright: ignore[reportReturnType]
122
+
123
+ @property
124
+ def bio(self) -> str | None:
125
+ """Bio of the user or description of the chat, as set in Telegram."""
126
+ return self._message.chat.bio
127
+
128
+ @property
129
+ def birthdate(self) -> telebot.types.Birthdate | None:
130
+ """Birthdate of the user, if set and visible."""
131
+ return self._message.chat.birthdate
132
+
133
+ @property
134
+ def description(self) -> str | None:
135
+ """Description of the group or channel. `None` for private chats."""
136
+ return self._message.chat.description
137
+
138
+ # ── Computed helpers ──────────────────────────────────────────
139
+
140
+ @cached_property
141
+ def full_name(self) -> str | None:
142
+ """Full name of the user (`first_name + last_name`), or the chat title.
143
+ Returns `None` if neither is available.
144
+ """
145
+ if isinstance(self._sender, telebot.types.User):
146
+ return self._sender.full_name
147
+ return " ".join(filter(None, [self.first_name, self.last_name])) or None
148
+
149
+ @property
150
+ def mention(self) -> str:
151
+ """
152
+ A `tg://user?id=` deep link that mentions the user in any context,
153
+ even without a username.
154
+ """
155
+ return f"tg://user?id={self.id}"
156
+
157
+ @property
158
+ def is_private(self) -> bool:
159
+ """Whether the message was sent in a private chat."""
160
+ return self.chat_type == "private"
161
+
162
+ @property
163
+ def is_group(self) -> bool:
164
+ """Whether the message was sent in a group chat."""
165
+ return self.chat_type == "group"
166
+
167
+ @property
168
+ def is_supergroup(self) -> bool:
169
+ """Whether the message was sent in a supergroup."""
170
+ return self.chat_type == "supergroup"
171
+
172
+ @property
173
+ def is_channel(self) -> bool:
174
+ """Whether the message was sent in a channel."""
175
+ return self.chat_type == "channel"
176
+
177
+ @property
178
+ def avatar(self) -> str | None:
179
+ """
180
+ File ID of the user's most recent profile photo, or `None` if not set.
181
+ Makes an API call each time — cache the result if called frequently.
182
+ """
183
+ photos = self.bot.get_user_profile_photos(self.id, limit=1)
184
+ if photos.total_count == 0:
185
+ return None
186
+ return photos.photos[0].file_id
187
+
188
+ @property
189
+ def profile_photos_count(self) -> int:
190
+ """
191
+ Total number of profile photos the user has set.
192
+ Makes an API call each time.
193
+ """
194
+ return self.bot.get_user_profile_photos(self.id).total_count
195
+
196
+ # ── Dunder ────────────────────────────────────────────────────
197
+
198
+ def __repr__(self) -> str:
199
+ return f"User(id={self.id}, username={self.username!r})"
@@ -3,4 +3,4 @@
3
3
  # PyPI history: https://pypi.org/project/telekit/#history
4
4
  # ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
5
5
 
6
- __version__ = "2.2.0a1"
6
+ __version__ = "2.2.0a2"
@@ -63,9 +63,7 @@ class EntryHandler(telekit.Handler):
63
63
  # Priority:
64
64
  # 1. Previous response (internal database)
65
65
  # 2. Telegram username (fallback)
66
- name: str | None = self._user_data.get_name(
67
- default=self.user.username
68
- )
66
+ name: str | None = self._user_data.get_name() or self.user.username
69
67
 
70
68
  if name:
71
69
  self.chain.set_entry_suggestions([name])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: telekit
3
- Version: 2.2.0a1
3
+ Version: 2.2.0a2
4
4
  Summary: Declarative, developer-friendly library for building Telegram bots
5
5
  Home-page: https://github.com/Romashkaa/telekit
6
6
  Author: romashka
@@ -378,15 +378,29 @@ It tries to make Telegram bot development easier.
378
378
 
379
379
  ---
380
380
 
381
- # Changes in version 2.2.0a1
381
+ # Changes in version 2.2.0a2
382
382
 
383
383
  ## New Button Types
384
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 brief notification at the top of the chat screen. |
389
-
390
- ## User Refactor
391
-
392
- `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.
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
+
390
+ ## User Improvements
391
+
392
+ | **Name** | **Description** |
393
+ | ---------------------- | --------------------------------------------------------- |
394
+ | `bio` | Bio of the user or description of the chat. |
395
+ | `birthdate` | Birthdate of the user, if set and visible. |
396
+ | `description` | Description of the group or channel. |
397
+ | `mention` | `tg://user?id=` deep link, works even without a username. |
398
+ | `is_private` | Whether the message was sent in a private chat. |
399
+ | `is_group` | Whether the message was sent in a group. |
400
+ | `is_supergroup` | Whether the message was sent in a supergroup. |
401
+ | `is_channel` | Whether the message was sent in a channel. |
402
+ | `avatar` | File ID of the user's most recent profile photo. |
403
+ | `profile_photos_count` | Total number of profile photos the user has set. |
404
+
405
+ - 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.
406
+ - Added `__repr__`.
@@ -1,116 +0,0 @@
1
- #
2
- # Copyright (C) 2026 Romashka
3
- #
4
- # 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
9
- # (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
14
- # the GNU General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU General Public License
17
- # along with Telekit. If not, see <https://www.gnu.org/licenses/>.
18
- #
19
- from functools import cached_property
20
- from typing import Literal
21
-
22
- import telebot
23
- import telebot.types
24
-
25
- from ._logger import logger
26
-
27
- __all__ = ["User"]
28
-
29
-
30
- class User:
31
-
32
- bot: telebot.TeleBot
33
-
34
- @classmethod
35
- def _init(cls, bot: telebot.TeleBot) -> None:
36
- cls.bot = bot
37
-
38
- def __init__(self, message: telebot.types.Message) -> None:
39
- self._message = message
40
- self._chat_id = message.chat.id
41
- self.logger = logger.users(self._chat_id)
42
-
43
- # ── sender ────────────────────────────────────────────────────
44
-
45
- @cached_property
46
- def _sender(self) -> telebot.types.User | telebot.types.Chat:
47
- return self._message.from_user or self._message.chat
48
-
49
- # ── logging ───────────────────────────────────────────────────
50
-
51
- def enable_logging(self, *user_ids: int | str) -> None:
52
- """Enable logging for this user or for additional user IDs."""
53
- logger.enable_user_logging(*(user_ids or (self._chat_id,)))
54
-
55
- # ── identity ──────────────────────────────────────────────────
56
-
57
- @cached_property
58
- def id(self) -> int:
59
- return self._sender.id
60
-
61
- @cached_property
62
- def is_bot(self) -> bool:
63
- if isinstance(self._sender, telebot.types.User):
64
- return self._sender.is_bot
65
- return False
66
-
67
- # ── name ──────────────────────────────────────────────────────
68
-
69
- @cached_property
70
- def first_name(self) -> str | None:
71
- if isinstance(self._sender, telebot.types.User):
72
- return self._sender.first_name
73
- return self._sender.first_name or self._sender.title
74
-
75
- @cached_property
76
- def last_name(self) -> str | None:
77
- return self._sender.last_name
78
-
79
- @cached_property
80
- def full_name(self) -> str | None:
81
- if isinstance(self._sender, telebot.types.User):
82
- return self._sender.full_name
83
- return " ".join(filter(None, [self.first_name, self.last_name])) or None
84
-
85
- @cached_property
86
- def username(self) -> str | None:
87
- return self._sender.username
88
-
89
- # ── locale ────────────────────────────────────────────────────
90
-
91
- @cached_property
92
- def language_code(self) -> str | None:
93
- if isinstance(self._sender, telebot.types.User):
94
- return self._sender.language_code
95
- return None
96
-
97
- # ── premium & extras ──────────────────────────────────────────
98
-
99
- @cached_property
100
- def is_premium(self) -> bool:
101
- if isinstance(self._sender, telebot.types.User):
102
- return bool(self._sender.is_premium)
103
- return False
104
-
105
- @cached_property
106
- def added_to_attachment_menu(self) -> bool:
107
- if isinstance(self._sender, telebot.types.User):
108
- return bool(self._sender.added_to_attachment_menu)
109
- return False
110
-
111
- # ── chat-only ─────────────────────────────────────────────────
112
-
113
- @cached_property
114
- def chat_type(self) -> Literal["private", "group", "supergroup", "channel"]:
115
- """Type of the chat: private, group, supergroup, or channel."""
116
- return self._message.chat.type # pyright: ignore[reportReturnType]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes