telegrinder 0.1.dev164__py3-none-any.whl → 0.1.dev166__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 +58 -0
- telegrinder/api/abc.py +1 -1
- telegrinder/api/api.py +8 -6
- telegrinder/api/error.py +2 -3
- telegrinder/bot/__init__.py +14 -0
- telegrinder/bot/bot.py +13 -2
- telegrinder/bot/cute_types/__init__.py +4 -0
- telegrinder/bot/cute_types/base.py +22 -13
- telegrinder/bot/cute_types/chat_join_request.py +63 -0
- telegrinder/bot/cute_types/chat_member_updated.py +244 -0
- telegrinder/bot/cute_types/message.py +33 -6
- telegrinder/bot/cute_types/update.py +5 -4
- telegrinder/bot/cute_types/utils.py +39 -17
- telegrinder/bot/dispatch/__init__.py +9 -1
- telegrinder/bot/dispatch/composition.py +10 -8
- telegrinder/bot/dispatch/context.py +9 -10
- telegrinder/bot/dispatch/dispatch.py +29 -19
- telegrinder/bot/dispatch/handler/abc.py +1 -0
- telegrinder/bot/dispatch/handler/func.py +29 -6
- telegrinder/bot/dispatch/handler/message_reply.py +2 -3
- telegrinder/bot/dispatch/middleware/abc.py +2 -4
- telegrinder/bot/dispatch/process.py +4 -3
- telegrinder/bot/dispatch/return_manager/__init__.py +1 -1
- telegrinder/bot/dispatch/return_manager/abc.py +39 -21
- telegrinder/bot/dispatch/return_manager/callback_query.py +4 -2
- telegrinder/bot/dispatch/return_manager/inline_query.py +4 -2
- telegrinder/bot/dispatch/return_manager/message.py +12 -6
- telegrinder/bot/dispatch/view/__init__.py +8 -2
- telegrinder/bot/dispatch/view/abc.py +26 -20
- telegrinder/bot/dispatch/view/box.py +72 -1
- telegrinder/bot/dispatch/view/callback_query.py +1 -3
- telegrinder/bot/dispatch/view/chat_join_request.py +17 -0
- telegrinder/bot/dispatch/view/chat_member.py +26 -0
- telegrinder/bot/dispatch/view/message.py +23 -1
- telegrinder/bot/dispatch/view/raw.py +116 -0
- telegrinder/bot/dispatch/waiter_machine/__init__.py +2 -1
- telegrinder/bot/dispatch/waiter_machine/machine.py +73 -19
- telegrinder/bot/dispatch/waiter_machine/middleware.py +3 -3
- telegrinder/bot/dispatch/waiter_machine/short_state.py +6 -3
- telegrinder/bot/polling/polling.py +17 -1
- telegrinder/bot/rules/__init__.py +20 -12
- telegrinder/bot/rules/abc.py +0 -9
- telegrinder/bot/rules/adapter/event.py +31 -22
- telegrinder/bot/rules/callback_data.py +15 -20
- telegrinder/bot/rules/chat_join.py +47 -0
- telegrinder/bot/rules/enum_text.py +7 -2
- telegrinder/bot/rules/inline.py +3 -3
- telegrinder/bot/rules/is_from.py +36 -50
- telegrinder/bot/rules/markup.py +1 -1
- telegrinder/bot/rules/message.py +17 -0
- telegrinder/bot/rules/message_entities.py +1 -1
- telegrinder/bot/rules/start.py +6 -4
- telegrinder/bot/rules/text.py +2 -1
- telegrinder/bot/rules/update.py +16 -0
- telegrinder/bot/scenario/checkbox.py +9 -7
- telegrinder/client/aiohttp.py +4 -4
- telegrinder/model.py +43 -19
- telegrinder/modules.py +16 -32
- telegrinder/msgspec_utils.py +48 -36
- telegrinder/node/__init__.py +12 -12
- telegrinder/node/attachment.py +15 -5
- telegrinder/node/base.py +24 -16
- telegrinder/node/composer.py +8 -6
- telegrinder/node/container.py +1 -1
- telegrinder/node/rule.py +4 -4
- telegrinder/node/source.py +4 -2
- telegrinder/node/tools/generator.py +1 -1
- telegrinder/tools/__init__.py +2 -1
- telegrinder/tools/error_handler/abc.py +4 -3
- telegrinder/tools/error_handler/error_handler.py +22 -16
- telegrinder/tools/formatting/html.py +20 -18
- telegrinder/tools/formatting/links.py +12 -6
- telegrinder/tools/formatting/spec_html_formats.py +5 -6
- telegrinder/tools/global_context/abc.py +5 -1
- telegrinder/tools/global_context/global_context.py +2 -2
- telegrinder/tools/global_context/telegrinder_ctx.py +1 -1
- telegrinder/tools/i18n/base.py +4 -3
- telegrinder/tools/i18n/simple.py +1 -3
- telegrinder/tools/keyboard.py +1 -1
- telegrinder/tools/loop_wrapper/__init__.py +2 -2
- telegrinder/tools/loop_wrapper/abc.py +1 -4
- telegrinder/tools/loop_wrapper/loop_wrapper.py +90 -36
- telegrinder/tools/magic.py +1 -1
- telegrinder/types/__init__.py +206 -0
- telegrinder/types/enums.py +34 -0
- telegrinder/types/methods.py +52 -47
- telegrinder/types/objects.py +531 -88
- telegrinder/verification_utils.py +33 -0
- {telegrinder-0.1.dev164.dist-info → telegrinder-0.1.dev166.dist-info}/METADATA +1 -1
- telegrinder-0.1.dev166.dist-info/RECORD +136 -0
- telegrinder-0.1.dev164.dist-info/RECORD +0 -127
- {telegrinder-0.1.dev164.dist-info → telegrinder-0.1.dev166.dist-info}/LICENSE +0 -0
- {telegrinder-0.1.dev164.dist-info → telegrinder-0.1.dev166.dist-info}/WHEEL +0 -0
|
@@ -49,7 +49,9 @@ class StringFormatter(string.Formatter):
|
|
|
49
49
|
)
|
|
50
50
|
return fmt
|
|
51
51
|
|
|
52
|
-
def get_spec_formatter(
|
|
52
|
+
def get_spec_formatter(
|
|
53
|
+
self, value: SpecialFormat
|
|
54
|
+
) -> typing.Callable[..., "TagFormat"]:
|
|
53
55
|
return globals()[value.__formatter_name__]
|
|
54
56
|
|
|
55
57
|
def check_formats(self, value: typing.Any, fmts: list[str]) -> "TagFormat":
|
|
@@ -78,11 +80,15 @@ class StringFormatter(string.Formatter):
|
|
|
78
80
|
with suppress(ValueError):
|
|
79
81
|
return HTMLFormatter(
|
|
80
82
|
format(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
(
|
|
84
|
+
value.formatting()
|
|
85
|
+
if isinstance(value, TagFormat)
|
|
86
|
+
else (
|
|
87
|
+
self.get_spec_formatter(value)(**value.__dict__).formatting()
|
|
88
|
+
if is_spec_format(value)
|
|
89
|
+
else value
|
|
90
|
+
)
|
|
91
|
+
),
|
|
86
92
|
fmt,
|
|
87
93
|
)
|
|
88
94
|
)
|
|
@@ -200,11 +206,8 @@ def bold(string: str) -> TagFormat:
|
|
|
200
206
|
return TagFormat(string, tag="b")
|
|
201
207
|
|
|
202
208
|
|
|
203
|
-
def channel_boost_link(
|
|
204
|
-
return link(
|
|
205
|
-
get_channel_boost_link(channel_username),
|
|
206
|
-
string or f"t.me/{channel_username}?boost",
|
|
207
|
-
)
|
|
209
|
+
def channel_boost_link(channel_id: str | int, string: str | None = None):
|
|
210
|
+
return link(get_channel_boost_link(channel_id), string)
|
|
208
211
|
|
|
209
212
|
|
|
210
213
|
def code_inline(string: str) -> TagFormat:
|
|
@@ -234,15 +237,14 @@ def spoiler(string: str) -> TagFormat:
|
|
|
234
237
|
return TagFormat(string, tag="tg-spoiler")
|
|
235
238
|
|
|
236
239
|
|
|
237
|
-
def start_bot_link(
|
|
238
|
-
return link(
|
|
239
|
-
get_start_bot_link(bot_username, data),
|
|
240
|
-
string or f"t.me/{bot_username}?start={data}"
|
|
241
|
-
)
|
|
240
|
+
def start_bot_link(bot_id: str | int, data: str, string: str | None = None) -> TagFormat:
|
|
241
|
+
return link(get_start_bot_link(bot_id, data), string)
|
|
242
242
|
|
|
243
243
|
|
|
244
|
-
def start_group_link(
|
|
245
|
-
|
|
244
|
+
def start_group_link(
|
|
245
|
+
bot_id: str | int, data: str, string: str | None = None
|
|
246
|
+
) -> TagFormat:
|
|
247
|
+
return link(get_start_group_link(bot_id, data), string)
|
|
246
248
|
|
|
247
249
|
|
|
248
250
|
def strike(string: str) -> TagFormat:
|
|
@@ -6,16 +6,22 @@ def get_resolve_domain_link(username: str) -> str:
|
|
|
6
6
|
return f"tg://resolve?domain={username}"
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def get_start_bot_link(
|
|
10
|
-
|
|
9
|
+
def get_start_bot_link(bot_id: str | int, data: str) -> str:
|
|
10
|
+
if isinstance(bot_id, int):
|
|
11
|
+
return get_mention_link(bot_id) + f"&start={data}"
|
|
12
|
+
return get_resolve_domain_link(bot_id) + f"&start={data}"
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
def get_start_group_link(
|
|
14
|
-
|
|
15
|
+
def get_start_group_link(bot_id: str | int, data: str) -> str:
|
|
16
|
+
if isinstance(bot_id, int):
|
|
17
|
+
return get_mention_link(bot_id) + f"&startgroup={data}"
|
|
18
|
+
return get_resolve_domain_link(bot_id) + f"&startgroup={data}"
|
|
15
19
|
|
|
16
20
|
|
|
17
|
-
def get_channel_boost_link(
|
|
18
|
-
|
|
21
|
+
def get_channel_boost_link(channel_id: str | int) -> str:
|
|
22
|
+
if isinstance(channel_id, int):
|
|
23
|
+
return get_mention_link(channel_id) + "&boost"
|
|
24
|
+
return get_resolve_domain_link(channel_id) + "&boost"
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
def get_invite_chat_link(invite_link: str) -> str:
|
|
@@ -3,14 +3,13 @@ import typing
|
|
|
3
3
|
|
|
4
4
|
from telegrinder.types.enums import ProgrammingLanguage
|
|
5
5
|
|
|
6
|
-
SpecialFormat = typing.Union[
|
|
6
|
+
SpecialFormat: typing.TypeAlias = typing.Union[
|
|
7
7
|
"ChannelBoostLink",
|
|
8
8
|
"InviteChatLink",
|
|
9
9
|
"Link",
|
|
10
10
|
"Mention",
|
|
11
11
|
"PreCode",
|
|
12
12
|
"ResolveDomain",
|
|
13
|
-
"SpecialFormat",
|
|
14
13
|
"StartBotLink",
|
|
15
14
|
"StartGroupLink",
|
|
16
15
|
"TgEmoji",
|
|
@@ -38,7 +37,7 @@ class BaseSpecFormat:
|
|
|
38
37
|
class ChannelBoostLink(BaseSpecFormat):
|
|
39
38
|
__formatter_name__ = "channel_boost_link"
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
channel_id: str | int
|
|
42
41
|
string: str | None = None
|
|
43
42
|
|
|
44
43
|
|
|
@@ -77,7 +76,7 @@ class PreCode(BaseSpecFormat):
|
|
|
77
76
|
@dataclasses.dataclass(repr=False)
|
|
78
77
|
class TgEmoji(BaseSpecFormat):
|
|
79
78
|
__formatter_name__ = "tg_emoji"
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
string: str
|
|
82
81
|
emoji_id: int
|
|
83
82
|
|
|
@@ -86,7 +85,7 @@ class TgEmoji(BaseSpecFormat):
|
|
|
86
85
|
class StartBotLink(BaseSpecFormat):
|
|
87
86
|
__formatter_name__ = "start_bot_link"
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
bot_id: str | int
|
|
90
89
|
data: str
|
|
91
90
|
string: str | None
|
|
92
91
|
|
|
@@ -95,7 +94,7 @@ class StartBotLink(BaseSpecFormat):
|
|
|
95
94
|
class StartGroupLink(BaseSpecFormat):
|
|
96
95
|
__formatter_name__ = "start_group_link"
|
|
97
96
|
|
|
98
|
-
|
|
97
|
+
bot_id: str | int
|
|
99
98
|
data: str
|
|
100
99
|
string: str | None = None
|
|
101
100
|
|
|
@@ -35,7 +35,11 @@ class GlobalCtxVar(typing.Generic[T]):
|
|
|
35
35
|
|
|
36
36
|
@classmethod
|
|
37
37
|
def collect(cls, name: str, ctx_value: T | CtxVariable[T]) -> typing.Self:
|
|
38
|
-
ctx_value =
|
|
38
|
+
ctx_value = (
|
|
39
|
+
CtxVar(ctx_value)
|
|
40
|
+
if not isinstance(ctx_value, CtxVar | GlobalCtxVar)
|
|
41
|
+
else ctx_value
|
|
42
|
+
)
|
|
39
43
|
params = ctx_value.__dict__
|
|
40
44
|
params["name"] = name
|
|
41
45
|
return cls(**params)
|
|
@@ -199,8 +199,8 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
199
199
|
self.set_context_variables(variables)
|
|
200
200
|
|
|
201
201
|
def __repr__(self) -> str:
|
|
202
|
-
return "<{
|
|
203
|
-
f"{self.__class__.__name__}@{self.ctx_name}",
|
|
202
|
+
return "<{} -> ({})>".format(
|
|
203
|
+
f"{self.__class__.__name__}@{self.ctx_name!r}",
|
|
204
204
|
", ".join(repr(var) for var in self),
|
|
205
205
|
)
|
|
206
206
|
|
|
@@ -7,7 +7,7 @@ from telegrinder.tools.global_context import GlobalContext, ctx_var
|
|
|
7
7
|
|
|
8
8
|
class TelegrinderCtx(GlobalContext):
|
|
9
9
|
"""Basic type-hinted telegrinder context with context name `"telegrinder"`.
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
You can use this class or GlobalContext:
|
|
12
12
|
```
|
|
13
13
|
from telegrinder.tools.global_context import GlobalContext, TelegrinderCtx
|
telegrinder/tools/i18n/base.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import enum
|
|
2
|
+
import typing
|
|
2
3
|
from abc import ABC, abstractmethod
|
|
3
4
|
|
|
4
5
|
|
|
@@ -9,14 +10,14 @@ class ABCI18n(ABC):
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class ABCTranslator(ABC):
|
|
12
|
-
def __init__(self, locale: str, **kwargs):
|
|
13
|
+
def __init__(self, locale: str, **kwargs: typing.Any) -> None:
|
|
13
14
|
self.locale = locale
|
|
14
15
|
|
|
15
16
|
@abstractmethod
|
|
16
|
-
def get(self, __key: str, *args, **kwargs) -> str:
|
|
17
|
+
def get(self, __key: str, *args: typing.Any, **kwargs: typing.Any) -> str:
|
|
17
18
|
"""This translates a key to actual human-readable string"""
|
|
18
19
|
|
|
19
|
-
def __call__(self, __key: str, *args, **kwargs):
|
|
20
|
+
def __call__(self, __key: str, *args: typing.Any, **kwargs: typing.Any) -> str:
|
|
20
21
|
return self.get(__key, *args, **kwargs)
|
|
21
22
|
|
|
22
23
|
|
telegrinder/tools/i18n/simple.py
CHANGED
|
@@ -20,9 +20,7 @@ class SimpleI18n(ABCI18n):
|
|
|
20
20
|
if not os.path.isdir(os.path.join(self.folder, name)):
|
|
21
21
|
continue
|
|
22
22
|
|
|
23
|
-
mo_path = os.path.join(
|
|
24
|
-
self.folder, name, "LC_MESSAGES", f"{self.domain}.mo"
|
|
25
|
-
)
|
|
23
|
+
mo_path = os.path.join(self.folder, name, "LC_MESSAGES", f"{self.domain}.mo")
|
|
26
24
|
if os.path.exists(mo_path):
|
|
27
25
|
with open(mo_path, "rb") as f:
|
|
28
26
|
result[name] = gettext.GNUTranslations(f)
|
telegrinder/tools/keyboard.py
CHANGED
|
@@ -46,7 +46,7 @@ class ABCMarkup(ABC, typing.Generic[ButtonT]):
|
|
|
46
46
|
def add(self, row_or_button: RowButtons[ButtonT] | ButtonT) -> typing.Self:
|
|
47
47
|
if not len(self.keyboard):
|
|
48
48
|
self.row()
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
if isinstance(row_or_button, RowButtons):
|
|
51
51
|
self.keyboard[-1].extend(row_or_button.get_data())
|
|
52
52
|
if row_or_button.auto_row:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
from .abc import ABCLoopWrapper
|
|
2
|
-
from .loop_wrapper import DelayedTask, LoopWrapper
|
|
2
|
+
from .loop_wrapper import DelayedTask, Lifespan, LoopWrapper
|
|
3
3
|
|
|
4
|
-
__all__ = ("ABCLoopWrapper", "DelayedTask", "LoopWrapper")
|
|
4
|
+
__all__ = ("ABCLoopWrapper", "DelayedTask", "Lifespan", "LoopWrapper")
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
|
|
4
|
-
CoroutineTask: typing.TypeAlias = typing.Coroutine[typing.Any, typing.Any, typing.Any]
|
|
5
|
-
CoroutineFunc: typing.TypeAlias = typing.Callable[..., CoroutineTask]
|
|
6
|
-
|
|
7
4
|
|
|
8
5
|
class ABCLoopWrapper(ABC):
|
|
9
6
|
@abstractmethod
|
|
10
|
-
def add_task(self, task:
|
|
7
|
+
def add_task(self, task: typing.Any) -> None:
|
|
11
8
|
pass
|
|
12
9
|
|
|
13
10
|
@abstractmethod
|
|
@@ -5,12 +5,36 @@ import typing
|
|
|
5
5
|
|
|
6
6
|
from telegrinder.modules import logger
|
|
7
7
|
|
|
8
|
-
from .abc import ABCLoopWrapper
|
|
8
|
+
from .abc import ABCLoopWrapper
|
|
9
|
+
|
|
10
|
+
T = typing.TypeVar("T")
|
|
11
|
+
P = typing.ParamSpec("P")
|
|
12
|
+
CoroFunc = typing.TypeVar("CoroFunc", bound="CoroutineFunc")
|
|
13
|
+
|
|
14
|
+
CoroutineTask: typing.TypeAlias = typing.Coroutine[typing.Any, typing.Any, T]
|
|
15
|
+
CoroutineFunc: typing.TypeAlias = typing.Callable[P, CoroutineTask[T]]
|
|
16
|
+
Task: typing.TypeAlias = typing.Union[CoroutineFunc, CoroutineTask, "DelayedTask"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run_tasks(
|
|
20
|
+
tasks: list[CoroutineTask[typing.Any]],
|
|
21
|
+
loop: asyncio.AbstractEventLoop,
|
|
22
|
+
) -> None:
|
|
23
|
+
while tasks:
|
|
24
|
+
loop.run_until_complete(tasks.pop(0))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def to_coroutine_task(task: Task) -> CoroutineTask[typing.Any]:
|
|
28
|
+
if asyncio.iscoroutinefunction(task) or isinstance(task, DelayedTask):
|
|
29
|
+
task = task()
|
|
30
|
+
elif not asyncio.iscoroutine(task):
|
|
31
|
+
raise TypeError("Task should be coroutine or coroutine function.")
|
|
32
|
+
return task
|
|
9
33
|
|
|
10
34
|
|
|
11
35
|
@dataclasses.dataclass
|
|
12
|
-
class DelayedTask:
|
|
13
|
-
handler:
|
|
36
|
+
class DelayedTask(typing.Generic[CoroFunc]):
|
|
37
|
+
handler: CoroFunc
|
|
14
38
|
seconds: float
|
|
15
39
|
repeat: bool = dataclasses.field(default=False, kw_only=True)
|
|
16
40
|
_cancelled: bool = dataclasses.field(default=False, init=False, repr=False)
|
|
@@ -33,28 +57,64 @@ class DelayedTask:
|
|
|
33
57
|
self._cancelled = True
|
|
34
58
|
|
|
35
59
|
|
|
60
|
+
@dataclasses.dataclass(kw_only=True)
|
|
61
|
+
class Lifespan:
|
|
62
|
+
startup_tasks: list[CoroutineTask[typing.Any]] = dataclasses.field(
|
|
63
|
+
default_factory=lambda: []
|
|
64
|
+
)
|
|
65
|
+
shutdown_tasks: list[CoroutineTask[typing.Any]] = dataclasses.field(
|
|
66
|
+
default_factory=lambda: []
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def on_startup(self, task_or_func: Task) -> Task:
|
|
70
|
+
task_or_func = to_coroutine_task(task_or_func)
|
|
71
|
+
self.startup_tasks.append(task_or_func)
|
|
72
|
+
return task_or_func
|
|
73
|
+
|
|
74
|
+
def on_shutdown(self, task_or_func: Task) -> Task:
|
|
75
|
+
task_or_func = to_coroutine_task(task_or_func)
|
|
76
|
+
self.shutdown_tasks.append(task_or_func)
|
|
77
|
+
return task_or_func
|
|
78
|
+
|
|
79
|
+
def start(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
80
|
+
run_tasks(self.startup_tasks, loop)
|
|
81
|
+
|
|
82
|
+
def shutdown(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
83
|
+
run_tasks(self.shutdown_tasks, loop)
|
|
84
|
+
|
|
85
|
+
|
|
36
86
|
class LoopWrapper(ABCLoopWrapper):
|
|
37
|
-
def __init__(
|
|
38
|
-
self
|
|
39
|
-
|
|
40
|
-
|
|
87
|
+
def __init__(
|
|
88
|
+
self,
|
|
89
|
+
*,
|
|
90
|
+
tasks: list[CoroutineTask[typing.Any]] | None = None,
|
|
91
|
+
lifespan: Lifespan | None = None,
|
|
92
|
+
) -> None:
|
|
93
|
+
self.tasks: list[CoroutineTask[typing.Any]] = tasks or []
|
|
94
|
+
self.lifespan = lifespan or Lifespan()
|
|
41
95
|
self._loop = asyncio.new_event_loop()
|
|
42
|
-
|
|
96
|
+
|
|
97
|
+
def __repr__(self) -> str:
|
|
98
|
+
return "<{}: loop={!r} with tasks={!r}, lifespan={!r}>".format(
|
|
99
|
+
self.__class__.__name__,
|
|
100
|
+
self._loop,
|
|
101
|
+
self.tasks,
|
|
102
|
+
self.lifespan,
|
|
103
|
+
)
|
|
104
|
+
|
|
43
105
|
def run_event_loop(self) -> None:
|
|
44
106
|
if not self.tasks:
|
|
45
107
|
logger.warning("You run loop with 0 tasks!")
|
|
46
108
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
self._loop.create_task(task)
|
|
51
|
-
|
|
52
|
-
self.tasks.clear()
|
|
109
|
+
self.lifespan.start(self._loop)
|
|
110
|
+
while self.tasks:
|
|
111
|
+
self._loop.create_task(self.tasks.pop(0))
|
|
53
112
|
tasks = asyncio.all_tasks(self._loop)
|
|
113
|
+
|
|
54
114
|
try:
|
|
55
115
|
while tasks:
|
|
56
116
|
tasks_results, _ = self._loop.run_until_complete(
|
|
57
|
-
asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
|
|
117
|
+
asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION),
|
|
58
118
|
)
|
|
59
119
|
for task_result in tasks_results:
|
|
60
120
|
try:
|
|
@@ -64,25 +124,21 @@ class LoopWrapper(ABCLoopWrapper):
|
|
|
64
124
|
tasks = asyncio.all_tasks(self._loop)
|
|
65
125
|
except KeyboardInterrupt:
|
|
66
126
|
print() # blank print for ^C
|
|
67
|
-
logger.info("KeyboardInterrupt")
|
|
127
|
+
logger.info("Caught KeyboardInterrupt, cancellation...")
|
|
68
128
|
self.complete_tasks(tasks)
|
|
69
129
|
finally:
|
|
70
|
-
|
|
71
|
-
self._loop.run_until_complete(shutdown_task)
|
|
130
|
+
self.lifespan.shutdown(self._loop)
|
|
72
131
|
if self._loop.is_running():
|
|
73
132
|
self._loop.close()
|
|
74
|
-
|
|
75
|
-
def add_task(self, task:
|
|
76
|
-
|
|
77
|
-
task = task()
|
|
78
|
-
elif not asyncio.iscoroutine(task):
|
|
79
|
-
raise TypeError("Task should be coroutine or coroutine function.")
|
|
133
|
+
|
|
134
|
+
def add_task(self, task: Task) -> None:
|
|
135
|
+
task = to_coroutine_task(task)
|
|
80
136
|
|
|
81
137
|
if self._loop and self._loop.is_running():
|
|
82
138
|
self._loop.create_task(task)
|
|
83
139
|
else:
|
|
84
140
|
self.tasks.append(task)
|
|
85
|
-
|
|
141
|
+
|
|
86
142
|
def complete_tasks(self, tasks: set[asyncio.Task[typing.Any]]) -> None:
|
|
87
143
|
tasks = tasks | asyncio.all_tasks(self._loop)
|
|
88
144
|
task_to_cancel = asyncio.gather(*tasks, return_exceptions=True)
|
|
@@ -97,15 +153,14 @@ class LoopWrapper(ABCLoopWrapper):
|
|
|
97
153
|
hours: int = 0,
|
|
98
154
|
minutes: int = 0,
|
|
99
155
|
seconds: float = 0,
|
|
100
|
-
)
|
|
156
|
+
):
|
|
101
157
|
seconds += minutes * 60
|
|
102
158
|
seconds += hours * 60 * 60
|
|
103
159
|
seconds += days * 24 * 60 * 60
|
|
104
160
|
|
|
105
|
-
def decorator(func:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return delayed_task
|
|
161
|
+
def decorator(func: CoroFunc) -> CoroFunc:
|
|
162
|
+
self.add_task(DelayedTask(func, seconds, repeat=False))
|
|
163
|
+
return func
|
|
109
164
|
|
|
110
165
|
return decorator
|
|
111
166
|
|
|
@@ -116,17 +171,16 @@ class LoopWrapper(ABCLoopWrapper):
|
|
|
116
171
|
hours: int = 0,
|
|
117
172
|
minutes: int = 0,
|
|
118
173
|
seconds: float = 0,
|
|
119
|
-
)
|
|
174
|
+
):
|
|
120
175
|
seconds += minutes * 60
|
|
121
176
|
seconds += hours * 60 * 60
|
|
122
177
|
seconds += days * 24 * 60 * 60
|
|
123
178
|
|
|
124
|
-
def decorator(func:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return delayed_task
|
|
179
|
+
def decorator(func: CoroFunc) -> CoroFunc:
|
|
180
|
+
self.add_task(DelayedTask(func, seconds, repeat=True))
|
|
181
|
+
return func
|
|
128
182
|
|
|
129
183
|
return decorator
|
|
130
184
|
|
|
131
185
|
|
|
132
|
-
__all__ = ("DelayedTask", "LoopWrapper")
|
|
186
|
+
__all__ = ("DelayedTask", "Lifespan", "LoopWrapper", "to_coroutine_task")
|
telegrinder/tools/magic.py
CHANGED
telegrinder/types/__init__.py
CHANGED
|
@@ -1,2 +1,208 @@
|
|
|
1
1
|
from telegrinder.types.enums import *
|
|
2
2
|
from telegrinder.types.objects import *
|
|
3
|
+
|
|
4
|
+
__all__ = (
|
|
5
|
+
"Animation",
|
|
6
|
+
"Audio",
|
|
7
|
+
"BackgroundFill",
|
|
8
|
+
"BackgroundFillFreeformGradient",
|
|
9
|
+
"BackgroundFillGradient",
|
|
10
|
+
"BackgroundFillSolid",
|
|
11
|
+
"BackgroundType",
|
|
12
|
+
"BackgroundTypeChatTheme",
|
|
13
|
+
"BackgroundTypeFill",
|
|
14
|
+
"BackgroundTypePattern",
|
|
15
|
+
"BackgroundTypeWallpaper",
|
|
16
|
+
"Birthdate",
|
|
17
|
+
"BotCommand",
|
|
18
|
+
"BotCommandScope",
|
|
19
|
+
"BotCommandScopeAllChatAdministrators",
|
|
20
|
+
"BotCommandScopeAllGroupChats",
|
|
21
|
+
"BotCommandScopeAllPrivateChats",
|
|
22
|
+
"BotCommandScopeChat",
|
|
23
|
+
"BotCommandScopeChatAdministrators",
|
|
24
|
+
"BotCommandScopeChatMember",
|
|
25
|
+
"BotCommandScopeDefault",
|
|
26
|
+
"BotDescription",
|
|
27
|
+
"BotName",
|
|
28
|
+
"BotShortDescription",
|
|
29
|
+
"BusinessConnection",
|
|
30
|
+
"BusinessIntro",
|
|
31
|
+
"BusinessLocation",
|
|
32
|
+
"BusinessMessagesDeleted",
|
|
33
|
+
"BusinessOpeningHours",
|
|
34
|
+
"BusinessOpeningHoursInterval",
|
|
35
|
+
"CallbackGame",
|
|
36
|
+
"CallbackQuery",
|
|
37
|
+
"Chat",
|
|
38
|
+
"ChatAdministratorRights",
|
|
39
|
+
"ChatBackground",
|
|
40
|
+
"ChatBoost",
|
|
41
|
+
"ChatBoostAdded",
|
|
42
|
+
"ChatBoostRemoved",
|
|
43
|
+
"ChatBoostSource",
|
|
44
|
+
"ChatBoostSourceGiftCode",
|
|
45
|
+
"ChatBoostSourceGiveaway",
|
|
46
|
+
"ChatBoostSourcePremium",
|
|
47
|
+
"ChatBoostUpdated",
|
|
48
|
+
"ChatFullInfo",
|
|
49
|
+
"ChatInviteLink",
|
|
50
|
+
"ChatJoinRequest",
|
|
51
|
+
"ChatLocation",
|
|
52
|
+
"ChatMember",
|
|
53
|
+
"ChatMemberAdministrator",
|
|
54
|
+
"ChatMemberBanned",
|
|
55
|
+
"ChatMemberLeft",
|
|
56
|
+
"ChatMemberMember",
|
|
57
|
+
"ChatMemberOwner",
|
|
58
|
+
"ChatMemberRestricted",
|
|
59
|
+
"ChatMemberUpdated",
|
|
60
|
+
"ChatPermissions",
|
|
61
|
+
"ChatPhoto",
|
|
62
|
+
"ChatShared",
|
|
63
|
+
"ChosenInlineResult",
|
|
64
|
+
"Contact",
|
|
65
|
+
"Dice",
|
|
66
|
+
"Document",
|
|
67
|
+
"EncryptedCredentials",
|
|
68
|
+
"EncryptedPassportElement",
|
|
69
|
+
"ExternalReplyInfo",
|
|
70
|
+
"File",
|
|
71
|
+
"ForceReply",
|
|
72
|
+
"ForumTopic",
|
|
73
|
+
"ForumTopicClosed",
|
|
74
|
+
"ForumTopicCreated",
|
|
75
|
+
"ForumTopicEdited",
|
|
76
|
+
"ForumTopicReopened",
|
|
77
|
+
"Game",
|
|
78
|
+
"GameHighScore",
|
|
79
|
+
"GeneralForumTopicHidden",
|
|
80
|
+
"GeneralForumTopicUnhidden",
|
|
81
|
+
"Giveaway",
|
|
82
|
+
"GiveawayCompleted",
|
|
83
|
+
"GiveawayCreated",
|
|
84
|
+
"GiveawayWinners",
|
|
85
|
+
"InaccessibleMessage",
|
|
86
|
+
"InlineKeyboardButton",
|
|
87
|
+
"InlineKeyboardMarkup",
|
|
88
|
+
"InlineQuery",
|
|
89
|
+
"InlineQueryResult",
|
|
90
|
+
"InlineQueryResultArticle",
|
|
91
|
+
"InlineQueryResultAudio",
|
|
92
|
+
"InlineQueryResultCachedAudio",
|
|
93
|
+
"InlineQueryResultCachedDocument",
|
|
94
|
+
"InlineQueryResultCachedGif",
|
|
95
|
+
"InlineQueryResultCachedMpeg4Gif",
|
|
96
|
+
"InlineQueryResultCachedPhoto",
|
|
97
|
+
"InlineQueryResultCachedSticker",
|
|
98
|
+
"InlineQueryResultCachedVideo",
|
|
99
|
+
"InlineQueryResultCachedVoice",
|
|
100
|
+
"InlineQueryResultContact",
|
|
101
|
+
"InlineQueryResultDocument",
|
|
102
|
+
"InlineQueryResultGame",
|
|
103
|
+
"InlineQueryResultGif",
|
|
104
|
+
"InlineQueryResultLocation",
|
|
105
|
+
"InlineQueryResultMpeg4Gif",
|
|
106
|
+
"InlineQueryResultPhoto",
|
|
107
|
+
"InlineQueryResultVenue",
|
|
108
|
+
"InlineQueryResultVideo",
|
|
109
|
+
"InlineQueryResultVoice",
|
|
110
|
+
"InlineQueryResultsButton",
|
|
111
|
+
"InputContactMessageContent",
|
|
112
|
+
"InputFile",
|
|
113
|
+
"InputInvoiceMessageContent",
|
|
114
|
+
"InputLocationMessageContent",
|
|
115
|
+
"InputMedia",
|
|
116
|
+
"InputMediaAnimation",
|
|
117
|
+
"InputMediaAudio",
|
|
118
|
+
"InputMediaDocument",
|
|
119
|
+
"InputMediaPhoto",
|
|
120
|
+
"InputMediaVideo",
|
|
121
|
+
"InputMessageContent",
|
|
122
|
+
"InputPollOption",
|
|
123
|
+
"InputSticker",
|
|
124
|
+
"InputTextMessageContent",
|
|
125
|
+
"InputVenueMessageContent",
|
|
126
|
+
"Invoice",
|
|
127
|
+
"KeyboardButton",
|
|
128
|
+
"KeyboardButtonPollType",
|
|
129
|
+
"KeyboardButtonRequestChat",
|
|
130
|
+
"KeyboardButtonRequestUsers",
|
|
131
|
+
"LabeledPrice",
|
|
132
|
+
"LinkPreviewOptions",
|
|
133
|
+
"Location",
|
|
134
|
+
"LoginUrl",
|
|
135
|
+
"MaskPosition",
|
|
136
|
+
"MaybeInaccessibleMessage",
|
|
137
|
+
"MenuButton",
|
|
138
|
+
"MenuButtonCommands",
|
|
139
|
+
"MenuButtonDefault",
|
|
140
|
+
"MenuButtonWebApp",
|
|
141
|
+
"Message",
|
|
142
|
+
"MessageAutoDeleteTimerChanged",
|
|
143
|
+
"MessageEntity",
|
|
144
|
+
"MessageId",
|
|
145
|
+
"MessageOrigin",
|
|
146
|
+
"MessageOriginChannel",
|
|
147
|
+
"MessageOriginChat",
|
|
148
|
+
"MessageOriginHiddenUser",
|
|
149
|
+
"MessageOriginUser",
|
|
150
|
+
"MessageReactionCountUpdated",
|
|
151
|
+
"MessageReactionUpdated",
|
|
152
|
+
"Model",
|
|
153
|
+
"OrderInfo",
|
|
154
|
+
"PassportData",
|
|
155
|
+
"PassportElementError",
|
|
156
|
+
"PassportElementErrorDataField",
|
|
157
|
+
"PassportElementErrorFile",
|
|
158
|
+
"PassportElementErrorFiles",
|
|
159
|
+
"PassportElementErrorFrontSide",
|
|
160
|
+
"PassportElementErrorReverseSide",
|
|
161
|
+
"PassportElementErrorSelfie",
|
|
162
|
+
"PassportElementErrorTranslationFile",
|
|
163
|
+
"PassportElementErrorTranslationFiles",
|
|
164
|
+
"PassportElementErrorUnspecified",
|
|
165
|
+
"PassportFile",
|
|
166
|
+
"PhotoSize",
|
|
167
|
+
"Poll",
|
|
168
|
+
"PollAnswer",
|
|
169
|
+
"PollOption",
|
|
170
|
+
"PreCheckoutQuery",
|
|
171
|
+
"ProximityAlertTriggered",
|
|
172
|
+
"ReactionCount",
|
|
173
|
+
"ReactionType",
|
|
174
|
+
"ReactionTypeCustomEmoji",
|
|
175
|
+
"ReactionTypeEmoji",
|
|
176
|
+
"ReplyKeyboardMarkup",
|
|
177
|
+
"ReplyKeyboardRemove",
|
|
178
|
+
"ReplyParameters",
|
|
179
|
+
"ResponseParameters",
|
|
180
|
+
"SentWebAppMessage",
|
|
181
|
+
"SharedUser",
|
|
182
|
+
"ShippingAddress",
|
|
183
|
+
"ShippingOption",
|
|
184
|
+
"ShippingQuery",
|
|
185
|
+
"Sticker",
|
|
186
|
+
"StickerSet",
|
|
187
|
+
"Story",
|
|
188
|
+
"SuccessfulPayment",
|
|
189
|
+
"SwitchInlineQueryChosenChat",
|
|
190
|
+
"TextQuote",
|
|
191
|
+
"Update",
|
|
192
|
+
"User",
|
|
193
|
+
"UserChatBoosts",
|
|
194
|
+
"UserProfilePhotos",
|
|
195
|
+
"UsersShared",
|
|
196
|
+
"Venue",
|
|
197
|
+
"Video",
|
|
198
|
+
"VideoChatEnded",
|
|
199
|
+
"VideoChatParticipantsInvited",
|
|
200
|
+
"VideoChatScheduled",
|
|
201
|
+
"VideoChatStarted",
|
|
202
|
+
"VideoNote",
|
|
203
|
+
"Voice",
|
|
204
|
+
"WebAppData",
|
|
205
|
+
"WebAppInfo",
|
|
206
|
+
"WebhookInfo",
|
|
207
|
+
"WriteAccessAllowed",
|
|
208
|
+
)
|