telegrinder 0.1.dev20__py3-none-any.whl → 0.1.dev159__py3-none-any.whl

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.

Potentially problematic release.


This version of telegrinder might be problematic. Click here for more details.

Files changed (132) hide show
  1. telegrinder/__init__.py +129 -22
  2. telegrinder/api/__init__.py +11 -2
  3. telegrinder/api/abc.py +25 -9
  4. telegrinder/api/api.py +47 -28
  5. telegrinder/api/error.py +14 -4
  6. telegrinder/api/response.py +11 -7
  7. telegrinder/bot/__init__.py +68 -7
  8. telegrinder/bot/bot.py +30 -24
  9. telegrinder/bot/cute_types/__init__.py +11 -1
  10. telegrinder/bot/cute_types/base.py +138 -0
  11. telegrinder/bot/cute_types/callback_query.py +458 -15
  12. telegrinder/bot/cute_types/inline_query.py +30 -24
  13. telegrinder/bot/cute_types/message.py +2982 -78
  14. telegrinder/bot/cute_types/update.py +30 -0
  15. telegrinder/bot/cute_types/utils.py +794 -0
  16. telegrinder/bot/dispatch/__init__.py +56 -3
  17. telegrinder/bot/dispatch/abc.py +9 -7
  18. telegrinder/bot/dispatch/composition.py +74 -0
  19. telegrinder/bot/dispatch/context.py +71 -0
  20. telegrinder/bot/dispatch/dispatch.py +86 -49
  21. telegrinder/bot/dispatch/handler/__init__.py +3 -0
  22. telegrinder/bot/dispatch/handler/abc.py +11 -5
  23. telegrinder/bot/dispatch/handler/func.py +41 -32
  24. telegrinder/bot/dispatch/handler/message_reply.py +46 -0
  25. telegrinder/bot/dispatch/middleware/__init__.py +2 -0
  26. telegrinder/bot/dispatch/middleware/abc.py +10 -4
  27. telegrinder/bot/dispatch/process.py +53 -49
  28. telegrinder/bot/dispatch/return_manager/__init__.py +19 -0
  29. telegrinder/bot/dispatch/return_manager/abc.py +95 -0
  30. telegrinder/bot/dispatch/return_manager/callback_query.py +19 -0
  31. telegrinder/bot/dispatch/return_manager/inline_query.py +14 -0
  32. telegrinder/bot/dispatch/return_manager/message.py +25 -0
  33. telegrinder/bot/dispatch/view/__init__.py +14 -2
  34. telegrinder/bot/dispatch/view/abc.py +128 -2
  35. telegrinder/bot/dispatch/view/box.py +38 -0
  36. telegrinder/bot/dispatch/view/callback_query.py +13 -39
  37. telegrinder/bot/dispatch/view/inline_query.py +11 -39
  38. telegrinder/bot/dispatch/view/message.py +11 -47
  39. telegrinder/bot/dispatch/waiter_machine/__init__.py +9 -0
  40. telegrinder/bot/dispatch/waiter_machine/machine.py +116 -0
  41. telegrinder/bot/dispatch/waiter_machine/middleware.py +76 -0
  42. telegrinder/bot/dispatch/waiter_machine/short_state.py +37 -0
  43. telegrinder/bot/polling/__init__.py +2 -0
  44. telegrinder/bot/polling/abc.py +11 -4
  45. telegrinder/bot/polling/polling.py +89 -40
  46. telegrinder/bot/rules/__init__.py +91 -5
  47. telegrinder/bot/rules/abc.py +81 -63
  48. telegrinder/bot/rules/adapter/__init__.py +11 -0
  49. telegrinder/bot/rules/adapter/abc.py +21 -0
  50. telegrinder/bot/rules/adapter/errors.py +5 -0
  51. telegrinder/bot/rules/adapter/event.py +49 -0
  52. telegrinder/bot/rules/adapter/raw_update.py +24 -0
  53. telegrinder/bot/rules/callback_data.py +159 -38
  54. telegrinder/bot/rules/command.py +116 -0
  55. telegrinder/bot/rules/enum_text.py +28 -0
  56. telegrinder/bot/rules/func.py +17 -17
  57. telegrinder/bot/rules/fuzzy.py +13 -10
  58. telegrinder/bot/rules/inline.py +61 -0
  59. telegrinder/bot/rules/integer.py +12 -7
  60. telegrinder/bot/rules/is_from.py +148 -7
  61. telegrinder/bot/rules/markup.py +21 -18
  62. telegrinder/bot/rules/mention.py +17 -0
  63. telegrinder/bot/rules/message_entities.py +33 -0
  64. telegrinder/bot/rules/regex.py +27 -19
  65. telegrinder/bot/rules/rule_enum.py +74 -0
  66. telegrinder/bot/rules/start.py +25 -13
  67. telegrinder/bot/rules/text.py +23 -14
  68. telegrinder/bot/scenario/__init__.py +2 -0
  69. telegrinder/bot/scenario/abc.py +12 -5
  70. telegrinder/bot/scenario/checkbox.py +48 -30
  71. telegrinder/bot/scenario/choice.py +16 -10
  72. telegrinder/client/__init__.py +3 -1
  73. telegrinder/client/abc.py +26 -16
  74. telegrinder/client/aiohttp.py +54 -32
  75. telegrinder/model.py +119 -40
  76. telegrinder/modules.py +189 -21
  77. telegrinder/msgspec_json.py +14 -0
  78. telegrinder/msgspec_utils.py +227 -0
  79. telegrinder/node/__init__.py +31 -0
  80. telegrinder/node/attachment.py +71 -0
  81. telegrinder/node/base.py +93 -0
  82. telegrinder/node/composer.py +71 -0
  83. telegrinder/node/container.py +22 -0
  84. telegrinder/node/message.py +18 -0
  85. telegrinder/node/rule.py +56 -0
  86. telegrinder/node/source.py +31 -0
  87. telegrinder/node/text.py +13 -0
  88. telegrinder/node/tools/__init__.py +3 -0
  89. telegrinder/node/tools/generator.py +40 -0
  90. telegrinder/node/update.py +12 -0
  91. telegrinder/rules.py +1 -1
  92. telegrinder/tools/__init__.py +138 -4
  93. telegrinder/tools/buttons.py +89 -51
  94. telegrinder/tools/error_handler/__init__.py +8 -0
  95. telegrinder/tools/error_handler/abc.py +30 -0
  96. telegrinder/tools/error_handler/error_handler.py +156 -0
  97. telegrinder/tools/formatting/__init__.py +81 -3
  98. telegrinder/tools/formatting/html.py +283 -37
  99. telegrinder/tools/formatting/links.py +32 -0
  100. telegrinder/tools/formatting/spec_html_formats.py +121 -0
  101. telegrinder/tools/global_context/__init__.py +12 -0
  102. telegrinder/tools/global_context/abc.py +66 -0
  103. telegrinder/tools/global_context/global_context.py +451 -0
  104. telegrinder/tools/global_context/telegrinder_ctx.py +25 -0
  105. telegrinder/tools/i18n/__init__.py +12 -0
  106. telegrinder/tools/i18n/base.py +31 -0
  107. telegrinder/tools/i18n/middleware/__init__.py +3 -0
  108. telegrinder/tools/i18n/middleware/base.py +26 -0
  109. telegrinder/tools/i18n/simple.py +48 -0
  110. telegrinder/tools/kb_set/__init__.py +2 -0
  111. telegrinder/tools/kb_set/base.py +3 -0
  112. telegrinder/tools/kb_set/yaml.py +28 -17
  113. telegrinder/tools/keyboard.py +84 -62
  114. telegrinder/tools/loop_wrapper/__init__.py +4 -0
  115. telegrinder/tools/loop_wrapper/abc.py +18 -0
  116. telegrinder/tools/loop_wrapper/loop_wrapper.py +132 -0
  117. telegrinder/tools/magic.py +48 -23
  118. telegrinder/tools/parse_mode.py +1 -2
  119. telegrinder/types/__init__.py +1 -0
  120. telegrinder/types/enums.py +653 -0
  121. telegrinder/types/methods.py +4107 -1279
  122. telegrinder/types/objects.py +4771 -1745
  123. {telegrinder-0.1.dev20.dist-info → telegrinder-0.1.dev159.dist-info}/LICENSE +2 -1
  124. telegrinder-0.1.dev159.dist-info/METADATA +109 -0
  125. telegrinder-0.1.dev159.dist-info/RECORD +126 -0
  126. {telegrinder-0.1.dev20.dist-info → telegrinder-0.1.dev159.dist-info}/WHEEL +1 -1
  127. telegrinder/bot/dispatch/waiter.py +0 -38
  128. telegrinder/result.py +0 -38
  129. telegrinder/tools/formatting/abc.py +0 -52
  130. telegrinder/tools/formatting/markdown.py +0 -57
  131. telegrinder-0.1.dev20.dist-info/METADATA +0 -22
  132. telegrinder-0.1.dev20.dist-info/RECORD +0 -71
@@ -0,0 +1,138 @@
1
+ import dataclasses
2
+ import inspect
3
+ import typing
4
+ from functools import wraps
5
+
6
+ from fntypes.result import Result
7
+
8
+ from telegrinder.api import ABCAPI, API
9
+ from telegrinder.model import Model, get_params
10
+
11
+ F = typing.TypeVar("F", bound=typing.Callable[..., typing.Any])
12
+ CuteT = typing.TypeVar("CuteT", bound="BaseCute")
13
+ UpdateT = typing.TypeVar("UpdateT", bound=Model)
14
+
15
+ Executor: typing.TypeAlias = typing.Callable[
16
+ [CuteT, str, dict[str, typing.Any]],
17
+ typing.Awaitable[Result[typing.Any, typing.Any]],
18
+ ]
19
+
20
+ if typing.TYPE_CHECKING:
21
+
22
+ class BaseCute(Model, typing.Generic[UpdateT]):
23
+ api: ABCAPI
24
+
25
+ @classmethod
26
+ def from_update(cls, update: UpdateT, bound_api: ABCAPI) -> typing.Self:
27
+ ...
28
+
29
+ @property
30
+ def ctx_api(self) -> API:
31
+ ...
32
+
33
+ else:
34
+
35
+ class BaseCute(typing.Generic[UpdateT]):
36
+ api: ABCAPI
37
+
38
+ @classmethod
39
+ def from_update(cls, update, bound_api):
40
+ return cls(**update.to_dict(), api=bound_api)
41
+
42
+ @property
43
+ def ctx_api(self):
44
+ assert isinstance(self.api, API)
45
+ return self.api
46
+
47
+ def to_dict(self, *, exclude_fields=None):
48
+ exclude_fields = exclude_fields or set()
49
+ return super().to_dict(exclude_fields={"api"} | exclude_fields)
50
+
51
+
52
+ def compose_method_params(
53
+ params: dict[str, typing.Any],
54
+ update: CuteT,
55
+ *,
56
+ default_params: set[str | tuple[str, str]] | None = None,
57
+ validators: dict[str, typing.Callable[[CuteT], bool]] | None = None,
58
+ ) -> dict[str, typing.Any]:
59
+ """Compose method `params` from `update` by `default_params` and `validators`.
60
+
61
+ :param params: Method params.
62
+ :param update: Update object.
63
+ :param default_params: Default params. \
64
+ type (`str`) - Attribute name to be taken from `update` if param undefined. \
65
+ type (`tuple[str, str]`) - tuple[0] Parameter name to be set in `params`, \
66
+ tuple[1] attribute name to be taken from `update`.
67
+ :param validators: Validators mapping (`str, Callable`), key - `Parameter name` \
68
+ for which the validator will be applied, value - `Validator`, if returned `True` \
69
+ parameter will be set, otherwise will not be set.
70
+ :return: Composed params.
71
+ """
72
+
73
+ default_params = default_params or set()
74
+ validators = validators or {}
75
+
76
+ for param in default_params:
77
+ param_name = param if isinstance(param, str) else param[0]
78
+ if param_name not in params:
79
+ if param_name in validators and not validators[param_name](update):
80
+ continue
81
+ params[param_name] = getattr(update, param if isinstance(param, str) else param[1])
82
+
83
+ return params
84
+
85
+
86
+ # NOTE: implement parser on ast for methods decorated this decorator
87
+ # to support updates to the schema Bot API.
88
+ def shortcut(
89
+ method_name: str,
90
+ *,
91
+ executor: Executor[CuteT] | None = None,
92
+ custom_params: set[str] | None = None,
93
+ ):
94
+ def wrapper(func: F) -> F:
95
+ @wraps(func)
96
+ async def inner(self: CuteT, *args: typing.Any, **kwargs: typing.Any) -> typing.Any:
97
+ if executor is None:
98
+ return await func(self, *args, **kwargs)
99
+ signature_params = {
100
+ k: p
101
+ for k, p in inspect.signature(func).parameters.items()
102
+ if k != "self"
103
+ }
104
+ params: dict[str, typing.Any] = {}
105
+ index = 0
106
+
107
+ for k, p in signature_params.items():
108
+ if p.kind in (p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY) and len(args) > index:
109
+ params[k] = args[index]
110
+ index += 1
111
+ continue
112
+ if p.kind in (p.VAR_KEYWORD, p.VAR_POSITIONAL):
113
+ params[k] = kwargs.copy() if p.kind is p.VAR_KEYWORD else args[index:]
114
+ continue
115
+ params[k] = kwargs.pop(k, p.default) if p.default is not p.empty else kwargs.pop(k)
116
+
117
+ return await executor(self, method_name, get_params(params))
118
+
119
+ func.__repr__ = lambda _: f"<Shortcut {method_name!r}@{func!r}>"
120
+ inner.__shortcut__ = Shortcut( # type: ignore
121
+ method_name=method_name,
122
+ executor=executor,
123
+ custom_params=custom_params or set(),
124
+ )
125
+ return inner # type: ignore
126
+
127
+ return wrapper
128
+
129
+
130
+ @dataclasses.dataclass
131
+ class Shortcut:
132
+ method_name: str
133
+ _: dataclasses.KW_ONLY
134
+ executor: Executor | None = dataclasses.field(default=None)
135
+ custom_params: set[str] = dataclasses.field(default_factory=lambda: set())
136
+
137
+
138
+ __all__ = ("BaseCute", "Shortcut", "compose_method_params", "shortcut")
@@ -1,28 +1,471 @@
1
- from telegrinder.types import CallbackQuery, User
2
- from telegrinder.model import get_params
3
- from telegrinder.api import API, APIError
4
- from telegrinder.result import Result
5
1
  import typing
2
+ from contextlib import suppress
3
+
4
+ import msgspec
5
+ from fntypes.co import Result, Some, Variative
6
+
7
+ from telegrinder.api import ABCAPI, APIError
8
+ from telegrinder.model import get_params
9
+ from telegrinder.msgspec_utils import Nothing, Option, decoder
10
+ from telegrinder.types import (
11
+ CallbackQuery,
12
+ InlineKeyboardMarkup,
13
+ InputFile,
14
+ InputMedia,
15
+ LinkPreviewOptions,
16
+ MessageEntity,
17
+ MessageId,
18
+ ReplyParameters,
19
+ User,
20
+ )
6
21
 
22
+ from .base import BaseCute, compose_method_params, shortcut
23
+ from .message import MediaType, MessageCute, ReplyMarkup, execute_method_edit
7
24
 
8
- class CallbackQueryCute(CallbackQuery):
9
- api: API
25
+
26
+ class CallbackQueryCute(
27
+ BaseCute[CallbackQuery], CallbackQuery, kw_only=True, dict=True
28
+ ):
29
+ api: ABCAPI
10
30
 
11
31
  @property
12
32
  def from_user(self) -> User:
13
33
  return self.from_
34
+
35
+ @property
36
+ def chat_id(self) -> Option[int]:
37
+ """Optional. Message from chat ID. This will be present if the message is sent
38
+ by the bot with the callback button that originated the query."""
14
39
 
40
+ return self.message.map(lambda m: m.v.chat.id)
41
+
15
42
  @property
16
- def ctx_api(self) -> API:
17
- return self.api
43
+ def is_topic_message(self) -> Option[bool]:
44
+ """Optional. True, if the message is a topic message with a name,
45
+ color and icon. This will be present if the message is sent
46
+ by the bot with the callback button that originated the query."""
47
+
48
+ return self.message.map(
49
+ lambda m: m.only().map(
50
+ lambda m: m.is_topic_message.unwrap_or(False)
51
+ ).unwrap_or(False)
52
+ )
53
+
54
+ @property
55
+ def message_thread_id(self) -> Option[int]:
56
+ """Optional. Unique identifier of the target message thread (for forum supergroups only).
57
+ This will be present if the message is sent
58
+ by the bot with the callback button that originated the query."""
59
+
60
+ return self.message.map(
61
+ lambda m: m.only().map(
62
+ lambda m: m.message_thread_id,
63
+ ).unwrap_or(Nothing)
64
+ ).unwrap_or(Nothing)
65
+
66
+ @property
67
+ def message_id(self) -> Option[int]:
68
+ """Optional. Unique message identifier inside this chat. This will be present
69
+ if the message is sent by the bot with the callback button that originated the query.
70
+ """
71
+
72
+ return self.message.map(lambda m: m.v.message_id)
73
+
74
+ def decode_callback_data(self, *, strict: bool = True) -> Option[dict[str, typing.Any]]:
75
+ if "cached_callback_data" in self.__dict__:
76
+ return self.__dict__["cached_callback_data"]
77
+ data = Nothing
78
+ with suppress(msgspec.ValidationError):
79
+ data = Some(decoder.decode(self.data.unwrap(), strict=strict))
80
+ self.__dict__["cached_callback_data"] = data
81
+ return data
18
82
 
83
+ @shortcut("answer_callback_query")
19
84
  async def answer(
20
85
  self,
21
- text: typing.Optional[str] = None,
22
- show_alert: typing.Optional[bool] = None,
23
- url: typing.Optional[str] = None,
24
- cache_time: typing.Optional[int] = None,
25
- **other
86
+ text: str | Option[str] = Nothing,
87
+ callback_query_id: str | Option[str] = Nothing,
88
+ show_alert: bool | Option[bool] = Nothing,
89
+ url: str | Option[str] = Nothing,
90
+ cache_time: int | Option[int] = Nothing,
91
+ **other: typing.Any,
92
+ ) -> Result[bool, APIError]:
93
+ """Shortcut `API.answer_callback_query()`, see the [documentation](https://core.telegram.org/bots/api#answercallbackquery)
94
+
95
+ Use this method to send answers to callback queries sent from inline keyboards.
96
+ The answer will be displayed to the user as a notification at the top of the
97
+ chat screen or as an alert. On success, True is returned.
98
+
99
+ :param callback_query_id: Unique identifier for the query to be answered.
100
+
101
+ :param text: Text of the notification. If not specified, nothing will be shown to the \
102
+ user, 0-200 characters.
103
+
104
+ :param show_alert: If True, an alert will be shown by the client instead of a notification at \
105
+ the top of the chat screen. Defaults to false.
106
+
107
+ :param url: URL that will be opened by the user's client. If you have created a Game and \
108
+ accepted the conditions via @BotFather, specify the URL that opens your \
109
+ game - note that this will only work if the query comes from a callback_game \
110
+ button. Otherwise, you may use links like t.me/your_bot?start=XXXX that \
111
+ open your bot with a parameter.
112
+
113
+ :param cache_time: The maximum amount of time in seconds that the result of the callback query \
114
+ may be cached client-side. Telegram apps will support caching starting \
115
+ in version 3.14. Defaults to 0."""
116
+
117
+ params = compose_method_params(
118
+ get_params(locals()), self, default_params={("callback_query_id", "id")}
119
+ )
120
+ return await self.ctx_api.answer_callback_query(**params)
121
+
122
+ @shortcut(
123
+ "copy_message",
124
+ custom_params={"reply_parameters", "message_thread_id"},
125
+ )
126
+ async def copy(
127
+ self,
128
+ chat_id: int | str | Option[int | str] = Nothing,
129
+ from_chat_id: int | str | Option[int | str] = Nothing,
130
+ message_id: int | Option[int] = Nothing,
131
+ message_thread_id: Option[int] | int = Nothing,
132
+ caption: Option[str] | str = Nothing,
133
+ parse_mode: Option[str] | str = Nothing,
134
+ caption_entities: Option[list[MessageEntity]] | list[MessageEntity] = Nothing,
135
+ disable_notification: Option[bool] | bool = Nothing,
136
+ protect_content: Option[bool] | bool = Nothing,
137
+ reply_parameters: Option[ReplyParameters | dict[str, typing.Any]]
138
+ | ReplyParameters
139
+ | dict[str, typing.Any] = Nothing,
140
+ reply_markup: Option[ReplyMarkup] | ReplyMarkup = Nothing,
141
+ **other: typing.Any,
142
+ ) -> Result[MessageId, APIError]:
143
+ """Shortcut `API.copy_message()`, see the [documentation](https://core.telegram.org/bots/api#copymessage)
144
+
145
+ Use this method to copy messages of any kind. Service messages, giveaway
146
+ messages, giveaway winners messages, and invoice messages can't be copied.
147
+ A quiz poll can be copied only if the value of the field correct_option_id
148
+ is known to the bot. The method is analogous to the method forwardMessage,
149
+ but the copied message doesn't have a link to the original message. Returns
150
+ the MessageId of the sent message on success.
151
+
152
+ :param chat_id: Unique identifier for the target chat or username of the target channel \
153
+ (in the format @channelusername).
154
+
155
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
156
+ forum supergroups only.
157
+
158
+ :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel \
159
+ username in the format @channelusername).
160
+
161
+ :param message_id: Message identifier in the chat specified in from_chat_id.
162
+
163
+ :param caption: New caption for media, 0-1024 characters after entities parsing. If not \
164
+ specified, the original caption is kept.
165
+
166
+ :param parse_mode: Mode for parsing entities in the new caption. See formatting options for \
167
+ more details.
168
+
169
+ :param caption_entities: A JSON-serialized list of special entities that appear in the new caption, \
170
+ which can be specified instead of parse_mode.
171
+
172
+ :param disable_notification: Sends the message silently. Users will receive a notification with no sound. \
173
+
174
+ :param protect_content: Protects the contents of the sent message from forwarding and saving.
175
+
176
+ :param reply_parameters: Description of the message to reply to.
177
+
178
+ :param reply_markup: Additional interface options. A JSON-serialized object for an inline \
179
+ keyboard, custom reply keyboard, instructions to remove reply keyboard \
180
+ or to force a reply from the user.
181
+ """
182
+
183
+ return await MessageCute.copy(self, **get_params(locals())) # type: ignore
184
+
185
+ @shortcut("delete_message", custom_params={"message_thread_id"})
186
+ async def delete(
187
+ self,
188
+ chat_id: int | Option[int] = Nothing,
189
+ message_id: int | Option[int] = Nothing,
190
+ message_thread_id: int | Option[int] = Nothing,
191
+ **other: typing.Any,
26
192
  ) -> Result[bool, APIError]:
27
- params = get_params(locals())
28
- return await self.ctx_api.answer_callback_query(self.id, **params)
193
+ """Shortcut `API.delete_message()`, see the [documentation](https://core.telegram.org/bots/api#deletemessage)
194
+
195
+ Use this method to delete a message, including service messages, with the
196
+ following limitations: - A message can only be deleted if it was sent less
197
+ than 48 hours ago. - Service messages about a supergroup, channel, or forum
198
+ topic creation can't be deleted. - A dice message in a private chat can only
199
+ be deleted if it was sent more than 24 hours ago. - Bots can delete outgoing
200
+ messages in private chats, groups, and supergroups. - Bots can delete incoming
201
+ messages in private chats. - Bots granted can_post_messages permissions
202
+ can delete outgoing messages in channels. - If the bot is an administrator
203
+ of a group, it can delete any message there. - If the bot has can_delete_messages
204
+ permission in a supergroup or a channel, it can delete any message there.
205
+ Returns True on success.
206
+
207
+ :param chat_id: Unique identifier for the target chat or username of the target channel \
208
+ (in the format @channelusername).
209
+
210
+ :param message_id: Identifier of the message to delete.
211
+
212
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
213
+ forum supergroups only."""
214
+
215
+ return await MessageCute.delete(self, **get_params(locals())) # type: ignore
216
+
217
+ @shortcut(
218
+ "edit_message_text",
219
+ executor=execute_method_edit,
220
+ custom_params={"message_thread_id", "link_preview_options"}
221
+ )
222
+ async def edit_text(
223
+ self,
224
+ text: str | Option[str],
225
+ inline_message_id: int | Option[int] = Nothing,
226
+ chat_id: Option[int | str] | int | str = Nothing,
227
+ message_id: Option[int] | int = Nothing,
228
+ message_thread_id: int | Option[int] = Nothing,
229
+ parse_mode: str | Option[str] = Nothing,
230
+ entities: list[MessageEntity] | Option[list[MessageEntity]] = Nothing,
231
+ link_preview_options: Option[LinkPreviewOptions | dict[str, typing.Any]]
232
+ | LinkPreviewOptions
233
+ | dict[str, typing.Any] = Nothing,
234
+ reply_markup: InlineKeyboardMarkup | Option[InlineKeyboardMarkup] = Nothing,
235
+ **other: typing.Any,
236
+ ) -> Result[Variative[MessageCute, bool], APIError]:
237
+ """Shortcut `API.edit_message_text()`, see the [documentation](https://core.telegram.org/bots/api#editmessagetext)
238
+
239
+ Use this method to edit text and game messages. On success, if the edited
240
+ message is not an inline message, the edited Message is returned, otherwise
241
+ True is returned.
242
+
243
+ :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the \
244
+ inline message.
245
+
246
+ :param chat_id: Required if inline_message_id is not specified. Unique identifier for \
247
+ the target chat or username of the target channel (in the format @channelusername). \
248
+
249
+ :param message_id: Required if inline_message_id is not specified. Identifier of the message \
250
+ to edit.
251
+
252
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
253
+ forum supergroups only.
254
+
255
+ :param text: New text of the message, 1-4096 characters after entities parsing.
256
+
257
+ :param parse_mode: Mode for parsing entities in the message text. See formatting options for \
258
+ more details.
259
+
260
+ :param entities: A JSON-serialized list of special entities that appear in message text, \
261
+ which can be specified instead of parse_mode.
262
+
263
+ :param link_preview_options: Link preview generation options for the message.
264
+
265
+ :param reply_markup: A JSON-serialized object for an inline keyboard."""
266
+
267
+ ...
268
+
269
+ @shortcut(
270
+ "edit_message_live_location",
271
+ executor=execute_method_edit,
272
+ custom_params={"message_thread_id"},
273
+ )
274
+ async def edit_live_location(
275
+ self,
276
+ latitude: float,
277
+ longitude: float,
278
+ inline_message_id: Option[str] | str = Nothing,
279
+ message_thread_id: int | Option[int] = Nothing,
280
+ chat_id: Option[int | str] | int | str = Nothing,
281
+ message_id: Option[int] | int = Nothing,
282
+ horizontal_accuracy: Option[float] | float = Nothing,
283
+ heading: Option[int] | int = Nothing,
284
+ proximity_alert_radius: Option[int] | int = Nothing,
285
+ reply_markup: Option[InlineKeyboardMarkup] | InlineKeyboardMarkup = Nothing,
286
+ **other: typing.Any,
287
+ ) -> Result[Variative[MessageCute, bool], APIError]:
288
+ """Shortcut `API.edit_message_live_location()`, see the [documentation](https://core.telegram.org/bots/api#editmessagelivelocation)
289
+
290
+ Use this method to edit live location messages. A location can be edited
291
+ until its live_period expires or editing is explicitly disabled by a call
292
+ to stopMessageLiveLocation. On success, if the edited message is not an
293
+ inline message, the edited Message is returned, otherwise True is returned.
294
+
295
+ :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the \
296
+ inline message.
297
+
298
+ :param chat_id: Required if inline_message_id is not specified. Unique identifier for \
299
+ the target chat or username of the target channel (in the format @channelusername). \
300
+
301
+ :param message_id: Required if inline_message_id is not specified. Identifier of the message \
302
+ to edit.
303
+
304
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
305
+ forum supergroups only.
306
+
307
+ :param latitude: Latitude of new location.
308
+
309
+ :param longitude: Longitude of new location.
310
+
311
+ :param horizontal_accuracy: The radius of uncertainty for the location, measured in meters; 0-1500. \
312
+
313
+ :param heading: Direction in which the user is moving, in degrees. Must be between 1 and 360 \
314
+ if specified.
315
+
316
+ :param proximity_alert_radius: The maximum distance for proximity alerts about approaching another chat \
317
+ member, in meters. Must be between 1 and 100000 if specified.
318
+
319
+ :param reply_markup: A JSON-serialized object for a new inline keyboard."""
320
+
321
+ ...
322
+
323
+ @shortcut(
324
+ "edit_message_caption",
325
+ executor=execute_method_edit,
326
+ custom_params={"message_thread_id"},
327
+ )
328
+ async def edit_caption(
329
+ self,
330
+ caption: Option[str] | str,
331
+ chat_id: Option[int | str] | int | str = Nothing,
332
+ message_id: Option[int] | int = Nothing,
333
+ message_thread_id: int | Option[int] = Nothing,
334
+ inline_message_id: Option[str] | str = Nothing,
335
+ parse_mode: Option[str] | str = Nothing,
336
+ caption_entities: Option[list[MessageEntity]] | list[MessageEntity] = Nothing,
337
+ reply_markup: Option[InlineKeyboardMarkup] | InlineKeyboardMarkup = Nothing,
338
+ **other: typing.Any,
339
+ ) -> Result[Variative[MessageCute, bool], APIError]:
340
+ """Shortcut `API.edit_message_caption()`, see the [documentation](https://core.telegram.org/bots/api#editmessagecaption)
341
+
342
+ Use this method to edit captions of messages. On success, if the edited message
343
+ is not an inline message, the edited Message is returned, otherwise True
344
+ is returned.
345
+
346
+ :param chat_id: Required if inline_message_id is not specified. Unique identifier for \
347
+ the target chat or username of the target channel (in the format @channelusername). \
348
+
349
+ :param message_id: Required if inline_message_id is not specified. Identifier of the message \
350
+ to edit.
351
+
352
+ :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the \
353
+ inline message.
354
+
355
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
356
+ forum supergroups only.
357
+
358
+ :param caption: New caption of the message, 0-1024 characters after entities parsing. \
359
+
360
+ :param parse_mode: Mode for parsing entities in the message caption. See formatting options \
361
+ for more details.
362
+
363
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, \
364
+ which can be specified instead of parse_mode.
365
+
366
+ :param reply_markup: A JSON-serialized object for an inline keyboard."""
367
+
368
+ ...
369
+
370
+ @shortcut(
371
+ "edit_message_media",
372
+ custom_params={
373
+ "media",
374
+ "type",
375
+ "message_thread_id",
376
+ "caption",
377
+ "parse_mode",
378
+ "caption_entities",
379
+ },
380
+ )
381
+ async def edit_media(
382
+ self,
383
+ media: str | InputFile | InputMedia,
384
+ type: MediaType | Option[MediaType] = Nothing,
385
+ caption: Option[str] | str = Nothing,
386
+ parse_mode: Option[str] | str = Nothing,
387
+ caption_entities: Option[list[MessageEntity]] | list[MessageEntity] = Nothing,
388
+ inline_message_id: Option[str] | str = Nothing,
389
+ chat_id: Option[int | str] | int | str = Nothing,
390
+ message_id: Option[int] | int = Nothing,
391
+ message_thread_id: Option[int] | int = Nothing,
392
+ reply_markup: Option[InlineKeyboardMarkup] | InlineKeyboardMarkup = Nothing,
393
+ **other: typing.Any,
394
+ ) -> Result[Variative[MessageCute, bool], APIError]:
395
+ """Shortcut `API.edit_message_media()`, see the [documentation](https://core.telegram.org/bots/api#editmessagemedia)
396
+
397
+ Use this method to edit animation, audio, document, photo, or video messages.
398
+ If a message is part of a message album, then it can be edited only to an audio
399
+ for audio albums, only to a document for document albums and to a photo or
400
+ a video otherwise. When an inline message is edited, a new file can't be uploaded;
401
+ use a previously uploaded file via its file_id or specify a URL. On success,
402
+ if the edited message is not an inline message, the edited Message is returned,
403
+ otherwise True is returned.
404
+
405
+ :param chat_id: Required if inline_message_id is not specified. Unique identifier for \
406
+ the target chat or username of the target channel (in the format @channelusername). \
407
+
408
+ :param message_id: Required if inline_message_id is not specified. Identifier of the message \
409
+ to edit.
410
+
411
+ :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the \
412
+ inline message.
413
+
414
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
415
+ forum supergroups only.
416
+
417
+ :param media: A JSON-serialized object for a new media content of the message.
418
+
419
+ :param caption: Audio caption, 0-1024 characters after entities parsing.
420
+
421
+ :param parse_mode: Mode for parsing entities in the audio caption. See formatting options \
422
+ for more details.
423
+
424
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, \
425
+ which can be specified instead of parse_mode.
426
+
427
+ :param type: Required if media is not an `str | InputMedia` object. Type of the media, \
428
+ must be one of `photo`, `video`, `animation`, `audio`, `document`.
429
+
430
+ :param reply_markup: A JSON-serialized object for a new inline keyboard."""
431
+
432
+ return await MessageCute.edit_media(self, **get_params(locals())) # type: ignore
433
+
434
+ @shortcut(
435
+ "edit_message_reply_markup",
436
+ executor=execute_method_edit,
437
+ custom_params={"message_thread_id"},
438
+ )
439
+ async def edit_reply_markup(
440
+ self,
441
+ inline_message_id: Option[str] | str = Nothing,
442
+ message_id: Option[int] | int = Nothing,
443
+ message_thread_id: Option[int] | int = Nothing,
444
+ chat_id: Option[int | str] | int | str = Nothing,
445
+ reply_markup: Option[InlineKeyboardMarkup] | InlineKeyboardMarkup = Nothing,
446
+ **other: typing.Any,
447
+ ) -> Result[Variative[MessageCute, bool], APIError]:
448
+ """Shortcut `API.edit_message_reply_markup()`, see the [documentation](https://core.telegram.org/bots/api#editmessagereplymarkup)
449
+
450
+ Use this method to edit only the reply markup of messages. On success, if
451
+ the edited message is not an inline message, the edited Message is returned,
452
+ otherwise True is returned.
453
+
454
+ :param chat_id: Required if inline_message_id is not specified. Unique identifier for \
455
+ the target chat or username of the target channel (in the format @channelusername). \
456
+
457
+ :param message_id: Required if inline_message_id is not specified. Identifier of the message \
458
+ to edit.
459
+
460
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for \
461
+ forum supergroups only.
462
+
463
+ :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the \
464
+ inline message.
465
+
466
+ :param reply_markup: A JSON-serialized object for an inline keyboard."""
467
+
468
+ ...
469
+
470
+
471
+ __all__ = ("CallbackQueryCute",)
@@ -1,35 +1,41 @@
1
- from telegrinder.types import InlineQuery, User
2
- from telegrinder.api import API, APIError
3
- from telegrinder.result import Result
4
1
  import typing
5
2
 
3
+ from fntypes.result import Result
6
4
 
7
- class InlineQueryCute(InlineQuery):
8
- api: API
5
+ from telegrinder.api import ABCAPI, APIError
6
+ from telegrinder.model import get_params
7
+ from telegrinder.msgspec_utils import Nothing, Option
8
+ from telegrinder.types import (
9
+ InlineQuery,
10
+ InlineQueryResult,
11
+ InlineQueryResultsButton,
12
+ User,
13
+ )
14
+
15
+ from .base import BaseCute
16
+
17
+
18
+ class InlineQueryCute(BaseCute[InlineQuery], InlineQuery, kw_only=True):
19
+ api: ABCAPI
9
20
 
10
21
  @property
11
22
  def from_user(self) -> User:
12
23
  return self.from_
13
24
 
14
- @property
15
- def ctx_api(self) -> API:
16
- return self.api
17
-
18
25
  async def answer(
19
26
  self,
20
- results: typing.Optional[list] = None,
21
- cache_time: typing.Optional[int] = None,
22
- is_personal: typing.Optional[bool] = None,
23
- next_offset: typing.Optional[str] = None,
24
- switch_pm_text: typing.Optional[str] = None,
25
- switch_pm_parameter: typing.Optional[str] = None,
27
+ results: InlineQueryResult | list[InlineQueryResult],
28
+ inline_query_id: str | Option[str] = Nothing,
29
+ cache_time: int | Option[int] = Nothing,
30
+ is_personal: bool | Option[bool] = Nothing,
31
+ next_offset: str | Option[str] = Nothing,
32
+ button: Option[InlineQueryResultsButton] | InlineQueryResultsButton = Nothing,
33
+ **other: typing.Any,
26
34
  ) -> Result[bool, APIError]:
27
- return await self.ctx_api.answer_inline_query(
28
- self.id,
29
- results=results,
30
- cache_time=cache_time,
31
- is_personal=is_personal,
32
- next_offset=next_offset,
33
- switch_pm_text=switch_pm_text,
34
- switch_pm_parameter=switch_pm_parameter,
35
- )
35
+ params = get_params(locals())
36
+ params["results"] = [results] if not isinstance(results, list) else results
37
+ params.setdefault("inline_query_id", self.id)
38
+ return await self.ctx_api.answer_inline_query(**params)
39
+
40
+
41
+ __all__ = ("InlineQueryCute",)