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.
- telegrinder/__init__.py +129 -22
- telegrinder/api/__init__.py +11 -2
- telegrinder/api/abc.py +25 -9
- telegrinder/api/api.py +47 -28
- telegrinder/api/error.py +14 -4
- telegrinder/api/response.py +11 -7
- telegrinder/bot/__init__.py +68 -7
- telegrinder/bot/bot.py +30 -24
- telegrinder/bot/cute_types/__init__.py +11 -1
- telegrinder/bot/cute_types/base.py +138 -0
- telegrinder/bot/cute_types/callback_query.py +458 -15
- telegrinder/bot/cute_types/inline_query.py +30 -24
- telegrinder/bot/cute_types/message.py +2982 -78
- telegrinder/bot/cute_types/update.py +30 -0
- telegrinder/bot/cute_types/utils.py +794 -0
- telegrinder/bot/dispatch/__init__.py +56 -3
- telegrinder/bot/dispatch/abc.py +9 -7
- telegrinder/bot/dispatch/composition.py +74 -0
- telegrinder/bot/dispatch/context.py +71 -0
- telegrinder/bot/dispatch/dispatch.py +86 -49
- telegrinder/bot/dispatch/handler/__init__.py +3 -0
- telegrinder/bot/dispatch/handler/abc.py +11 -5
- telegrinder/bot/dispatch/handler/func.py +41 -32
- telegrinder/bot/dispatch/handler/message_reply.py +46 -0
- telegrinder/bot/dispatch/middleware/__init__.py +2 -0
- telegrinder/bot/dispatch/middleware/abc.py +10 -4
- telegrinder/bot/dispatch/process.py +53 -49
- telegrinder/bot/dispatch/return_manager/__init__.py +19 -0
- telegrinder/bot/dispatch/return_manager/abc.py +95 -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 +25 -0
- telegrinder/bot/dispatch/view/__init__.py +14 -2
- telegrinder/bot/dispatch/view/abc.py +128 -2
- telegrinder/bot/dispatch/view/box.py +38 -0
- telegrinder/bot/dispatch/view/callback_query.py +13 -39
- telegrinder/bot/dispatch/view/inline_query.py +11 -39
- telegrinder/bot/dispatch/view/message.py +11 -47
- telegrinder/bot/dispatch/waiter_machine/__init__.py +9 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +116 -0
- telegrinder/bot/dispatch/waiter_machine/middleware.py +76 -0
- telegrinder/bot/dispatch/waiter_machine/short_state.py +37 -0
- telegrinder/bot/polling/__init__.py +2 -0
- telegrinder/bot/polling/abc.py +11 -4
- telegrinder/bot/polling/polling.py +89 -40
- telegrinder/bot/rules/__init__.py +91 -5
- telegrinder/bot/rules/abc.py +81 -63
- telegrinder/bot/rules/adapter/__init__.py +11 -0
- telegrinder/bot/rules/adapter/abc.py +21 -0
- telegrinder/bot/rules/adapter/errors.py +5 -0
- telegrinder/bot/rules/adapter/event.py +49 -0
- telegrinder/bot/rules/adapter/raw_update.py +24 -0
- telegrinder/bot/rules/callback_data.py +159 -38
- telegrinder/bot/rules/command.py +116 -0
- telegrinder/bot/rules/enum_text.py +28 -0
- telegrinder/bot/rules/func.py +17 -17
- telegrinder/bot/rules/fuzzy.py +13 -10
- telegrinder/bot/rules/inline.py +61 -0
- telegrinder/bot/rules/integer.py +12 -7
- telegrinder/bot/rules/is_from.py +148 -7
- telegrinder/bot/rules/markup.py +21 -18
- telegrinder/bot/rules/mention.py +17 -0
- telegrinder/bot/rules/message_entities.py +33 -0
- telegrinder/bot/rules/regex.py +27 -19
- telegrinder/bot/rules/rule_enum.py +74 -0
- telegrinder/bot/rules/start.py +25 -13
- telegrinder/bot/rules/text.py +23 -14
- telegrinder/bot/scenario/__init__.py +2 -0
- telegrinder/bot/scenario/abc.py +12 -5
- telegrinder/bot/scenario/checkbox.py +48 -30
- telegrinder/bot/scenario/choice.py +16 -10
- telegrinder/client/__init__.py +3 -1
- telegrinder/client/abc.py +26 -16
- telegrinder/client/aiohttp.py +54 -32
- telegrinder/model.py +119 -40
- telegrinder/modules.py +189 -21
- telegrinder/msgspec_json.py +14 -0
- telegrinder/msgspec_utils.py +227 -0
- telegrinder/node/__init__.py +31 -0
- telegrinder/node/attachment.py +71 -0
- telegrinder/node/base.py +93 -0
- telegrinder/node/composer.py +71 -0
- telegrinder/node/container.py +22 -0
- telegrinder/node/message.py +18 -0
- telegrinder/node/rule.py +56 -0
- telegrinder/node/source.py +31 -0
- telegrinder/node/text.py +13 -0
- telegrinder/node/tools/__init__.py +3 -0
- telegrinder/node/tools/generator.py +40 -0
- telegrinder/node/update.py +12 -0
- telegrinder/rules.py +1 -1
- telegrinder/tools/__init__.py +138 -4
- telegrinder/tools/buttons.py +89 -51
- telegrinder/tools/error_handler/__init__.py +8 -0
- telegrinder/tools/error_handler/abc.py +30 -0
- telegrinder/tools/error_handler/error_handler.py +156 -0
- telegrinder/tools/formatting/__init__.py +81 -3
- telegrinder/tools/formatting/html.py +283 -37
- telegrinder/tools/formatting/links.py +32 -0
- telegrinder/tools/formatting/spec_html_formats.py +121 -0
- telegrinder/tools/global_context/__init__.py +12 -0
- telegrinder/tools/global_context/abc.py +66 -0
- telegrinder/tools/global_context/global_context.py +451 -0
- telegrinder/tools/global_context/telegrinder_ctx.py +25 -0
- telegrinder/tools/i18n/__init__.py +12 -0
- telegrinder/tools/i18n/base.py +31 -0
- telegrinder/tools/i18n/middleware/__init__.py +3 -0
- telegrinder/tools/i18n/middleware/base.py +26 -0
- telegrinder/tools/i18n/simple.py +48 -0
- telegrinder/tools/kb_set/__init__.py +2 -0
- telegrinder/tools/kb_set/base.py +3 -0
- telegrinder/tools/kb_set/yaml.py +28 -17
- telegrinder/tools/keyboard.py +84 -62
- telegrinder/tools/loop_wrapper/__init__.py +4 -0
- telegrinder/tools/loop_wrapper/abc.py +18 -0
- telegrinder/tools/loop_wrapper/loop_wrapper.py +132 -0
- telegrinder/tools/magic.py +48 -23
- telegrinder/tools/parse_mode.py +1 -2
- telegrinder/types/__init__.py +1 -0
- telegrinder/types/enums.py +653 -0
- telegrinder/types/methods.py +4107 -1279
- telegrinder/types/objects.py +4771 -1745
- {telegrinder-0.1.dev20.dist-info → telegrinder-0.1.dev159.dist-info}/LICENSE +2 -1
- telegrinder-0.1.dev159.dist-info/METADATA +109 -0
- telegrinder-0.1.dev159.dist-info/RECORD +126 -0
- {telegrinder-0.1.dev20.dist-info → telegrinder-0.1.dev159.dist-info}/WHEEL +1 -1
- telegrinder/bot/dispatch/waiter.py +0 -38
- telegrinder/result.py +0 -38
- telegrinder/tools/formatting/abc.py +0 -52
- telegrinder/tools/formatting/markdown.py +0 -57
- telegrinder-0.1.dev20.dist-info/METADATA +0 -22
- telegrinder-0.1.dev20.dist-info/RECORD +0 -71
|
@@ -1,61 +1,34 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
-
from .
|
|
4
|
-
from .middleware.abc import ABCMiddleware
|
|
5
|
-
from .handler.abc import ABCHandler
|
|
6
|
-
from telegrinder.types import Update
|
|
7
|
-
from telegrinder.modules import logger
|
|
8
|
-
|
|
9
|
-
T = typing.TypeVar("T")
|
|
10
|
-
E = typing.TypeVar("E")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async def process_waiters(
|
|
14
|
-
waiters: typing.Dict[T, Waiter],
|
|
15
|
-
key: T,
|
|
16
|
-
event: typing.Optional[E],
|
|
17
|
-
raw_event: dict,
|
|
18
|
-
str_handler: typing.Callable,
|
|
19
|
-
) -> bool:
|
|
20
|
-
if key not in waiters:
|
|
21
|
-
return False
|
|
22
|
-
|
|
23
|
-
logger.debug(
|
|
24
|
-
"update {} found in waiter (key={})", event.__class__.__name__, str(key)
|
|
25
|
-
)
|
|
3
|
+
from fntypes.result import Error
|
|
26
4
|
|
|
27
|
-
|
|
28
|
-
|
|
5
|
+
from telegrinder.api.abc import ABCAPI
|
|
6
|
+
from telegrinder.bot.cute_types import BaseCute
|
|
7
|
+
from telegrinder.bot.dispatch.context import Context
|
|
8
|
+
from telegrinder.modules import logger
|
|
9
|
+
from telegrinder.tools.i18n.base import I18nEnum
|
|
10
|
+
from telegrinder.types import Update
|
|
29
11
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if rule.__event__ is None:
|
|
33
|
-
chk_event = raw_event
|
|
34
|
-
if not await rule.run_check(chk_event, ctx):
|
|
35
|
-
if not waiter.default:
|
|
36
|
-
return True
|
|
37
|
-
elif isinstance(waiter.default, str):
|
|
38
|
-
await str_handler(waiter.default)
|
|
39
|
-
else:
|
|
40
|
-
await waiter.default(event)
|
|
41
|
-
return True
|
|
12
|
+
from .middleware.abc import ABCMiddleware
|
|
13
|
+
from .return_manager.abc import ABCReturnManager
|
|
42
14
|
|
|
43
|
-
|
|
15
|
+
if typing.TYPE_CHECKING:
|
|
16
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
17
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
44
18
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
waiter.event.set()
|
|
48
|
-
return True
|
|
19
|
+
T = typing.TypeVar("T", bound=BaseCute)
|
|
20
|
+
_ = typing.Any
|
|
49
21
|
|
|
50
22
|
|
|
51
23
|
async def process_inner(
|
|
52
24
|
event: T,
|
|
53
25
|
raw_event: Update,
|
|
54
|
-
middlewares:
|
|
55
|
-
handlers:
|
|
26
|
+
middlewares: list[ABCMiddleware[T]],
|
|
27
|
+
handlers: list["ABCHandler[T]"],
|
|
28
|
+
return_manager: ABCReturnManager[T],
|
|
56
29
|
) -> bool:
|
|
57
|
-
logger.debug("
|
|
58
|
-
ctx =
|
|
30
|
+
logger.debug("Processing {!r}...", event.__class__.__name__)
|
|
31
|
+
ctx = Context(raw_update=raw_event)
|
|
59
32
|
|
|
60
33
|
for middleware in middlewares:
|
|
61
34
|
if await middleware.pre(event, ctx) is False:
|
|
@@ -64,12 +37,12 @@ async def process_inner(
|
|
|
64
37
|
found = False
|
|
65
38
|
responses = []
|
|
66
39
|
for handler in handlers:
|
|
67
|
-
|
|
68
|
-
if result:
|
|
69
|
-
handler.ctx.update(ctx)
|
|
40
|
+
if await handler.check(event.api, raw_event, ctx):
|
|
70
41
|
found = True
|
|
42
|
+
handler.ctx |= ctx
|
|
71
43
|
response = await handler.run(event)
|
|
72
44
|
responses.append(response)
|
|
45
|
+
await return_manager.run(response, event, ctx)
|
|
73
46
|
if handler.is_blocking:
|
|
74
47
|
break
|
|
75
48
|
|
|
@@ -77,3 +50,34 @@ async def process_inner(
|
|
|
77
50
|
await middleware.post(event, responses, ctx)
|
|
78
51
|
|
|
79
52
|
return found
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def check_rule(
|
|
56
|
+
api: ABCAPI,
|
|
57
|
+
rule: "ABCRule",
|
|
58
|
+
update: Update,
|
|
59
|
+
ctx: Context,
|
|
60
|
+
) -> bool:
|
|
61
|
+
"""Checks requirements, adapts update.
|
|
62
|
+
Returns check result."""
|
|
63
|
+
|
|
64
|
+
cute_model = await rule.adapter.adapt(api, update)
|
|
65
|
+
match cute_model:
|
|
66
|
+
case Error(err):
|
|
67
|
+
logger.debug("Adapter failed with error message: {!r}", str(err))
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
ctx_copy = ctx.copy()
|
|
71
|
+
for requirement in rule.requires:
|
|
72
|
+
if not await check_rule(api, requirement, update, ctx_copy):
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
ctx |= ctx_copy
|
|
76
|
+
|
|
77
|
+
if I18nEnum.I18N in ctx:
|
|
78
|
+
rule = await rule.translate(ctx.get(I18nEnum.I18N))
|
|
79
|
+
|
|
80
|
+
return await rule.check(cute_model.unwrap(), ctx)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
__all__ = ("check_rule", "process_inner")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .abc import (
|
|
2
|
+
ABCReturnManager,
|
|
3
|
+
BaseReturnManager,
|
|
4
|
+
Manager,
|
|
5
|
+
register_manager,
|
|
6
|
+
)
|
|
7
|
+
from .callback_query import CallbackQueryReturnManager
|
|
8
|
+
from .inline_query import InlineQueryReturnManager
|
|
9
|
+
from .message import MessageReturnManager
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
"ABCReturnManager",
|
|
13
|
+
"BaseReturnManager",
|
|
14
|
+
"CallbackQueryReturnManager",
|
|
15
|
+
"InlineQueryReturnManager",
|
|
16
|
+
"Manager",
|
|
17
|
+
"MessageReturnManager",
|
|
18
|
+
"register_manager",
|
|
19
|
+
)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import types
|
|
3
|
+
import typing
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
|
|
6
|
+
from telegrinder.bot.cute_types import BaseCute
|
|
7
|
+
from telegrinder.bot.dispatch.context import Context
|
|
8
|
+
from telegrinder.modules import logger
|
|
9
|
+
|
|
10
|
+
T = typing.TypeVar("T")
|
|
11
|
+
EventT = typing.TypeVar("EventT", bound=BaseCute, contravariant=True)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_union_types(t: types.UnionType) -> tuple[type, ...] | None:
|
|
15
|
+
if type(t) in (types.UnionType, typing._UnionGenericAlias): # type: ignore
|
|
16
|
+
return tuple(typing.get_origin(x) or x for x in typing.get_args(t))
|
|
17
|
+
return None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def register_manager(return_type: type | types.UnionType):
|
|
21
|
+
def wrapper(func: typing.Callable[..., typing.Awaitable]):
|
|
22
|
+
return Manager(get_union_types(return_type) or (return_type,), func) # type: ignore
|
|
23
|
+
|
|
24
|
+
return wrapper
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclasses.dataclass(frozen=True)
|
|
28
|
+
class Manager:
|
|
29
|
+
types: tuple[type, ...]
|
|
30
|
+
callback: typing.Callable[..., typing.Awaitable]
|
|
31
|
+
|
|
32
|
+
async def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
|
|
33
|
+
try:
|
|
34
|
+
await self.callback(*args, **kwargs)
|
|
35
|
+
except BaseException as ex:
|
|
36
|
+
logger.exception(ex)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ABCReturnManager(ABC, typing.Generic[EventT]):
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def run(self, response: typing.Any, event: EventT, ctx: Context) -> None:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class BaseReturnManager(ABCReturnManager[EventT]):
|
|
46
|
+
@property
|
|
47
|
+
def managers(self) -> list[Manager]:
|
|
48
|
+
return [
|
|
49
|
+
manager
|
|
50
|
+
for manager in (vars(BaseReturnManager) | vars(self.__class__)).values()
|
|
51
|
+
if isinstance(manager, Manager)
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
@register_manager(Context)
|
|
55
|
+
@staticmethod
|
|
56
|
+
async def ctx_manager(value: Context, event: EventT, ctx: Context) -> None:
|
|
57
|
+
"""Basic manager for returning context from handler."""
|
|
58
|
+
|
|
59
|
+
ctx.update(value)
|
|
60
|
+
|
|
61
|
+
async def run(self, response: typing.Any, event: EventT, ctx: Context) -> None:
|
|
62
|
+
for manager in self.managers:
|
|
63
|
+
if typing.Any in manager.types or any(type(response) is x for x in manager.types):
|
|
64
|
+
await manager(response, event, ctx)
|
|
65
|
+
|
|
66
|
+
@typing.overload
|
|
67
|
+
def register_manager(self, return_type: type[T]) -> typing.Callable[
|
|
68
|
+
[typing.Callable[[T, EventT, Context], typing.Awaitable]], Manager
|
|
69
|
+
]:
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
@typing.overload
|
|
73
|
+
def register_manager(self, return_type: tuple[type[T], ...]) -> typing.Callable[
|
|
74
|
+
[typing.Callable[[tuple[T, ...], EventT, Context], typing.Awaitable]], Manager
|
|
75
|
+
]:
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
def register_manager(self, return_type: type[T] | tuple[type[T], ...]) -> typing.Callable[
|
|
79
|
+
[typing.Callable[[T | tuple[T, ...], EventT, Context], typing.Awaitable]], Manager
|
|
80
|
+
]:
|
|
81
|
+
def wrapper(func: typing.Callable[[T, EventT, Context], typing.Awaitable]) -> Manager:
|
|
82
|
+
manager = Manager(get_union_types(return_type) or (return_type,), func) # type: ignore
|
|
83
|
+
setattr(self.__class__, func.__name__, manager)
|
|
84
|
+
return manager
|
|
85
|
+
|
|
86
|
+
return wrapper
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
__all__ = (
|
|
90
|
+
"ABCReturnManager",
|
|
91
|
+
"BaseReturnManager",
|
|
92
|
+
"Manager",
|
|
93
|
+
"register_manager",
|
|
94
|
+
"get_union_types",
|
|
95
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
2
|
+
from telegrinder.bot.dispatch.context import Context
|
|
3
|
+
|
|
4
|
+
from .abc import BaseReturnManager, register_manager
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CallbackQueryReturnManager(BaseReturnManager[CallbackQueryCute]):
|
|
8
|
+
@register_manager(str)
|
|
9
|
+
@staticmethod
|
|
10
|
+
async def str_manager(value: str, event: CallbackQueryCute, ctx: Context) -> None:
|
|
11
|
+
await event.answer(value)
|
|
12
|
+
|
|
13
|
+
@register_manager(dict)
|
|
14
|
+
@staticmethod
|
|
15
|
+
async def dict_manager(value: dict, event: CallbackQueryCute, ctx: Context) -> None:
|
|
16
|
+
await event.answer(**value)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = ("CallbackQueryReturnManager",)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types import InlineQueryCute
|
|
2
|
+
from telegrinder.bot.dispatch.context import Context
|
|
3
|
+
|
|
4
|
+
from .abc import BaseReturnManager, register_manager
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InlineQueryReturnManager(BaseReturnManager[InlineQueryCute]):
|
|
8
|
+
@register_manager(dict)
|
|
9
|
+
@staticmethod
|
|
10
|
+
async def dict_manager(value: dict, event: InlineQueryCute, ctx: Context) -> None:
|
|
11
|
+
await event.answer(**value)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ("InlineQueryReturnManager",)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types import MessageCute
|
|
2
|
+
from telegrinder.bot.dispatch.context import Context
|
|
3
|
+
|
|
4
|
+
from .abc import BaseReturnManager, register_manager
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MessageReturnManager(BaseReturnManager[MessageCute]):
|
|
8
|
+
@register_manager(str)
|
|
9
|
+
@staticmethod
|
|
10
|
+
async def str_manager(value: str, event: MessageCute, ctx: Context) -> None:
|
|
11
|
+
await event.answer(value)
|
|
12
|
+
|
|
13
|
+
@register_manager(list | tuple)
|
|
14
|
+
@staticmethod
|
|
15
|
+
async def seq_manager(value: list[str] | tuple[str, ...], event: MessageCute, ctx: Context) -> None:
|
|
16
|
+
for message in value:
|
|
17
|
+
await event.answer(message)
|
|
18
|
+
|
|
19
|
+
@register_manager(dict)
|
|
20
|
+
@staticmethod
|
|
21
|
+
async def dict_manager(value: dict, event: MessageCute, ctx: Context) -> None:
|
|
22
|
+
await event.answer(**value)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ("MessageReturnManager",)
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
from .abc import ABCView
|
|
2
|
-
from .
|
|
1
|
+
from .abc import ABCStateView, ABCView, BaseStateView, BaseView
|
|
2
|
+
from .box import ViewBox
|
|
3
3
|
from .callback_query import CallbackQueryView
|
|
4
4
|
from .inline_query import InlineQueryView
|
|
5
|
+
from .message import MessageView
|
|
6
|
+
|
|
7
|
+
__all__ = (
|
|
8
|
+
"ABCView",
|
|
9
|
+
"ABCStateView",
|
|
10
|
+
"BaseView",
|
|
11
|
+
"BaseStateView",
|
|
12
|
+
"CallbackQueryView",
|
|
13
|
+
"InlineQueryView",
|
|
14
|
+
"MessageView",
|
|
15
|
+
"ViewBox",
|
|
16
|
+
)
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
+
import typing
|
|
1
2
|
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
from fntypes.co import Nothing, Some
|
|
5
|
+
|
|
2
6
|
from telegrinder.api.abc import ABCAPI
|
|
3
|
-
from telegrinder.
|
|
7
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
8
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
9
|
+
from telegrinder.bot.dispatch.handler.func import ErrorHandlerT, FuncHandler
|
|
10
|
+
from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
|
|
11
|
+
from telegrinder.bot.dispatch.process import process_inner
|
|
12
|
+
from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
|
|
13
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
14
|
+
from telegrinder.model import Model
|
|
15
|
+
from telegrinder.msgspec_utils import Option
|
|
16
|
+
from telegrinder.types.objects import Update
|
|
17
|
+
|
|
18
|
+
EventType = typing.TypeVar("EventType", bound=BaseCute)
|
|
19
|
+
MiddlewareT = typing.TypeVar("MiddlewareT", bound=ABCMiddleware)
|
|
4
20
|
|
|
5
21
|
|
|
6
22
|
class ABCView(ABC):
|
|
@@ -13,5 +29,115 @@ class ABCView(ABC):
|
|
|
13
29
|
pass
|
|
14
30
|
|
|
15
31
|
@abstractmethod
|
|
16
|
-
|
|
32
|
+
def load(self, external: typing.Self) -> None:
|
|
17
33
|
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ABCStateView(ABCView, typing.Generic[EventType]):
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def get_state_key(self, event: EventType) -> int | None:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
def __repr__(self) -> str:
|
|
42
|
+
return "<{!r}: {}>".format(
|
|
43
|
+
self.__class__.__name__,
|
|
44
|
+
", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class BaseView(ABCView, typing.Generic[EventType]):
|
|
49
|
+
auto_rules: list[ABCRule[EventType]]
|
|
50
|
+
handlers: list[ABCHandler[EventType]]
|
|
51
|
+
middlewares: list[ABCMiddleware[EventType]]
|
|
52
|
+
return_manager: ABCReturnManager[EventType]
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def get_event_type(cls) -> Option[type[EventType]]:
|
|
56
|
+
for base in cls.__dict__.get("__orig_bases__", ()):
|
|
57
|
+
if issubclass(typing.get_origin(base) or base, ABCView):
|
|
58
|
+
for generic_type in typing.get_args(base):
|
|
59
|
+
if issubclass(typing.get_origin(generic_type) or generic_type, BaseCute):
|
|
60
|
+
return Some(generic_type)
|
|
61
|
+
return Nothing()
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def get_raw_event(cls, update: Update) -> Option[Model]:
|
|
65
|
+
match update.update_type:
|
|
66
|
+
case Some(update_type):
|
|
67
|
+
return getattr(update, update_type.value)
|
|
68
|
+
case _:
|
|
69
|
+
return Nothing()
|
|
70
|
+
|
|
71
|
+
def __call__(
|
|
72
|
+
self,
|
|
73
|
+
*rules: ABCRule[EventType],
|
|
74
|
+
is_blocking: bool = True,
|
|
75
|
+
error_handler: ErrorHandlerT | None = None,
|
|
76
|
+
):
|
|
77
|
+
def wrapper(
|
|
78
|
+
func: typing.Callable[
|
|
79
|
+
typing.Concatenate[EventType, ...],
|
|
80
|
+
typing.Coroutine,
|
|
81
|
+
]
|
|
82
|
+
):
|
|
83
|
+
func_handler = FuncHandler(
|
|
84
|
+
func,
|
|
85
|
+
[*self.auto_rules, *rules],
|
|
86
|
+
is_blocking,
|
|
87
|
+
dataclass=None,
|
|
88
|
+
error_handler=error_handler,
|
|
89
|
+
)
|
|
90
|
+
self.handlers.append(func_handler)
|
|
91
|
+
return func_handler
|
|
92
|
+
|
|
93
|
+
return wrapper
|
|
94
|
+
|
|
95
|
+
def register_middleware(self, *args: typing.Any, **kwargs: typing.Any):
|
|
96
|
+
def wrapper(cls: type[MiddlewareT]):
|
|
97
|
+
self.middlewares.append(cls(*args, **kwargs))
|
|
98
|
+
return cls
|
|
99
|
+
|
|
100
|
+
return wrapper
|
|
101
|
+
|
|
102
|
+
async def check(self, event: Update) -> bool:
|
|
103
|
+
match self.get_raw_event(event):
|
|
104
|
+
case Some(e) if issubclass(
|
|
105
|
+
self.get_event_type().expect(
|
|
106
|
+
"{!r} has no event type in generic.".format(self.__class__.__name__),
|
|
107
|
+
),
|
|
108
|
+
e.__class__,
|
|
109
|
+
):
|
|
110
|
+
return True
|
|
111
|
+
case _:
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
async def process(self, event: Update, api: ABCAPI) -> bool:
|
|
115
|
+
return await process_inner(
|
|
116
|
+
self.get_event_type().unwrap().from_update(
|
|
117
|
+
update=self.get_raw_event(event).unwrap(),
|
|
118
|
+
bound_api=api,
|
|
119
|
+
),
|
|
120
|
+
event,
|
|
121
|
+
self.middlewares,
|
|
122
|
+
self.handlers,
|
|
123
|
+
self.return_manager,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def load(self, external: typing.Self) -> None:
|
|
127
|
+
self.auto_rules.extend(external.auto_rules)
|
|
128
|
+
self.handlers.extend(external.handlers)
|
|
129
|
+
self.middlewares.extend(external.middlewares)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class BaseStateView(ABCStateView[EventType], BaseView[EventType], ABC, typing.Generic[EventType]):
|
|
133
|
+
@abstractmethod
|
|
134
|
+
def get_state_key(self, event: EventType) -> int | None:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
__all__ = (
|
|
139
|
+
"ABCView",
|
|
140
|
+
"ABCStateView",
|
|
141
|
+
"BaseView",
|
|
142
|
+
"BaseStateView",
|
|
143
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
|
|
3
|
+
import typing_extensions as typing
|
|
4
|
+
|
|
5
|
+
from .abc import ABCView
|
|
6
|
+
from .callback_query import CallbackQueryView
|
|
7
|
+
from .inline_query import InlineQueryView
|
|
8
|
+
from .message import MessageView
|
|
9
|
+
|
|
10
|
+
CallbackQueryViewT = typing.TypeVar(
|
|
11
|
+
"CallbackQueryViewT", bound=ABCView, default=CallbackQueryView
|
|
12
|
+
)
|
|
13
|
+
InlineQueryViewT = typing.TypeVar(
|
|
14
|
+
"InlineQueryViewT", bound=ABCView, default=InlineQueryView
|
|
15
|
+
)
|
|
16
|
+
MessageViewT = typing.TypeVar("MessageViewT", bound=ABCView, default=MessageView)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclasses.dataclass(kw_only=True)
|
|
20
|
+
class ViewBox(typing.Generic[CallbackQueryViewT, InlineQueryViewT, MessageViewT]):
|
|
21
|
+
callback_query: CallbackQueryViewT = dataclasses.field( # type: ignore
|
|
22
|
+
default_factory=lambda: CallbackQueryView(),
|
|
23
|
+
)
|
|
24
|
+
inline_query: InlineQueryViewT = dataclasses.field( # type: ignore
|
|
25
|
+
default_factory=lambda: InlineQueryView(),
|
|
26
|
+
)
|
|
27
|
+
message: MessageViewT = dataclasses.field( # type: ignore
|
|
28
|
+
default_factory=lambda: MessageView(),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def get_views(self) -> dict[str, ABCView]:
|
|
32
|
+
return {
|
|
33
|
+
name: view for name, view in self.__dict__.items()
|
|
34
|
+
if isinstance(view, ABCView)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ("ViewBox",)
|
|
@@ -1,46 +1,20 @@
|
|
|
1
|
-
from .
|
|
2
|
-
from telegrinder.bot.dispatch.handler import ABCHandler, FuncHandler
|
|
3
|
-
from telegrinder.bot.dispatch.waiter import Waiter
|
|
4
|
-
from telegrinder.bot.dispatch.middleware import ABCMiddleware
|
|
5
|
-
from telegrinder.bot.rules import ABCRule
|
|
6
|
-
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
7
|
-
from telegrinder.api.abc import ABCAPI
|
|
8
|
-
from telegrinder.bot.dispatch.waiter import WithWaiter
|
|
9
|
-
from telegrinder.bot.dispatch.process import process_waiters, process_inner
|
|
10
|
-
from telegrinder.types import Update
|
|
11
|
-
import typing
|
|
12
|
-
|
|
1
|
+
from fntypes.option import Some
|
|
13
2
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
self.auto_rules: list[ABCRule] = []
|
|
17
|
-
self.handlers: typing.List[ABCHandler[CallbackQueryCute]] = []
|
|
18
|
-
self.middlewares: typing.List[ABCMiddleware[CallbackQueryCute]] = []
|
|
19
|
-
self.short_waiters: typing.Dict[int, Waiter] = {}
|
|
20
|
-
|
|
21
|
-
def __call__(self, *rules: ABCRule, is_blocking: bool = True):
|
|
22
|
-
def wrapper(func: typing.Callable[..., typing.Coroutine]):
|
|
23
|
-
self.handlers.append(
|
|
24
|
-
FuncHandler(func, [*self.auto_rules, *rules], is_blocking, dataclass=None)
|
|
25
|
-
)
|
|
26
|
-
return func
|
|
3
|
+
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
4
|
+
from telegrinder.bot.dispatch.return_manager import CallbackQueryReturnManager
|
|
27
5
|
|
|
28
|
-
|
|
6
|
+
from .abc import BaseStateView
|
|
29
7
|
|
|
30
|
-
async def check(self, event: Update) -> bool:
|
|
31
|
-
return bool(event.callback_query)
|
|
32
8
|
|
|
33
|
-
|
|
34
|
-
|
|
9
|
+
class CallbackQueryView(BaseStateView[CallbackQueryCute]):
|
|
10
|
+
def __init__(self) -> None:
|
|
11
|
+
self.auto_rules = []
|
|
12
|
+
self.handlers = []
|
|
13
|
+
self.middlewares = []
|
|
14
|
+
self.return_manager = CallbackQueryReturnManager()
|
|
35
15
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
):
|
|
39
|
-
return
|
|
16
|
+
def get_state_key(self, event: CallbackQueryCute) -> int | None:
|
|
17
|
+
return event.message.map(lambda variative: variative.v.message_id).unwrap_or_none()
|
|
40
18
|
|
|
41
|
-
return await process_inner(query, event, self.middlewares, self.handlers)
|
|
42
19
|
|
|
43
|
-
|
|
44
|
-
self.handlers.extend(external.handlers)
|
|
45
|
-
self.middlewares.extend(external.middlewares)
|
|
46
|
-
external.short_waiters = self.short_waiters
|
|
20
|
+
__all__ = ("CallbackQueryView",)
|
|
@@ -1,46 +1,18 @@
|
|
|
1
|
-
from .abc import ABCView
|
|
2
|
-
from telegrinder.bot.dispatch.handler import ABCHandler, FuncHandler
|
|
3
|
-
from telegrinder.bot.dispatch.waiter import Waiter
|
|
4
|
-
from telegrinder.bot.dispatch.middleware import ABCMiddleware
|
|
5
|
-
from telegrinder.bot.rules import ABCRule
|
|
6
1
|
from telegrinder.bot.cute_types import InlineQueryCute
|
|
7
|
-
from telegrinder.
|
|
8
|
-
from telegrinder.bot.dispatch.waiter import WithWaiter
|
|
9
|
-
from telegrinder.bot.dispatch.process import process_waiters, process_inner
|
|
10
|
-
from telegrinder.types import Update
|
|
11
|
-
import typing
|
|
2
|
+
from telegrinder.bot.dispatch.return_manager import InlineQueryReturnManager
|
|
12
3
|
|
|
4
|
+
from .abc import BaseStateView
|
|
13
5
|
|
|
14
|
-
class InlineQueryView(ABCView, WithWaiter[str, InlineQueryCute]):
|
|
15
|
-
def __init__(self):
|
|
16
|
-
self.auto_rules: list[ABCRule] = []
|
|
17
|
-
self.handlers: typing.List[ABCHandler[InlineQueryCute]] = []
|
|
18
|
-
self.middlewares: typing.List[ABCMiddleware[InlineQueryCute]] = []
|
|
19
|
-
self.short_waiters: typing.Dict[str, Waiter] = {}
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
7
|
+
class InlineQueryView(BaseStateView[InlineQueryCute]):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
self.auto_rules = []
|
|
10
|
+
self.handlers = []
|
|
11
|
+
self.middlewares = []
|
|
12
|
+
self.return_manager = InlineQueryReturnManager()
|
|
27
13
|
|
|
28
|
-
|
|
14
|
+
def get_state_key(self, event: InlineQueryCute) -> int | None:
|
|
15
|
+
return event.from_.id
|
|
29
16
|
|
|
30
|
-
def load(self, external: "InlineQueryView"):
|
|
31
|
-
self.handlers.extend(external.handlers)
|
|
32
|
-
self.middlewares.extend(external.middlewares)
|
|
33
|
-
external.short_waiters = self.short_waiters
|
|
34
17
|
|
|
35
|
-
|
|
36
|
-
return bool(event.inline_query)
|
|
37
|
-
|
|
38
|
-
async def process(self, event: Update, api: ABCAPI):
|
|
39
|
-
query = InlineQueryCute(**event.inline_query.to_dict(), api=api)
|
|
40
|
-
|
|
41
|
-
if await process_waiters(
|
|
42
|
-
self.short_waiters, query.id, query, event, query.answer
|
|
43
|
-
):
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
return await process_inner(query, event, self.middlewares, self.handlers)
|
|
18
|
+
__all__ = ("InlineQueryView",)
|