telegrinder 1.0.0rc1__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.
- telegrinder/__init__.py +258 -0
- telegrinder/__meta__.py +1 -0
- telegrinder/api/__init__.py +15 -0
- telegrinder/api/api.py +175 -0
- telegrinder/api/error.py +50 -0
- telegrinder/api/response.py +23 -0
- telegrinder/api/token.py +30 -0
- telegrinder/api/validators.py +30 -0
- telegrinder/bot/__init__.py +144 -0
- telegrinder/bot/bot.py +70 -0
- telegrinder/bot/cute_types/__init__.py +41 -0
- telegrinder/bot/cute_types/base.py +228 -0
- telegrinder/bot/cute_types/base.pyi +49 -0
- telegrinder/bot/cute_types/business_connection.py +9 -0
- telegrinder/bot/cute_types/business_messages_deleted.py +9 -0
- telegrinder/bot/cute_types/callback_query.py +248 -0
- telegrinder/bot/cute_types/chat_boost_removed.py +9 -0
- telegrinder/bot/cute_types/chat_boost_updated.py +9 -0
- telegrinder/bot/cute_types/chat_join_request.py +59 -0
- telegrinder/bot/cute_types/chat_member_updated.py +158 -0
- telegrinder/bot/cute_types/chosen_inline_result.py +11 -0
- telegrinder/bot/cute_types/inline_query.py +41 -0
- telegrinder/bot/cute_types/message.py +2809 -0
- telegrinder/bot/cute_types/message_reaction_count_updated.py +9 -0
- telegrinder/bot/cute_types/message_reaction_updated.py +9 -0
- telegrinder/bot/cute_types/paid_media_purchased.py +11 -0
- telegrinder/bot/cute_types/poll.py +9 -0
- telegrinder/bot/cute_types/poll_answer.py +9 -0
- telegrinder/bot/cute_types/pre_checkout_query.py +36 -0
- telegrinder/bot/cute_types/shipping_query.py +11 -0
- telegrinder/bot/cute_types/update.py +209 -0
- telegrinder/bot/cute_types/utils.py +141 -0
- telegrinder/bot/dispatch/__init__.py +99 -0
- telegrinder/bot/dispatch/abc.py +74 -0
- telegrinder/bot/dispatch/action.py +99 -0
- telegrinder/bot/dispatch/context.py +162 -0
- telegrinder/bot/dispatch/dispatch.py +362 -0
- telegrinder/bot/dispatch/handler/__init__.py +23 -0
- telegrinder/bot/dispatch/handler/abc.py +25 -0
- telegrinder/bot/dispatch/handler/audio_reply.py +43 -0
- telegrinder/bot/dispatch/handler/base.py +34 -0
- telegrinder/bot/dispatch/handler/document_reply.py +43 -0
- telegrinder/bot/dispatch/handler/func.py +73 -0
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -0
- telegrinder/bot/dispatch/handler/message_reply.py +35 -0
- telegrinder/bot/dispatch/handler/photo_reply.py +43 -0
- telegrinder/bot/dispatch/handler/sticker_reply.py +36 -0
- telegrinder/bot/dispatch/handler/video_reply.py +43 -0
- telegrinder/bot/dispatch/middleware/__init__.py +13 -0
- telegrinder/bot/dispatch/middleware/abc.py +112 -0
- telegrinder/bot/dispatch/middleware/box.py +32 -0
- telegrinder/bot/dispatch/middleware/filter.py +88 -0
- telegrinder/bot/dispatch/middleware/media_group.py +69 -0
- telegrinder/bot/dispatch/process.py +93 -0
- telegrinder/bot/dispatch/return_manager/__init__.py +21 -0
- telegrinder/bot/dispatch/return_manager/abc.py +107 -0
- telegrinder/bot/dispatch/return_manager/callback_query.py +19 -0
- telegrinder/bot/dispatch/return_manager/inline_query.py +14 -0
- telegrinder/bot/dispatch/return_manager/message.py +34 -0
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +19 -0
- telegrinder/bot/dispatch/return_manager/utils.py +20 -0
- telegrinder/bot/dispatch/router/__init__.py +4 -0
- telegrinder/bot/dispatch/router/abc.py +15 -0
- telegrinder/bot/dispatch/router/base.py +154 -0
- telegrinder/bot/dispatch/view/__init__.py +15 -0
- telegrinder/bot/dispatch/view/abc.py +15 -0
- telegrinder/bot/dispatch/view/base.py +226 -0
- telegrinder/bot/dispatch/view/box.py +207 -0
- telegrinder/bot/dispatch/view/media_group.py +25 -0
- telegrinder/bot/dispatch/waiter_machine/__init__.py +25 -0
- telegrinder/bot/dispatch/waiter_machine/actions.py +16 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +13 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +53 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +61 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +49 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +264 -0
- telegrinder/bot/dispatch/waiter_machine/middleware.py +77 -0
- telegrinder/bot/dispatch/waiter_machine/short_state.py +105 -0
- telegrinder/bot/polling/__init__.py +4 -0
- telegrinder/bot/polling/abc.py +25 -0
- telegrinder/bot/polling/error_handler.py +93 -0
- telegrinder/bot/polling/polling.py +167 -0
- telegrinder/bot/polling/utils.py +12 -0
- telegrinder/bot/rules/__init__.py +166 -0
- telegrinder/bot/rules/abc.py +150 -0
- telegrinder/bot/rules/button.py +20 -0
- telegrinder/bot/rules/callback_data.py +109 -0
- telegrinder/bot/rules/chat_join.py +28 -0
- telegrinder/bot/rules/chat_member_updated.py +145 -0
- telegrinder/bot/rules/command.py +137 -0
- telegrinder/bot/rules/enum_text.py +29 -0
- telegrinder/bot/rules/func.py +21 -0
- telegrinder/bot/rules/fuzzy.py +21 -0
- telegrinder/bot/rules/inline.py +45 -0
- telegrinder/bot/rules/integer.py +19 -0
- telegrinder/bot/rules/is_from.py +213 -0
- telegrinder/bot/rules/logic.py +22 -0
- telegrinder/bot/rules/magic.py +60 -0
- telegrinder/bot/rules/markup.py +51 -0
- telegrinder/bot/rules/media.py +13 -0
- telegrinder/bot/rules/mention.py +15 -0
- telegrinder/bot/rules/message_entities.py +37 -0
- telegrinder/bot/rules/node.py +43 -0
- telegrinder/bot/rules/payload.py +89 -0
- telegrinder/bot/rules/payment_invoice.py +14 -0
- telegrinder/bot/rules/regex.py +34 -0
- telegrinder/bot/rules/rule_enum.py +71 -0
- telegrinder/bot/rules/start.py +73 -0
- telegrinder/bot/rules/state.py +35 -0
- telegrinder/bot/rules/text.py +27 -0
- telegrinder/bot/rules/update.py +14 -0
- telegrinder/bot/scenario/__init__.py +5 -0
- telegrinder/bot/scenario/abc.py +16 -0
- telegrinder/bot/scenario/checkbox.py +183 -0
- telegrinder/bot/scenario/choice.py +44 -0
- telegrinder/client/__init__.py +11 -0
- telegrinder/client/abc.py +136 -0
- telegrinder/client/form_data.py +34 -0
- telegrinder/client/rnet.py +198 -0
- telegrinder/model.py +133 -0
- telegrinder/model.pyi +57 -0
- telegrinder/modules.py +1081 -0
- telegrinder/msgspec_utils/__init__.py +42 -0
- telegrinder/msgspec_utils/abc.py +16 -0
- telegrinder/msgspec_utils/custom_types/__init__.py +6 -0
- telegrinder/msgspec_utils/custom_types/datetime.py +24 -0
- telegrinder/msgspec_utils/custom_types/enum_meta.py +61 -0
- telegrinder/msgspec_utils/custom_types/literal.py +25 -0
- telegrinder/msgspec_utils/custom_types/option.py +17 -0
- telegrinder/msgspec_utils/decoder.py +388 -0
- telegrinder/msgspec_utils/encoder.py +204 -0
- telegrinder/msgspec_utils/json.py +15 -0
- telegrinder/msgspec_utils/tools.py +80 -0
- telegrinder/node/__init__.py +80 -0
- telegrinder/node/compose.py +193 -0
- telegrinder/node/nodes/__init__.py +96 -0
- telegrinder/node/nodes/attachment.py +169 -0
- telegrinder/node/nodes/callback_query.py +25 -0
- telegrinder/node/nodes/channel.py +97 -0
- telegrinder/node/nodes/command.py +33 -0
- telegrinder/node/nodes/error.py +43 -0
- telegrinder/node/nodes/event.py +70 -0
- telegrinder/node/nodes/file.py +39 -0
- telegrinder/node/nodes/global_node.py +66 -0
- telegrinder/node/nodes/i18n.py +110 -0
- telegrinder/node/nodes/me.py +26 -0
- telegrinder/node/nodes/message_entities.py +15 -0
- telegrinder/node/nodes/payload.py +84 -0
- telegrinder/node/nodes/reply_message.py +14 -0
- telegrinder/node/nodes/source.py +172 -0
- telegrinder/node/nodes/state_mutator.py +71 -0
- telegrinder/node/nodes/text.py +62 -0
- telegrinder/node/scope.py +88 -0
- telegrinder/node/utils.py +38 -0
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +1 -0
- telegrinder/tools/__init__.py +183 -0
- telegrinder/tools/aio.py +147 -0
- telegrinder/tools/final.py +21 -0
- telegrinder/tools/formatting/__init__.py +85 -0
- telegrinder/tools/formatting/deep_links/__init__.py +39 -0
- telegrinder/tools/formatting/deep_links/links.py +468 -0
- telegrinder/tools/formatting/deep_links/parsing.py +88 -0
- telegrinder/tools/formatting/deep_links/validators.py +8 -0
- telegrinder/tools/formatting/html.py +241 -0
- telegrinder/tools/fullname.py +82 -0
- telegrinder/tools/global_context/__init__.py +13 -0
- telegrinder/tools/global_context/abc.py +63 -0
- telegrinder/tools/global_context/builtin_context.py +45 -0
- telegrinder/tools/global_context/global_context.py +614 -0
- telegrinder/tools/input_file_directory.py +30 -0
- telegrinder/tools/keyboard/__init__.py +6 -0
- telegrinder/tools/keyboard/abc.py +84 -0
- telegrinder/tools/keyboard/base.py +108 -0
- telegrinder/tools/keyboard/button.py +181 -0
- telegrinder/tools/keyboard/data.py +31 -0
- telegrinder/tools/keyboard/keyboard.py +160 -0
- telegrinder/tools/keyboard/utils.py +95 -0
- telegrinder/tools/lifespan.py +188 -0
- telegrinder/tools/limited_dict.py +35 -0
- telegrinder/tools/loop_wrapper.py +271 -0
- telegrinder/tools/magic/__init__.py +29 -0
- telegrinder/tools/magic/annotations.py +172 -0
- telegrinder/tools/magic/descriptors.py +57 -0
- telegrinder/tools/magic/function.py +254 -0
- telegrinder/tools/magic/inspect.py +16 -0
- telegrinder/tools/magic/shortcut.py +107 -0
- telegrinder/tools/member_descriptor_proxy.py +95 -0
- telegrinder/tools/parse_mode.py +12 -0
- telegrinder/tools/serialization/__init__.py +5 -0
- telegrinder/tools/serialization/abc.py +34 -0
- telegrinder/tools/serialization/json_ser.py +60 -0
- telegrinder/tools/serialization/msgpack_ser.py +197 -0
- telegrinder/tools/serialization/utils.py +18 -0
- telegrinder/tools/singleton/__init__.py +4 -0
- telegrinder/tools/singleton/abc.py +14 -0
- telegrinder/tools/singleton/singleton.py +18 -0
- telegrinder/tools/state_mutator/__init__.py +4 -0
- telegrinder/tools/state_mutator/mutation.py +85 -0
- telegrinder/tools/state_storage/__init__.py +4 -0
- telegrinder/tools/state_storage/abc.py +38 -0
- telegrinder/tools/state_storage/memory.py +27 -0
- telegrinder/tools/strings.py +22 -0
- telegrinder/types/__init__.py +323 -0
- telegrinder/types/enums.py +754 -0
- telegrinder/types/input_file.py +51 -0
- telegrinder/types/methods.py +6143 -0
- telegrinder/types/methods_utils.py +66 -0
- telegrinder/types/objects.py +8184 -0
- telegrinder/types/webapp.py +129 -0
- telegrinder/verification_utils.py +35 -0
- telegrinder-1.0.0rc1.dist-info/METADATA +166 -0
- telegrinder-1.0.0rc1.dist-info/RECORD +215 -0
- telegrinder-1.0.0rc1.dist-info/WHEEL +4 -0
- telegrinder-1.0.0rc1.dist-info/licenses/LICENSE +22 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
2
|
+
from telegrinder.types.objects import MessageReactionCountUpdated
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MessageReactionCountUpdatedCute(BaseCute[MessageReactionCountUpdated], MessageReactionCountUpdated, kw_only=True):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = ("MessageReactionCountUpdatedCute",)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
2
|
+
from telegrinder.types.objects import MessageReactionUpdated
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MessageReactionUpdatedCute(BaseCute[MessageReactionUpdated], MessageReactionUpdated, kw_only=True):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = ("MessageReactionUpdatedCute",)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
2
|
+
from telegrinder.types.objects import PaidMediaPurchased, User
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PaidMediaPurchasedCute(BaseCute[PaidMediaPurchased], PaidMediaPurchased, kw_only=True):
|
|
6
|
+
@property
|
|
7
|
+
def from_user(self) -> User:
|
|
8
|
+
return self.from_
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
__all__ = ("PaidMediaPurchasedCute",)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from kungfu.library.monad.result import Result
|
|
4
|
+
|
|
5
|
+
from telegrinder.api.error import APIError
|
|
6
|
+
from telegrinder.bot.cute_types.base import BaseCute, compose_method_params, shortcut
|
|
7
|
+
from telegrinder.types.methods_utils import get_params
|
|
8
|
+
from telegrinder.types.objects import PreCheckoutQuery, User
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PreCheckoutQueryCute(BaseCute[PreCheckoutQuery], PreCheckoutQuery, kw_only=True):
|
|
12
|
+
@property
|
|
13
|
+
def from_user(self) -> User:
|
|
14
|
+
return self.from_
|
|
15
|
+
|
|
16
|
+
@shortcut("answer_pre_checkout_query", custom_params={"pre_checkout_query_id"})
|
|
17
|
+
async def answer(
|
|
18
|
+
self,
|
|
19
|
+
ok: bool,
|
|
20
|
+
*,
|
|
21
|
+
error_message: str | None = None,
|
|
22
|
+
pre_checkout_query_id: str | None = None,
|
|
23
|
+
**other: typing.Any,
|
|
24
|
+
) -> Result[bool, APIError]:
|
|
25
|
+
"""Shortcut `API.answer_pre_checkout_query()`, see the [documentation](https://core.telegram.org/bots/api#answerprecheckoutquery)
|
|
26
|
+
|
|
27
|
+
Once the user has confirmed their payment and shipping details, the Bot
|
|
28
|
+
API sends the final confirmation in the form of an Update with the field pre_checkout_query.
|
|
29
|
+
Use this method to respond to such pre-checkout queries. On success, True
|
|
30
|
+
is returned. Note: The Bot API must receive an answer within 10 seconds after
|
|
31
|
+
the pre-checkout query was sent."""
|
|
32
|
+
params = compose_method_params(get_params(locals()), self, default_params={("pre_checkout_query_id", "id")})
|
|
33
|
+
return await self.ctx_api.answer_pre_checkout_query(**params)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = ("PreCheckoutQueryCute",)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
2
|
+
from telegrinder.types.objects import ShippingQuery, User
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ShippingQueryCute(BaseCute[ShippingQuery], ShippingQuery, kw_only=True):
|
|
6
|
+
@property
|
|
7
|
+
def from_user(self) -> User:
|
|
8
|
+
return self.from_
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
__all__ = ("ShippingQueryCute",)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from functools import cached_property
|
|
2
|
+
|
|
3
|
+
from kungfu.library.monad.option import NOTHING, Some
|
|
4
|
+
|
|
5
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
6
|
+
from telegrinder.bot.cute_types.business_connection import BusinessConnectionCute
|
|
7
|
+
from telegrinder.bot.cute_types.business_messages_deleted import BusinessMessagesDeletedCute
|
|
8
|
+
from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
|
|
9
|
+
from telegrinder.bot.cute_types.chat_boost_removed import ChatBoostRemovedCute
|
|
10
|
+
from telegrinder.bot.cute_types.chat_boost_updated import ChatBoostUpdatedCute
|
|
11
|
+
from telegrinder.bot.cute_types.chat_join_request import ChatJoinRequestCute
|
|
12
|
+
from telegrinder.bot.cute_types.chat_member_updated import ChatMemberUpdatedCute
|
|
13
|
+
from telegrinder.bot.cute_types.chosen_inline_result import ChosenInlineResultCute
|
|
14
|
+
from telegrinder.bot.cute_types.inline_query import InlineQueryCute
|
|
15
|
+
from telegrinder.bot.cute_types.message import MessageCute
|
|
16
|
+
from telegrinder.bot.cute_types.message_reaction_count_updated import MessageReactionCountUpdatedCute
|
|
17
|
+
from telegrinder.bot.cute_types.message_reaction_updated import MessageReactionUpdatedCute
|
|
18
|
+
from telegrinder.bot.cute_types.paid_media_purchased import PaidMediaPurchasedCute
|
|
19
|
+
from telegrinder.bot.cute_types.poll import PollCute
|
|
20
|
+
from telegrinder.bot.cute_types.poll_answer import PollAnswerCute
|
|
21
|
+
from telegrinder.bot.cute_types.pre_checkout_query import PreCheckoutQueryCute
|
|
22
|
+
from telegrinder.bot.cute_types.shipping_query import ShippingQueryCute
|
|
23
|
+
from telegrinder.model import From, field
|
|
24
|
+
from telegrinder.msgspec_utils import Option
|
|
25
|
+
from telegrinder.types.objects import *
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UpdateCute(BaseCute[Update], Update, kw_only=True):
|
|
29
|
+
"""Cute version of the object [Update](https://core.telegram.org/bots/api#update).
|
|
30
|
+
|
|
31
|
+
This object represents a `cute` incoming update.
|
|
32
|
+
At most one of the optional parameters can be present in any given cute update.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
message: Option[MessageCute] = field(
|
|
36
|
+
default=...,
|
|
37
|
+
converter=From[MessageCute | None],
|
|
38
|
+
)
|
|
39
|
+
"""Optional. New incoming message of any kind - text, photo, sticker, etc."""
|
|
40
|
+
|
|
41
|
+
edited_message: Option[MessageCute] = field(
|
|
42
|
+
default=...,
|
|
43
|
+
converter=From[MessageCute | None],
|
|
44
|
+
)
|
|
45
|
+
"""Optional. New version of a message that is known to the bot and was edited.
|
|
46
|
+
This update may at times be triggered by changes to message fields that are
|
|
47
|
+
either unavailable or not actively used by your bot."""
|
|
48
|
+
|
|
49
|
+
channel_post: Option[MessageCute] = field(
|
|
50
|
+
default=...,
|
|
51
|
+
converter=From[MessageCute | None],
|
|
52
|
+
)
|
|
53
|
+
"""Optional. New incoming channel post of any kind - text, photo, sticker,
|
|
54
|
+
etc."""
|
|
55
|
+
|
|
56
|
+
edited_channel_post: Option[MessageCute] = field(
|
|
57
|
+
default=...,
|
|
58
|
+
converter=From[MessageCute | None],
|
|
59
|
+
)
|
|
60
|
+
"""Optional. New version of a channel post that is known to the bot and was edited.
|
|
61
|
+
This update may at times be triggered by changes to message fields that are
|
|
62
|
+
either unavailable or not actively used by your bot."""
|
|
63
|
+
|
|
64
|
+
business_connection: Option[BusinessConnectionCute] = field(
|
|
65
|
+
default=...,
|
|
66
|
+
converter=From["BusinessConnectionCute | None"],
|
|
67
|
+
)
|
|
68
|
+
"""Optional. The bot was connected to or disconnected from a business account,
|
|
69
|
+
or a user edited an existing connection with the bot."""
|
|
70
|
+
|
|
71
|
+
business_message: Option[MessageCute] = field(
|
|
72
|
+
default=...,
|
|
73
|
+
converter=From[MessageCute | None],
|
|
74
|
+
)
|
|
75
|
+
"""Optional. New message from a connected business account."""
|
|
76
|
+
|
|
77
|
+
edited_business_message: Option[MessageCute] = field(
|
|
78
|
+
default=...,
|
|
79
|
+
converter=From[MessageCute | None],
|
|
80
|
+
)
|
|
81
|
+
"""Optional. New version of a message from a connected business account."""
|
|
82
|
+
|
|
83
|
+
deleted_business_messages: Option[BusinessMessagesDeletedCute] = field(
|
|
84
|
+
default=...,
|
|
85
|
+
converter=From["BusinessMessagesDeletedCute | None"],
|
|
86
|
+
)
|
|
87
|
+
"""Optional. Messages were deleted from a connected business account."""
|
|
88
|
+
|
|
89
|
+
message_reaction: Option[MessageReactionUpdatedCute] = field(
|
|
90
|
+
default=...,
|
|
91
|
+
converter=From["MessageReactionUpdatedCute | None"],
|
|
92
|
+
)
|
|
93
|
+
"""Optional. A reaction to a message was changed by a user. The bot must be an
|
|
94
|
+
administrator in the chat and must explicitly specify `message_reaction`
|
|
95
|
+
in the list of allowed_updates to receive these updates. The update isn't
|
|
96
|
+
received for reactions set by bots."""
|
|
97
|
+
|
|
98
|
+
message_reaction_count: Option[MessageReactionCountUpdatedCute] = field(
|
|
99
|
+
default=...,
|
|
100
|
+
converter=From["MessageReactionCountUpdatedCute | None"],
|
|
101
|
+
)
|
|
102
|
+
"""Optional. Reactions to a message with anonymous reactions were changed.
|
|
103
|
+
The bot must be an administrator in the chat and must explicitly specify
|
|
104
|
+
`message_reaction_count` in the list of allowed_updates to receive these
|
|
105
|
+
updates. The updates are grouped and can be sent with delay up to a few minutes."""
|
|
106
|
+
|
|
107
|
+
inline_query: Option[InlineQueryCute] = field(
|
|
108
|
+
default=...,
|
|
109
|
+
converter=From[InlineQueryCute | None],
|
|
110
|
+
)
|
|
111
|
+
"""Optional. New incoming inline query."""
|
|
112
|
+
|
|
113
|
+
chosen_inline_result: Option[ChosenInlineResultCute] = field(
|
|
114
|
+
default=...,
|
|
115
|
+
converter=From["ChosenInlineResultCute | None"],
|
|
116
|
+
)
|
|
117
|
+
"""Optional. The result of an inline query that was chosen by a user and sent
|
|
118
|
+
to their chat partner. Please see our documentation on the feedback collecting
|
|
119
|
+
for details on how to enable these updates for your bot."""
|
|
120
|
+
|
|
121
|
+
callback_query: Option[CallbackQueryCute] = field(
|
|
122
|
+
default=...,
|
|
123
|
+
converter=From[CallbackQueryCute | None],
|
|
124
|
+
)
|
|
125
|
+
"""Optional. New incoming callback query."""
|
|
126
|
+
|
|
127
|
+
shipping_query: Option[ShippingQueryCute] = field(
|
|
128
|
+
default=...,
|
|
129
|
+
converter=From[ShippingQueryCute | None],
|
|
130
|
+
)
|
|
131
|
+
"""Optional. New incoming shipping query. Only for invoices with flexible
|
|
132
|
+
price."""
|
|
133
|
+
|
|
134
|
+
pre_checkout_query: Option[PreCheckoutQueryCute] = field(
|
|
135
|
+
default=...,
|
|
136
|
+
converter=From[PreCheckoutQueryCute | None],
|
|
137
|
+
)
|
|
138
|
+
"""Optional. New incoming pre-checkout query. Contains full information
|
|
139
|
+
about checkout."""
|
|
140
|
+
|
|
141
|
+
purchased_paid_media: Option[PaidMediaPurchasedCute] = field(
|
|
142
|
+
default=...,
|
|
143
|
+
converter=From["PaidMediaPurchasedCute | None"],
|
|
144
|
+
)
|
|
145
|
+
"""Optional. A user purchased paid media with a non-empty payload sent by the
|
|
146
|
+
bot in a non-channel chat."""
|
|
147
|
+
|
|
148
|
+
poll: Option[PollCute] = field(
|
|
149
|
+
default=...,
|
|
150
|
+
converter=From["PollCute | None"],
|
|
151
|
+
)
|
|
152
|
+
"""Optional. New poll state. Bots receive only updates about manually stopped
|
|
153
|
+
polls and polls, which are sent by the bot."""
|
|
154
|
+
|
|
155
|
+
poll_answer: Option[PollAnswerCute] = field(
|
|
156
|
+
default=...,
|
|
157
|
+
converter=From["PollAnswerCute | None"],
|
|
158
|
+
)
|
|
159
|
+
"""Optional. A user changed their answer in a non-anonymous poll. Bots receive
|
|
160
|
+
new votes only in polls that were sent by the bot itself."""
|
|
161
|
+
|
|
162
|
+
my_chat_member: Option[ChatMemberUpdatedCute] = field(
|
|
163
|
+
default=...,
|
|
164
|
+
converter=From[ChatMemberUpdatedCute | None],
|
|
165
|
+
)
|
|
166
|
+
"""Optional. The bot's chat member status was updated in a chat. For private
|
|
167
|
+
chats, this update is received only when the bot is blocked or unblocked
|
|
168
|
+
by the user."""
|
|
169
|
+
|
|
170
|
+
chat_member: Option[ChatMemberUpdatedCute] = field(
|
|
171
|
+
default=...,
|
|
172
|
+
converter=From[ChatMemberUpdatedCute | None],
|
|
173
|
+
)
|
|
174
|
+
"""Optional. A chat member's status was updated in a chat. The bot must be an
|
|
175
|
+
administrator in the chat and must explicitly specify `chat_member` in
|
|
176
|
+
the list of allowed_updates to receive these updates."""
|
|
177
|
+
|
|
178
|
+
chat_join_request: Option[ChatJoinRequestCute] = field(
|
|
179
|
+
default=...,
|
|
180
|
+
converter=From[ChatJoinRequestCute | None],
|
|
181
|
+
)
|
|
182
|
+
"""Optional. A request to join the chat has been sent. The bot must have the can_invite_users
|
|
183
|
+
administrator right in the chat to receive these updates."""
|
|
184
|
+
|
|
185
|
+
chat_boost: Option[ChatBoostUpdatedCute] = field(
|
|
186
|
+
default=...,
|
|
187
|
+
converter=From["ChatBoostUpdatedCute | None"],
|
|
188
|
+
)
|
|
189
|
+
"""Optional. A chat boost was added or changed. The bot must be an administrator
|
|
190
|
+
in the chat to receive these updates."""
|
|
191
|
+
|
|
192
|
+
removed_chat_boost: Option[ChatBoostRemovedCute] = field(
|
|
193
|
+
default=...,
|
|
194
|
+
converter=From["ChatBoostRemovedCute | None"],
|
|
195
|
+
)
|
|
196
|
+
"""Optional. A boost was removed from a chat. The bot must be an administrator
|
|
197
|
+
in the chat to receive these updates."""
|
|
198
|
+
|
|
199
|
+
@cached_property
|
|
200
|
+
def incoming_update(self) -> BaseCute:
|
|
201
|
+
return getattr(self, self.update_type.value).unwrap()
|
|
202
|
+
|
|
203
|
+
def get_event[T: BaseCute](self, event_model: type[T], /) -> Option[T]:
|
|
204
|
+
if isinstance(self.incoming_update, event_model):
|
|
205
|
+
return Some(self.incoming_update)
|
|
206
|
+
return NOTHING
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
__all__ = ("UpdateCute",)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from telegrinder.tools.formatting.html import FORMATTERS, link, pre_code, tg_emoji
|
|
5
|
+
from telegrinder.tools.strings import to_utf16_map, utf16_to_py_index
|
|
6
|
+
from telegrinder.types.enums import ContentType, MessageEntityType
|
|
7
|
+
from telegrinder.types.methods_utils import get_params
|
|
8
|
+
from telegrinder.types.objects import (
|
|
9
|
+
InputFile,
|
|
10
|
+
InputMediaAnimation,
|
|
11
|
+
InputMediaAudio,
|
|
12
|
+
InputMediaDocument,
|
|
13
|
+
InputMediaPhoto,
|
|
14
|
+
InputMediaVideo,
|
|
15
|
+
MessageEntity,
|
|
16
|
+
ReactionEmoji,
|
|
17
|
+
ReactionType,
|
|
18
|
+
ReactionTypeEmoji,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
type InputMedia = typing.Union[
|
|
22
|
+
InputMediaAnimation,
|
|
23
|
+
InputMediaAudio,
|
|
24
|
+
InputMediaDocument,
|
|
25
|
+
InputMediaPhoto,
|
|
26
|
+
InputMediaVideo,
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
type MediaType = typing.Literal["animation", "audio", "document", "photo", "video"]
|
|
30
|
+
|
|
31
|
+
EntitiesDict = collections.defaultdict[int, list[MessageEntity]]
|
|
32
|
+
|
|
33
|
+
MEDIA_TYPES: typing.Final = (
|
|
34
|
+
ContentType.ANIMATION,
|
|
35
|
+
ContentType.AUDIO,
|
|
36
|
+
ContentType.DOCUMENT,
|
|
37
|
+
ContentType.PHOTO,
|
|
38
|
+
ContentType.VIDEO,
|
|
39
|
+
)
|
|
40
|
+
INPUT_TYPES: typing.Final = (
|
|
41
|
+
InputMediaAnimation,
|
|
42
|
+
InputMediaAudio,
|
|
43
|
+
InputMediaDocument,
|
|
44
|
+
InputMediaPhoto,
|
|
45
|
+
InputMediaVideo,
|
|
46
|
+
)
|
|
47
|
+
INPUT_MEDIA_TYPES: typing.Final[dict[ContentType, type[InputMedia]]] = dict(zip(MEDIA_TYPES, INPUT_TYPES))
|
|
48
|
+
HTML_FORMAT_ENTITIES: typing.Final[tuple[MessageEntityType, ...]] = (
|
|
49
|
+
MessageEntityType.PRE,
|
|
50
|
+
MessageEntityType.CODE,
|
|
51
|
+
MessageEntityType.TEXT_LINK,
|
|
52
|
+
MessageEntityType.CUSTOM_EMOJI,
|
|
53
|
+
*tuple(x for x in MessageEntityType if x.name.lower() in FORMATTERS),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def build_html(text: str, entities: list[MessageEntity], /) -> str:
|
|
58
|
+
utf16_map = to_utf16_map(text)
|
|
59
|
+
text_length_utf16 = utf16_map[-1]
|
|
60
|
+
events = set[int]()
|
|
61
|
+
|
|
62
|
+
for entity in entities:
|
|
63
|
+
events.add(entity.offset)
|
|
64
|
+
events.add(entity.offset + entity.length)
|
|
65
|
+
|
|
66
|
+
events = sorted(events)
|
|
67
|
+
utf16_to_py = {u: utf16_to_py_index(utf16_map, u) for u in events + [0, text_length_utf16]}
|
|
68
|
+
|
|
69
|
+
opens = EntitiesDict(list)
|
|
70
|
+
closes = EntitiesDict(list)
|
|
71
|
+
|
|
72
|
+
for entity in entities:
|
|
73
|
+
opens[entity.offset].append(entity)
|
|
74
|
+
closes[entity.offset + entity.length].append(entity)
|
|
75
|
+
|
|
76
|
+
result = list[str]()
|
|
77
|
+
stack = collections.deque[MessageEntity]()
|
|
78
|
+
utf16_pos = 0
|
|
79
|
+
|
|
80
|
+
while utf16_pos < text_length_utf16:
|
|
81
|
+
py_start = utf16_to_py[utf16_pos]
|
|
82
|
+
next_events = [u for u in events if u > utf16_pos]
|
|
83
|
+
next_utf16 = min(next_events) if next_events else text_length_utf16
|
|
84
|
+
py_end = utf16_to_py[next_utf16]
|
|
85
|
+
|
|
86
|
+
if closes[utf16_pos]:
|
|
87
|
+
for _ in closes[utf16_pos]:
|
|
88
|
+
stack.pop()
|
|
89
|
+
|
|
90
|
+
if opens[utf16_pos]:
|
|
91
|
+
for e in sorted(opens[utf16_pos], key=lambda e: e.length, reverse=True):
|
|
92
|
+
stack.append(e)
|
|
93
|
+
|
|
94
|
+
chunk = text[py_start:py_end]
|
|
95
|
+
formatted = chunk
|
|
96
|
+
|
|
97
|
+
for e in reversed(stack):
|
|
98
|
+
if (formatter := FORMATTERS.get(e.type.name.lower())) is not None:
|
|
99
|
+
formatted = formatter(formatted)
|
|
100
|
+
elif e.type in (MessageEntityType.PRE, MessageEntityType.CODE):
|
|
101
|
+
formatted = pre_code(formatted, lang=e.language.unwrap_or_none())
|
|
102
|
+
elif e.type == MessageEntityType.TEXT_LINK:
|
|
103
|
+
formatted = link(e.url.unwrap(), text=formatted)
|
|
104
|
+
elif e.type == MessageEntityType.CUSTOM_EMOJI:
|
|
105
|
+
formatted = tg_emoji(formatted, emoji_id=e.custom_emoji_id.map(int).unwrap())
|
|
106
|
+
|
|
107
|
+
result.append(formatted)
|
|
108
|
+
utf16_pos = next_utf16
|
|
109
|
+
|
|
110
|
+
return "".join(result)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def compose_reactions(
|
|
114
|
+
reactions: str | ReactionEmoji | ReactionType | list[str | ReactionEmoji | ReactionType],
|
|
115
|
+
/,
|
|
116
|
+
) -> list[ReactionType]:
|
|
117
|
+
if not isinstance(reactions, list):
|
|
118
|
+
reactions = [reactions]
|
|
119
|
+
return [
|
|
120
|
+
(
|
|
121
|
+
ReactionTypeEmoji(emoji)
|
|
122
|
+
if isinstance(emoji, ReactionEmoji)
|
|
123
|
+
else (ReactionTypeEmoji(ReactionEmoji(emoji)) if isinstance(emoji, str) else emoji)
|
|
124
|
+
)
|
|
125
|
+
for emoji in reactions
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def input_media(
|
|
130
|
+
type: MediaType,
|
|
131
|
+
media: str | InputFile,
|
|
132
|
+
*,
|
|
133
|
+
caption: str | None = None,
|
|
134
|
+
parse_mode: str | None = None,
|
|
135
|
+
caption_entities: list[MessageEntity] | None = None,
|
|
136
|
+
**other: typing.Any,
|
|
137
|
+
) -> InputMedia:
|
|
138
|
+
return INPUT_MEDIA_TYPES[ContentType(type)](**get_params(locals()))
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
__all__ = ("build_html", "compose_reactions", "input_media")
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from telegrinder.bot.dispatch.abc import ABCDispatch
|
|
2
|
+
from telegrinder.bot.dispatch.action import action
|
|
3
|
+
from telegrinder.bot.dispatch.context import Context
|
|
4
|
+
from telegrinder.bot.dispatch.dispatch import Dispatch, TelegrinderContext
|
|
5
|
+
from telegrinder.bot.dispatch.handler import (
|
|
6
|
+
ABCHandler,
|
|
7
|
+
AudioReplyHandler,
|
|
8
|
+
DocumentReplyHandler,
|
|
9
|
+
FuncHandler,
|
|
10
|
+
MediaGroupReplyHandler,
|
|
11
|
+
MessageReplyHandler,
|
|
12
|
+
PhotoReplyHandler,
|
|
13
|
+
StickerReplyHandler,
|
|
14
|
+
VideoReplyHandler,
|
|
15
|
+
)
|
|
16
|
+
from telegrinder.bot.dispatch.middleware import ABCMiddleware, FilterMiddleware, MediaGroupMiddleware, MiddlewareBox
|
|
17
|
+
from telegrinder.bot.dispatch.process import check_rule, process_inner
|
|
18
|
+
from telegrinder.bot.dispatch.return_manager import (
|
|
19
|
+
ABCReturnManager,
|
|
20
|
+
BaseReturnManager,
|
|
21
|
+
CallbackQueryReturnManager,
|
|
22
|
+
InlineQueryReturnManager,
|
|
23
|
+
Manager,
|
|
24
|
+
MessageReturnManager,
|
|
25
|
+
PreCheckoutQueryReturnManager,
|
|
26
|
+
register_manager,
|
|
27
|
+
)
|
|
28
|
+
from telegrinder.bot.dispatch.router import ABCRouter, Router
|
|
29
|
+
from telegrinder.bot.dispatch.view import (
|
|
30
|
+
ABCView,
|
|
31
|
+
ErrorView,
|
|
32
|
+
EventModelView,
|
|
33
|
+
EventView,
|
|
34
|
+
MediaGroupView,
|
|
35
|
+
RawEventView,
|
|
36
|
+
View,
|
|
37
|
+
ViewBox,
|
|
38
|
+
)
|
|
39
|
+
from telegrinder.bot.dispatch.waiter_machine import (
|
|
40
|
+
CALLBACK_QUERY_FOR_MESSAGE,
|
|
41
|
+
CALLBACK_QUERY_FROM_CHAT,
|
|
42
|
+
CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE,
|
|
43
|
+
MESSAGE_FROM_USER,
|
|
44
|
+
MESSAGE_FROM_USER_IN_CHAT,
|
|
45
|
+
MESSAGE_IN_CHAT,
|
|
46
|
+
Hasher,
|
|
47
|
+
ShortState,
|
|
48
|
+
WaiterMachine,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
__all__ = (
|
|
52
|
+
"CALLBACK_QUERY_FOR_MESSAGE",
|
|
53
|
+
"CALLBACK_QUERY_FROM_CHAT",
|
|
54
|
+
"CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE",
|
|
55
|
+
"MESSAGE_FROM_USER",
|
|
56
|
+
"MESSAGE_FROM_USER_IN_CHAT",
|
|
57
|
+
"MESSAGE_IN_CHAT",
|
|
58
|
+
"ABCDispatch",
|
|
59
|
+
"ABCHandler",
|
|
60
|
+
"ABCMiddleware",
|
|
61
|
+
"ABCReturnManager",
|
|
62
|
+
"ABCRouter",
|
|
63
|
+
"ABCView",
|
|
64
|
+
"AudioReplyHandler",
|
|
65
|
+
"BaseReturnManager",
|
|
66
|
+
"CallbackQueryReturnManager",
|
|
67
|
+
"Context",
|
|
68
|
+
"Dispatch",
|
|
69
|
+
"DocumentReplyHandler",
|
|
70
|
+
"ErrorView",
|
|
71
|
+
"EventModelView",
|
|
72
|
+
"EventView",
|
|
73
|
+
"FilterMiddleware",
|
|
74
|
+
"FuncHandler",
|
|
75
|
+
"Hasher",
|
|
76
|
+
"InlineQueryReturnManager",
|
|
77
|
+
"Manager",
|
|
78
|
+
"MediaGroupMiddleware",
|
|
79
|
+
"MediaGroupReplyHandler",
|
|
80
|
+
"MediaGroupView",
|
|
81
|
+
"MessageReplyHandler",
|
|
82
|
+
"MessageReturnManager",
|
|
83
|
+
"MiddlewareBox",
|
|
84
|
+
"PhotoReplyHandler",
|
|
85
|
+
"PreCheckoutQueryReturnManager",
|
|
86
|
+
"RawEventView",
|
|
87
|
+
"Router",
|
|
88
|
+
"ShortState",
|
|
89
|
+
"StickerReplyHandler",
|
|
90
|
+
"TelegrinderContext",
|
|
91
|
+
"VideoReplyHandler",
|
|
92
|
+
"View",
|
|
93
|
+
"ViewBox",
|
|
94
|
+
"WaiterMachine",
|
|
95
|
+
"action",
|
|
96
|
+
"check_rule",
|
|
97
|
+
"process_inner",
|
|
98
|
+
"register_manager",
|
|
99
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import importlib.util as importlib_util
|
|
2
|
+
import os
|
|
3
|
+
import pathlib
|
|
4
|
+
import sys
|
|
5
|
+
import typing
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
|
|
8
|
+
from telegrinder.api.api import API
|
|
9
|
+
from telegrinder.types.objects import Update
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PathExistsError(BaseException):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ABCDispatch(ABC):
|
|
17
|
+
@abstractmethod
|
|
18
|
+
async def feed(self, api: API, update: Update) -> typing.Any:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def load(self, external: typing.Self) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def load_many(self, *externals: typing.Self) -> None:
|
|
26
|
+
for external in externals:
|
|
27
|
+
self.load(external)
|
|
28
|
+
|
|
29
|
+
def load_from_dir(
|
|
30
|
+
self,
|
|
31
|
+
directory: str | pathlib.Path,
|
|
32
|
+
*,
|
|
33
|
+
recursive: bool = False,
|
|
34
|
+
) -> bool:
|
|
35
|
+
"""Loads dispatchers from a directory containing Python modules where global variables
|
|
36
|
+
are declared with instances of dispatch.
|
|
37
|
+
Returns True if dispatchers were found, otherwise False.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
directory = pathlib.Path(directory)
|
|
41
|
+
|
|
42
|
+
if not directory.exists():
|
|
43
|
+
raise PathExistsError(f"Path `{directory!s}` doesn't exists.")
|
|
44
|
+
|
|
45
|
+
found = False
|
|
46
|
+
files_iter = os.walk(directory) if recursive else [(directory, [], os.listdir(directory))]
|
|
47
|
+
|
|
48
|
+
for root, _, files in files_iter:
|
|
49
|
+
for f in files:
|
|
50
|
+
if f.endswith(".py") and f != "__init__.py":
|
|
51
|
+
module_path = os.path.join(root, f)
|
|
52
|
+
relative_path = os.path.relpath(module_path, sys.path[0])
|
|
53
|
+
module_name = os.path.splitext(relative_path)[0].replace(os.sep, ".")
|
|
54
|
+
|
|
55
|
+
if module_name not in sys.modules:
|
|
56
|
+
spec = importlib_util.spec_from_file_location(module_name, module_path)
|
|
57
|
+
if spec is None or spec.loader is None:
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
module = importlib_util.module_from_spec(spec)
|
|
61
|
+
sys.modules[module_name] = module
|
|
62
|
+
spec.loader.exec_module(module)
|
|
63
|
+
else:
|
|
64
|
+
module = sys.modules[module_name]
|
|
65
|
+
|
|
66
|
+
for obj in vars(module).values():
|
|
67
|
+
if isinstance(obj, type(self)):
|
|
68
|
+
found = True
|
|
69
|
+
self.load(obj)
|
|
70
|
+
|
|
71
|
+
return found
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
__all__ = ("ABCDispatch",)
|