telegrinder 0.3.2__py3-none-any.whl → 0.3.3__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 (44) hide show
  1. telegrinder/bot/cute_types/__init__.py +6 -6
  2. telegrinder/bot/cute_types/callback_query.py +5 -2
  3. telegrinder/bot/cute_types/inline_query.py +3 -13
  4. telegrinder/bot/cute_types/message.py +9 -3
  5. telegrinder/bot/cute_types/update.py +45 -11
  6. telegrinder/bot/cute_types/utils.py +5 -5
  7. telegrinder/bot/dispatch/context.py +6 -0
  8. telegrinder/bot/dispatch/handler/func.py +10 -3
  9. telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +2 -2
  10. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +2 -2
  11. telegrinder/bot/dispatch/waiter_machine/machine.py +6 -7
  12. telegrinder/bot/dispatch/waiter_machine/short_state.py +4 -1
  13. telegrinder/bot/rules/abc.py +2 -27
  14. telegrinder/bot/rules/adapter/abc.py +1 -1
  15. telegrinder/bot/rules/adapter/event.py +22 -31
  16. telegrinder/bot/rules/adapter/node.py +1 -1
  17. telegrinder/bot/rules/adapter/raw_update.py +1 -1
  18. telegrinder/bot/rules/callback_data.py +1 -2
  19. telegrinder/bot/rules/chat_join.py +1 -3
  20. telegrinder/bot/rules/inline.py +1 -1
  21. telegrinder/bot/rules/is_from.py +19 -19
  22. telegrinder/bot/rules/message.py +2 -2
  23. telegrinder/model.py +51 -0
  24. telegrinder/msgspec_utils.py +2 -2
  25. telegrinder/node/__init__.py +24 -20
  26. telegrinder/node/attachment.py +5 -5
  27. telegrinder/node/base.py +30 -7
  28. telegrinder/node/callback_query.py +41 -2
  29. telegrinder/node/composer.py +6 -4
  30. telegrinder/node/event.py +3 -9
  31. telegrinder/node/text.py +22 -2
  32. telegrinder/tools/formatting/html.py +25 -25
  33. telegrinder/tools/i18n/__init__.py +5 -5
  34. telegrinder/tools/i18n/abc.py +2 -2
  35. telegrinder/tools/keyboard.py +5 -5
  36. telegrinder/tools/loop_wrapper/loop_wrapper.py +17 -9
  37. telegrinder/tools/magic.py +11 -11
  38. telegrinder/types/__init__.py +254 -254
  39. telegrinder/types/enums.py +29 -29
  40. telegrinder/types/objects.py +3723 -1703
  41. {telegrinder-0.3.2.dist-info → telegrinder-0.3.3.dist-info}/METADATA +1 -1
  42. {telegrinder-0.3.2.dist-info → telegrinder-0.3.3.dist-info}/RECORD +44 -44
  43. {telegrinder-0.3.2.dist-info → telegrinder-0.3.3.dist-info}/LICENSE +0 -0
  44. {telegrinder-0.3.2.dist-info → telegrinder-0.3.3.dist-info}/WHEEL +0 -0
@@ -7,11 +7,11 @@ from telegrinder.bot.cute_types.message import MessageCute
7
7
  from telegrinder.bot.cute_types.update import UpdateCute
8
8
 
9
9
  __all__ = (
10
- "BaseCute",
11
- "CallbackQueryCute",
12
- "ChatJoinRequestCute",
13
- "ChatMemberUpdatedCute",
14
- "InlineQueryCute",
15
- "MessageCute",
10
+ "BaseCute",
11
+ "CallbackQueryCute",
12
+ "ChatJoinRequestCute",
13
+ "ChatMemberUpdatedCute",
14
+ "InlineQueryCute",
15
+ "MessageCute",
16
16
  "UpdateCute",
17
17
  )
@@ -7,7 +7,7 @@ from fntypes.co import Nothing, Result, Some, Variative, unwrapping
7
7
  from telegrinder.api import API, APIError
8
8
  from telegrinder.bot.cute_types.base import BaseCute, compose_method_params, shortcut
9
9
  from telegrinder.bot.cute_types.message import MediaType, MessageCute, ReplyMarkup, execute_method_edit
10
- from telegrinder.model import get_params
10
+ from telegrinder.model import From, field, get_params
11
11
  from telegrinder.msgspec_utils import Option, decoder
12
12
  from telegrinder.types.objects import *
13
13
 
@@ -15,7 +15,10 @@ from telegrinder.types.objects import *
15
15
  class CallbackQueryCute(BaseCute[CallbackQuery], CallbackQuery, kw_only=True):
16
16
  api: API
17
17
 
18
- message: Option[Variative[MessageCute, InaccessibleMessage]] = Nothing()
18
+ message: Option[Variative[MessageCute, InaccessibleMessage]] = field(
19
+ default=Nothing(),
20
+ converter=From[MessageCute | InaccessibleMessage | None],
21
+ )
19
22
  """Optional. Message sent by the bot with the callback button that originated
20
23
  the query."""
21
24
 
@@ -15,11 +15,11 @@ class InlineQueryCute(BaseCute[InlineQuery], InlineQuery, kw_only=True):
15
15
  def from_user(self) -> User:
16
16
  return self.from_
17
17
 
18
- @shortcut("answer_inline_query", custom_params={"results"})
18
+ @shortcut("answer_inline_query", custom_params={"results", "inline_query_id"})
19
19
  async def answer(
20
20
  self,
21
21
  results: InlineQueryResult | list[InlineQueryResult],
22
- inline_query_id: str,
22
+ inline_query_id: str | None = None,
23
23
  cache_time: int | None = None,
24
24
  is_personal: bool | None = None,
25
25
  next_offset: str | None = None,
@@ -29,17 +29,7 @@ class InlineQueryCute(BaseCute[InlineQuery], InlineQuery, kw_only=True):
29
29
  """Shortcut `API.answer_inline_query()`, see the [documentation](https://core.telegram.org/bots/api#answerinlinequery)
30
30
 
31
31
  Use this method to send answers to an inline query. On success, True is returned.
32
- No more than 50 results per query are allowed.
33
- :param inline_query_id: Unique identifier for the answered query.
34
-
35
- :param results: A JSON-serialized array of results for the inline query.
36
-
37
- :param cache_time: The maximum amount of time in seconds that the result of the inline querymay be cached on the server. Defaults to 300.
38
-
39
- :param is_personal: Pass True if results may be cached on the server side only for the user thatsent the query. By default, results may be returned to any user who sendsthe same query.
40
-
41
- :param next_offset: Pass the offset that a client should send in the next query with the same textto receive more results. Pass an empty string if there are no more resultsor if you don't support pagination. Offset length can't exceed 64 bytes.
42
- :param button: A JSON-serialized object describing a button to be shown above inline queryresults."""
32
+ No more than 50 results per query are allowed."""
43
33
 
44
34
  params = compose_method_params(
45
35
  get_params(locals()),
@@ -13,7 +13,7 @@ from telegrinder.bot.cute_types.utils import (
13
13
  compose_reply_params,
14
14
  input_media,
15
15
  )
16
- from telegrinder.model import get_params
16
+ from telegrinder.model import From, field, get_params
17
17
  from telegrinder.msgspec_utils import Nothing, Option
18
18
  from telegrinder.types import *
19
19
 
@@ -135,12 +135,18 @@ def get_entity_value(
135
135
  class MessageCute(BaseCute[Message], Message, kw_only=True):
136
136
  api: API
137
137
 
138
- reply_to_message: Option[MessageCute] = Nothing
138
+ reply_to_message: Option[MessageCute] = field(
139
+ default=Nothing,
140
+ converter=From["MessageCute | None"],
141
+ )
139
142
  """Optional. For replies in the same chat and message thread, the original
140
143
  message. Note that the Message object in this field will not contain further
141
144
  reply_to_message fields even if it itself is a reply."""
142
145
 
143
- pinned_message: Option[Variative[MessageCute, InaccessibleMessage]] = Nothing
146
+ pinned_message: Option[Variative[MessageCute, InaccessibleMessage]] = field(
147
+ default=Nothing,
148
+ converter=From["MessageCute | InaccessibleMessage | None"],
149
+ )
144
150
  """Optional. Specified message was pinned. Note that the Message object in
145
151
  this field will not contain further reply_to_message fields even if it
146
152
  itself is a reply."""
@@ -10,6 +10,7 @@ from telegrinder.bot.cute_types.chat_join_request import ChatJoinRequestCute
10
10
  from telegrinder.bot.cute_types.chat_member_updated import ChatMemberUpdatedCute
11
11
  from telegrinder.bot.cute_types.inline_query import InlineQueryCute
12
12
  from telegrinder.bot.cute_types.message import MessageCute
13
+ from telegrinder.model import From, field
13
14
  from telegrinder.msgspec_utils import Option
14
15
  from telegrinder.types.objects import *
15
16
 
@@ -19,46 +20,79 @@ EventModel = typing.TypeVar("EventModel", bound=Model)
19
20
  class UpdateCute(BaseCute[Update], Update, kw_only=True):
20
21
  api: API
21
22
 
22
- message: Option[MessageCute] = Nothing()
23
+ message: Option[MessageCute] = field(
24
+ default=Nothing(),
25
+ converter=From[MessageCute | None],
26
+ )
23
27
  """Optional. New incoming message of any kind - text, photo, sticker, etc."""
24
28
 
25
- edited_message: Option[MessageCute] = Nothing()
29
+ edited_message: Option[MessageCute] = field(
30
+ default=Nothing(),
31
+ converter=From[MessageCute | None],
32
+ )
26
33
  """Optional. New version of a message that is known to the bot and was edited.
27
34
  This update may at times be triggered by changes to message fields that are
28
35
  either unavailable or not actively used by your bot."""
29
36
 
30
- channel_post: Option[MessageCute] = Nothing()
37
+ channel_post: Option[MessageCute] = field(
38
+ default=Nothing(),
39
+ converter=From[MessageCute | None],
40
+ )
31
41
  """Optional. New incoming channel post of any kind - text, photo, sticker,
32
42
  etc."""
33
43
 
34
- edited_channel_post: Option[MessageCute] = Nothing()
44
+ edited_channel_post: Option[MessageCute] = field(
45
+ default=Nothing(),
46
+ converter=From[MessageCute | None],
47
+ )
35
48
  """Optional. New version of a channel post that is known to the bot and was edited.
36
49
  This update may at times be triggered by changes to message fields that are
37
50
  either unavailable or not actively used by your bot."""
38
51
 
39
- business_message: Option[MessageCute] = Nothing()
52
+ business_message: Option[MessageCute] = field(
53
+ default=Nothing(),
54
+ converter=From[MessageCute | None],
55
+ )
40
56
  """Optional. New message from a connected business account."""
41
57
 
42
- edited_business_message: Option[MessageCute] = Nothing()
58
+ edited_business_message: Option[MessageCute] = field(
59
+ default=Nothing(),
60
+ converter=From[MessageCute | None],
61
+ )
43
62
  """Optional. New version of a message from a connected business account."""
44
63
 
45
- inline_query: Option[InlineQueryCute] = Nothing()
64
+ inline_query: Option[InlineQueryCute] = field(
65
+ default=Nothing(),
66
+ converter=From[InlineQueryCute | None],
67
+ )
46
68
  """Optional. New incoming inline query."""
47
69
 
48
- callback_query: Option[CallbackQueryCute] = Nothing()
70
+ callback_query: Option[CallbackQueryCute] = field(
71
+ default=Nothing(),
72
+ converter=From[CallbackQueryCute | None],
73
+ )
49
74
  """Optional. New incoming callback query."""
50
75
 
51
- my_chat_member: Option[ChatMemberUpdatedCute] = Nothing()
76
+ my_chat_member: Option[ChatMemberUpdatedCute] = field(
77
+ default=Nothing(),
78
+ converter=From[ChatMemberUpdatedCute | None],
79
+ )
52
80
  """Optional. The bot's chat member status was updated in a chat. For private
53
81
  chats, this update is received only when the bot is blocked or unblocked
54
82
  by the user."""
55
83
 
56
- chat_member: Option[ChatMemberUpdatedCute] = Nothing()
84
+ chat_member: Option[ChatMemberUpdatedCute] = field(
85
+ default=Nothing(),
86
+ converter=From[ChatMemberUpdatedCute | None],
87
+ )
57
88
  """Optional. A chat member's status was updated in a chat. The bot must be an
58
89
  administrator in the chat and must explicitly specify `chat_member` in
59
90
  the list of allowed_updates to receive these updates."""
60
91
 
61
- chat_join_request: Option[ChatJoinRequestCute] = Nothing()
92
+ chat_join_request: Option[ChatJoinRequestCute] = field(
93
+ default=Nothing(),
94
+ converter=From[ChatJoinRequestCute | None],
95
+ )
62
96
  """Optional. A request to join the chat has been sent. The bot must have the can_invite_users
63
97
  administrator right in the chat to receive these updates."""
64
98
 
@@ -41,9 +41,9 @@ def compose_reactions(
41
41
  reactions = [reactions]
42
42
  return [
43
43
  (
44
- ReactionTypeEmoji("emoji", emoji)
44
+ ReactionTypeEmoji(emoji)
45
45
  if isinstance(emoji, ReactionEmoji)
46
- else (ReactionTypeEmoji("emoji", ReactionEmoji(emoji)) if isinstance(emoji, str) else emoji)
46
+ else (ReactionTypeEmoji(ReactionEmoji(emoji)) if isinstance(emoji, str) else emoji)
47
47
  )
48
48
  for emoji in ([reactions] if isinstance(reactions, str) else reactions) # type: ignore
49
49
  ]
@@ -88,8 +88,8 @@ def input_media(
88
88
 
89
89
 
90
90
  __all__ = (
91
- "compose_link_preview_options",
92
- "compose_reactions",
93
- "compose_reply_params",
91
+ "compose_link_preview_options",
92
+ "compose_reactions",
93
+ "compose_reply_params",
94
94
  "input_media",
95
95
  )
@@ -1,9 +1,14 @@
1
+ from __future__ import annotations
2
+
1
3
  import enum
2
4
  import typing
3
5
  from reprlib import recursive_repr
4
6
 
5
7
  from telegrinder.types.objects import Update
6
8
 
9
+ if typing.TYPE_CHECKING:
10
+ from telegrinder.node.composer import NodeCollection
11
+
7
12
  T = typing.TypeVar("T")
8
13
 
9
14
  Key: typing.TypeAlias = str | enum.Enum
@@ -24,6 +29,7 @@ class Context(dict[str, AnyValue]):
24
29
  """
25
30
 
26
31
  raw_update: Update
32
+ node_col: NodeCollection | None = None
27
33
 
28
34
  def __init__(self, **kwargs: AnyValue) -> None:
29
35
  cls_vars = vars(self.__class__)
@@ -10,7 +10,7 @@ from telegrinder.bot.dispatch.process import check_rule
10
10
  from telegrinder.model import Model
11
11
  from telegrinder.modules import logger
12
12
  from telegrinder.node.base import Node, get_nodes
13
- from telegrinder.node.composer import compose_nodes
13
+ from telegrinder.node.composer import NodeCollection, compose_nodes
14
14
  from telegrinder.node.event import EVENT_NODE_KEY
15
15
  from telegrinder.tools.error_handler import ABCErrorHandler, ErrorHandler
16
16
  from telegrinder.types.enums import UpdateType
@@ -19,7 +19,8 @@ from telegrinder.types.objects import Update
19
19
  from .abc import ABCHandler
20
20
 
21
21
  if typing.TYPE_CHECKING:
22
- from telegrinder.bot.rules import ABCRule
22
+ from telegrinder.bot.rules.abc import ABCRule
23
+ from telegrinder.node.composer import NodeCollection
23
24
 
24
25
  Rest = typing.ParamSpec("Rest")
25
26
  Result = typing.TypeVar("Result")
@@ -101,7 +102,13 @@ class FuncHandler(ABCHandler[Event], typing.Generic[Event, Function, ErrorHandle
101
102
  ctx |= temp_ctx
102
103
  return True
103
104
 
104
- async def run(self, api: API, event: Event, ctx: Context) -> typing.Any:
105
+ async def run(
106
+ self,
107
+ api: API,
108
+ event: Event,
109
+ ctx: Context,
110
+ node_col: "NodeCollection | None" = None,
111
+ ) -> typing.Any:
105
112
  logger.debug(f"Running func handler {self.function.__qualname__!r}")
106
113
 
107
114
  if self.dataclass is not None and EVENT_NODE_KEY not in ctx:
@@ -51,7 +51,7 @@ CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE = Hasher(
51
51
 
52
52
 
53
53
  __all__ = (
54
- "CALLBACK_QUERY_FOR_MESSAGE",
55
- "CALLBACK_QUERY_FROM_CHAT",
54
+ "CALLBACK_QUERY_FOR_MESSAGE",
55
+ "CALLBACK_QUERY_FROM_CHAT",
56
56
  "CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE",
57
57
  )
@@ -47,7 +47,7 @@ MESSAGE_FROM_USER_IN_CHAT = Hasher(
47
47
 
48
48
 
49
49
  __all__ = (
50
- "MESSAGE_FROM_USER",
51
- "MESSAGE_FROM_USER_IN_CHAT",
50
+ "MESSAGE_FROM_USER",
51
+ "MESSAGE_FROM_USER_IN_CHAT",
52
52
  "MESSAGE_IN_CHAT",
53
53
  )
@@ -51,12 +51,11 @@ class WaiterMachine:
51
51
  for hasher in self.storage:
52
52
  for ident, short_state in self.storage[hasher].items():
53
53
  if short_state.context:
54
- await self.drop(
55
- hasher,
56
- ident,
57
- )
54
+ await self.drop(hasher, ident)
58
55
  else:
59
- short_state.cancel()
56
+ await short_state.cancel()
57
+
58
+ del self.storage[hasher]
60
59
 
61
60
  async def drop(
62
61
  self,
@@ -79,7 +78,7 @@ class WaiterMachine:
79
78
  if on_drop := short_state.actions.get("on_drop"):
80
79
  on_drop(short_state, **context)
81
80
 
82
- short_state.cancel()
81
+ await short_state.cancel()
83
82
 
84
83
  async def wait_from_event(
85
84
  self,
@@ -135,7 +134,7 @@ class WaiterMachine:
135
134
  self.storage[hasher] = LimitedDict(maxlimit=self.max_storage_size)
136
135
 
137
136
  if (deleted_short_state := self.storage[hasher].set(waiter_hash, short_state)) is not None:
138
- deleted_short_state.cancel()
137
+ await deleted_short_state.cancel()
139
138
 
140
139
  await event.wait()
141
140
  self.storage[hasher].pop(waiter_hash, None)
@@ -2,6 +2,7 @@ import asyncio
2
2
  import dataclasses
3
3
  import datetime
4
4
  import typing
5
+ from contextlib import suppress
5
6
 
6
7
  from telegrinder.bot.cute_types import BaseCute
7
8
  from telegrinder.bot.dispatch.context import Context
@@ -51,7 +52,7 @@ class ShortState(typing.Generic[EventModel]):
51
52
  self.creation_date = datetime.datetime.now()
52
53
  self.expiration_date = (self.creation_date + expiration) if expiration is not None else None
53
54
 
54
- def cancel(self) -> None:
55
+ async def cancel(self) -> None:
55
56
  """Cancel schedule waiters."""
56
57
 
57
58
  waiters = typing.cast(
@@ -60,6 +61,8 @@ class ShortState(typing.Generic[EventModel]):
60
61
  )
61
62
  for future in waiters:
62
63
  future.cancel()
64
+ with suppress(asyncio.CancelledError):
65
+ await future
63
66
 
64
67
 
65
68
  __all__ = ("ShortState", "ShortStateContext")
@@ -24,7 +24,7 @@ if typing.TYPE_CHECKING:
24
24
 
25
25
  AdaptTo = typing.TypeVar("AdaptTo", default=typing.Any, contravariant=True)
26
26
 
27
- CheckResult: typing.TypeAlias = bool | typing.Coroutine[typing.Any, typing.Any, bool]
27
+ CheckResult: typing.TypeAlias = bool | typing.Awaitable[bool]
28
28
  Message: typing.TypeAlias = MessageCute
29
29
  Update: typing.TypeAlias = UpdateCute
30
30
 
@@ -48,31 +48,6 @@ class ABCRule(ABC, typing.Generic[AdaptTo]):
48
48
 
49
49
  if typing.TYPE_CHECKING:
50
50
 
51
- @typing.overload
52
- def check(self) -> CheckResult: ...
53
-
54
- @typing.overload
55
- def check(self, event: AdaptTo, /) -> CheckResult: ...
56
-
57
- @typing.overload
58
- def check(self, event: AdaptTo, ctx: Context, /) -> CheckResult: ...
59
-
60
- @typing.overload
61
- def check(
62
- self,
63
- event: AdaptTo,
64
- ctx: Context,
65
- /,
66
- *args: typing.Any,
67
- **kwargs: typing.Any,
68
- ) -> CheckResult: ...
69
-
70
- @typing.overload
71
- def check(self, event: AdaptTo, /, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
72
-
73
- @typing.overload
74
- def check(self, ctx: Context, /, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
75
-
76
51
  @abstractmethod
77
52
  def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult:
78
53
  pass
@@ -230,9 +205,9 @@ __all__ = (
230
205
  "ABCRule",
231
206
  "Always",
232
207
  "AndRule",
208
+ "CheckResult",
233
209
  "Never",
234
210
  "NotRule",
235
211
  "OrRule",
236
- "CheckResult",
237
212
  "with_caching_translations",
238
213
  )
@@ -4,7 +4,7 @@ import typing
4
4
 
5
5
  from fntypes.result import Result
6
6
 
7
- from telegrinder.api import API
7
+ from telegrinder.api.api import API
8
8
  from telegrinder.bot.dispatch.context import Context
9
9
  from telegrinder.bot.rules.adapter.errors import AdapterError
10
10
  from telegrinder.model import Model
@@ -2,12 +2,12 @@ import typing
2
2
 
3
3
  from fntypes.result import Error, Ok, Result
4
4
 
5
- from telegrinder.api import API
5
+ from telegrinder.api.api import API
6
6
  from telegrinder.bot.cute_types.base import BaseCute
7
7
  from telegrinder.bot.dispatch.context import Context
8
8
  from telegrinder.bot.rules.adapter.abc import ABCAdapter
9
9
  from telegrinder.bot.rules.adapter.errors import AdapterError
10
- from telegrinder.msgspec_utils import Nothing
10
+ from telegrinder.bot.rules.adapter.raw_update import RawUpdateAdapter
11
11
  from telegrinder.types.enums import UpdateType
12
12
  from telegrinder.types.objects import Model, Update
13
13
 
@@ -42,35 +42,26 @@ class EventAdapter(ABCAdapter[Update, ToCute]):
42
42
  if self.ADAPTED_VALUE_KEY in context:
43
43
  return Ok(context[self.ADAPTED_VALUE_KEY])
44
44
 
45
- if isinstance(self.event, UpdateType):
46
- if update.update_type != self.event:
47
- return Error(
48
- AdapterError(f"Update is not of event type {self.event!r}."),
49
- )
50
-
51
- if isinstance(event := getattr(update, self.event.value, Nothing), type(Nothing)):
52
- return Error(
53
- AdapterError(f"Update is not an {self.event!r}."),
54
- )
55
-
56
- event = event.unwrap()
57
-
58
- if type(event) is self.cute_model:
59
- adapted = event
60
- else:
61
- adapted = self.cute_model.from_update(event, bound_api=api)
62
- else:
63
- event = getattr(update, update.update_type.value).unwrap()
64
- if not update.update_type or not issubclass(type(event), self.event):
65
- return Error(AdapterError(f"Update is not an {self.event.__name__!r}."))
66
-
67
- if type(event) is self.cute_model:
68
- adapted = event
69
- else:
70
- adapted = self.cute_model.from_update(event, bound_api=api)
71
-
72
- context[self.ADAPTED_VALUE_KEY] = adapted
73
- return Ok(adapted) # type: ignore
45
+ match await RawUpdateAdapter().adapt(api, update, context):
46
+ case Ok(update_cute):
47
+ incoming_update = None
48
+ if isinstance(self.event, UpdateType) and self.event == update_cute.update_type:
49
+ incoming_update = update_cute.incoming_update
50
+ if not isinstance(self.event, UpdateType) and (event := update_cute.get_event(self.event)):
51
+ incoming_update = update_cute.get_event(self.event).unwrap_or_none()
52
+
53
+ if incoming_update is not None:
54
+ adapted = (
55
+ typing.cast(ToCute, incoming_update)
56
+ if isinstance(incoming_update, BaseCute)
57
+ else self.cute_model.from_update(incoming_update, bound_api=api)
58
+ )
59
+ context[self.ADAPTED_VALUE_KEY] = adapted
60
+ return Ok(adapted)
61
+
62
+ return Error(AdapterError(f"Update is not an {self.event!r}."))
63
+ case Error(_) as err:
64
+ return err
74
65
 
75
66
 
76
67
  __all__ = ("EventAdapter",)
@@ -1,7 +1,7 @@
1
1
  import typing_extensions as typing
2
2
  from fntypes.result import Error, Ok, Result
3
3
 
4
- from telegrinder.api import API
4
+ from telegrinder.api.api import API
5
5
  from telegrinder.bot.dispatch.context import Context
6
6
  from telegrinder.bot.rules.adapter.abc import ABCAdapter, Event
7
7
  from telegrinder.bot.rules.adapter.errors import AdapterError
@@ -1,6 +1,6 @@
1
1
  from fntypes.result import Ok, Result
2
2
 
3
- from telegrinder.api import API
3
+ from telegrinder.api.api import API
4
4
  from telegrinder.bot.cute_types.update import UpdateCute
5
5
  from telegrinder.bot.dispatch.context import Context
6
6
  from telegrinder.bot.rules.adapter.abc import ABCAdapter
@@ -26,8 +26,7 @@ class CallbackQueryRule(ABCRule[CallbackQuery], abc.ABC):
26
26
  adapter: EventAdapter[CallbackQuery] = EventAdapter(UpdateType.CALLBACK_QUERY, CallbackQuery)
27
27
 
28
28
  @abc.abstractmethod
29
- def check(self, event: CallbackQuery, context: Context) -> CheckResult:
30
- pass
29
+ def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
31
30
 
32
31
 
33
32
  class HasData(CallbackQueryRule):
@@ -2,7 +2,6 @@ import abc
2
2
  import typing
3
3
 
4
4
  from telegrinder.bot.cute_types import ChatJoinRequestCute
5
- from telegrinder.bot.dispatch.context import Context
6
5
  from telegrinder.bot.rules.adapter import EventAdapter
7
6
  from telegrinder.types.enums import UpdateType
8
7
 
@@ -15,8 +14,7 @@ class ChatJoinRequestRule(ABCRule[ChatJoinRequest], requires=[]):
15
14
  adapter: EventAdapter[ChatJoinRequest] = EventAdapter(UpdateType.CHAT_JOIN_REQUEST, ChatJoinRequest)
16
15
 
17
16
  @abc.abstractmethod
18
- def check(self, event: ChatJoinRequest, context: Context) -> CheckResult:
19
- pass
17
+ def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
20
18
 
21
19
 
22
20
  class HasInviteLink(ChatJoinRequestRule):
@@ -16,7 +16,7 @@ class InlineQueryRule(ABCRule[InlineQuery], abc.ABC):
16
16
  adapter: EventAdapter[InlineQuery] = EventAdapter(UpdateType.INLINE_QUERY, InlineQuery)
17
17
 
18
18
  @abc.abstractmethod
19
- def check(self, query: InlineQuery, ctx: Context) -> CheckResult: ...
19
+ def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
20
20
 
21
21
 
22
22
  class HasLocation(InlineQueryRule):
@@ -123,24 +123,24 @@ class IsPhoto(MessageRule):
123
123
 
124
124
 
125
125
  __all__ = (
126
- "IsBot",
127
- "IsChat",
128
- "IsChatId",
129
- "IsDice",
130
- "IsDiceEmoji",
131
- "IsDocument",
132
- "IsForum",
133
- "IsForward",
134
- "IsForwardType",
135
- "IsGroup",
136
- "IsLanguageCode",
137
- "IsPhoto",
138
- "IsPremium",
139
- "IsPrivate",
140
- "IsReply",
141
- "IsSticker",
142
- "IsSuperGroup",
143
- "IsUser",
144
- "IsUserId",
126
+ "IsBot",
127
+ "IsChat",
128
+ "IsChatId",
129
+ "IsDice",
130
+ "IsDiceEmoji",
131
+ "IsDocument",
132
+ "IsForum",
133
+ "IsForward",
134
+ "IsForwardType",
135
+ "IsGroup",
136
+ "IsLanguageCode",
137
+ "IsPhoto",
138
+ "IsPremium",
139
+ "IsPrivate",
140
+ "IsReply",
141
+ "IsSticker",
142
+ "IsSuperGroup",
143
+ "IsUser",
144
+ "IsUserId",
145
145
  "IsVideoNote",
146
146
  )
@@ -1,6 +1,6 @@
1
1
  import abc
2
+ import typing
2
3
 
3
- from telegrinder.bot.dispatch.context import Context
4
4
  from telegrinder.types.objects import Message as MessageEvent
5
5
 
6
6
  from .abc import ABCRule, CheckResult, Message
@@ -11,7 +11,7 @@ class MessageRule(ABCRule[Message], abc.ABC):
11
11
  adapter: EventAdapter[Message] = EventAdapter(MessageEvent, Message)
12
12
 
13
13
  @abc.abstractmethod
14
- def check(self, message: Message, ctx: Context) -> CheckResult: ...
14
+ def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
15
15
 
16
16
 
17
17
  __all__ = ("MessageRule",)