telegrinder 0.4.2__py3-none-any.whl → 0.5.1__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 +37 -55
- telegrinder/__meta__.py +1 -0
- telegrinder/api/__init__.py +6 -4
- telegrinder/api/api.py +100 -26
- telegrinder/api/error.py +42 -8
- telegrinder/api/response.py +4 -1
- telegrinder/api/token.py +2 -2
- telegrinder/bot/__init__.py +9 -25
- telegrinder/bot/bot.py +31 -25
- telegrinder/bot/cute_types/__init__.py +0 -0
- telegrinder/bot/cute_types/base.py +103 -61
- telegrinder/bot/cute_types/callback_query.py +447 -400
- telegrinder/bot/cute_types/chat_join_request.py +59 -62
- telegrinder/bot/cute_types/chat_member_updated.py +154 -157
- telegrinder/bot/cute_types/inline_query.py +41 -44
- telegrinder/bot/cute_types/message.py +98 -67
- telegrinder/bot/cute_types/pre_checkout_query.py +38 -42
- telegrinder/bot/cute_types/update.py +1 -8
- telegrinder/bot/cute_types/utils.py +1 -1
- telegrinder/bot/dispatch/__init__.py +10 -15
- telegrinder/bot/dispatch/abc.py +12 -11
- telegrinder/bot/dispatch/action.py +104 -0
- telegrinder/bot/dispatch/context.py +32 -26
- telegrinder/bot/dispatch/dispatch.py +61 -134
- telegrinder/bot/dispatch/handler/__init__.py +2 -0
- telegrinder/bot/dispatch/handler/abc.py +10 -8
- telegrinder/bot/dispatch/handler/audio_reply.py +2 -3
- telegrinder/bot/dispatch/handler/base.py +10 -33
- telegrinder/bot/dispatch/handler/document_reply.py +2 -3
- telegrinder/bot/dispatch/handler/func.py +55 -87
- telegrinder/bot/dispatch/handler/media_group_reply.py +2 -3
- telegrinder/bot/dispatch/handler/message_reply.py +2 -3
- telegrinder/bot/dispatch/handler/photo_reply.py +2 -3
- telegrinder/bot/dispatch/handler/sticker_reply.py +2 -3
- telegrinder/bot/dispatch/handler/video_reply.py +2 -3
- telegrinder/bot/dispatch/middleware/__init__.py +0 -0
- telegrinder/bot/dispatch/middleware/abc.py +79 -55
- telegrinder/bot/dispatch/middleware/global_middleware.py +18 -33
- telegrinder/bot/dispatch/process.py +84 -105
- telegrinder/bot/dispatch/return_manager/__init__.py +0 -0
- telegrinder/bot/dispatch/return_manager/abc.py +102 -65
- telegrinder/bot/dispatch/return_manager/callback_query.py +4 -5
- telegrinder/bot/dispatch/return_manager/inline_query.py +3 -4
- telegrinder/bot/dispatch/return_manager/message.py +8 -10
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +4 -5
- telegrinder/bot/dispatch/view/__init__.py +4 -4
- telegrinder/bot/dispatch/view/abc.py +6 -16
- telegrinder/bot/dispatch/view/base.py +54 -178
- telegrinder/bot/dispatch/view/box.py +19 -18
- telegrinder/bot/dispatch/view/callback_query.py +4 -8
- telegrinder/bot/dispatch/view/chat_join_request.py +5 -6
- telegrinder/bot/dispatch/view/chat_member.py +5 -25
- telegrinder/bot/dispatch/view/error.py +9 -0
- telegrinder/bot/dispatch/view/inline_query.py +4 -8
- telegrinder/bot/dispatch/view/message.py +5 -25
- telegrinder/bot/dispatch/view/pre_checkout_query.py +4 -8
- telegrinder/bot/dispatch/view/raw.py +3 -109
- telegrinder/bot/dispatch/waiter_machine/__init__.py +2 -5
- telegrinder/bot/dispatch/waiter_machine/actions.py +6 -4
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +1 -3
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +1 -1
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +11 -7
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +43 -60
- telegrinder/bot/dispatch/waiter_machine/middleware.py +19 -23
- telegrinder/bot/dispatch/waiter_machine/short_state.py +6 -5
- telegrinder/bot/polling/__init__.py +0 -0
- telegrinder/bot/polling/abc.py +0 -0
- telegrinder/bot/polling/polling.py +209 -88
- telegrinder/bot/rules/__init__.py +3 -16
- telegrinder/bot/rules/abc.py +42 -122
- telegrinder/bot/rules/callback_data.py +29 -49
- telegrinder/bot/rules/chat_join.py +5 -23
- telegrinder/bot/rules/command.py +8 -4
- telegrinder/bot/rules/enum_text.py +3 -4
- telegrinder/bot/rules/func.py +7 -14
- telegrinder/bot/rules/fuzzy.py +3 -4
- telegrinder/bot/rules/inline.py +8 -20
- telegrinder/bot/rules/integer.py +2 -3
- telegrinder/bot/rules/is_from.py +12 -11
- telegrinder/bot/rules/logic.py +11 -5
- telegrinder/bot/rules/markup.py +22 -14
- telegrinder/bot/rules/mention.py +8 -7
- telegrinder/bot/rules/message_entities.py +8 -4
- telegrinder/bot/rules/node.py +23 -12
- telegrinder/bot/rules/payload.py +5 -4
- telegrinder/bot/rules/payment_invoice.py +6 -21
- telegrinder/bot/rules/regex.py +2 -4
- telegrinder/bot/rules/rule_enum.py +8 -7
- telegrinder/bot/rules/start.py +5 -6
- telegrinder/bot/rules/state.py +1 -1
- telegrinder/bot/rules/text.py +4 -15
- telegrinder/bot/rules/update.py +3 -4
- telegrinder/bot/scenario/__init__.py +0 -0
- telegrinder/bot/scenario/abc.py +6 -5
- telegrinder/bot/scenario/checkbox.py +1 -1
- telegrinder/bot/scenario/choice.py +30 -39
- telegrinder/client/__init__.py +3 -5
- telegrinder/client/abc.py +11 -6
- telegrinder/client/aiohttp.py +141 -27
- telegrinder/client/form_data.py +1 -1
- telegrinder/model.py +61 -89
- telegrinder/modules.py +325 -102
- telegrinder/msgspec_utils/__init__.py +40 -0
- telegrinder/msgspec_utils/abc.py +18 -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 +43 -0
- telegrinder/msgspec_utils/custom_types/literal.py +25 -0
- telegrinder/msgspec_utils/custom_types/option.py +17 -0
- telegrinder/msgspec_utils/decoder.py +389 -0
- telegrinder/msgspec_utils/encoder.py +206 -0
- telegrinder/{msgspec_json.py → msgspec_utils/json.py} +6 -5
- telegrinder/msgspec_utils/tools.py +75 -0
- telegrinder/node/__init__.py +24 -7
- telegrinder/node/attachment.py +1 -0
- telegrinder/node/base.py +154 -72
- telegrinder/node/callback_query.py +5 -5
- telegrinder/node/collection.py +39 -0
- telegrinder/node/command.py +1 -2
- telegrinder/node/composer.py +121 -72
- telegrinder/node/container.py +11 -8
- telegrinder/node/context.py +48 -0
- telegrinder/node/either.py +27 -40
- telegrinder/node/error.py +41 -0
- telegrinder/node/event.py +37 -11
- telegrinder/node/exceptions.py +7 -0
- telegrinder/node/file.py +0 -0
- telegrinder/node/i18n.py +108 -0
- telegrinder/node/me.py +3 -2
- telegrinder/node/payload.py +1 -1
- telegrinder/node/polymorphic.py +63 -28
- telegrinder/node/reply_message.py +12 -0
- telegrinder/node/rule.py +6 -13
- telegrinder/node/scope.py +14 -5
- telegrinder/node/session.py +53 -0
- telegrinder/node/source.py +41 -9
- telegrinder/node/text.py +1 -2
- telegrinder/node/tools/__init__.py +0 -0
- telegrinder/node/tools/generator.py +3 -5
- telegrinder/node/utility.py +16 -0
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +0 -0
- telegrinder/tools/__init__.py +48 -88
- telegrinder/tools/aio.py +103 -0
- telegrinder/tools/callback_data_serialization/__init__.py +5 -0
- telegrinder/tools/{callback_data_serilization → callback_data_serialization}/abc.py +0 -0
- telegrinder/tools/{callback_data_serilization → callback_data_serialization}/json_ser.py +2 -3
- telegrinder/tools/{callback_data_serilization → callback_data_serialization}/msgpack_ser.py +45 -27
- telegrinder/tools/final.py +21 -0
- telegrinder/tools/formatting/__init__.py +2 -18
- telegrinder/tools/formatting/deep_links/__init__.py +39 -0
- telegrinder/tools/formatting/{deep_links.py → deep_links/links.py} +12 -85
- telegrinder/tools/formatting/deep_links/parsing.py +90 -0
- telegrinder/tools/formatting/deep_links/validators.py +8 -0
- telegrinder/tools/formatting/html_formatter.py +18 -45
- telegrinder/tools/fullname.py +83 -0
- telegrinder/tools/global_context/__init__.py +4 -3
- telegrinder/tools/global_context/abc.py +17 -14
- telegrinder/tools/global_context/builtin_context.py +39 -0
- telegrinder/tools/global_context/global_context.py +138 -39
- telegrinder/tools/input_file_directory.py +0 -0
- telegrinder/tools/keyboard/__init__.py +39 -0
- telegrinder/tools/keyboard/abc.py +159 -0
- telegrinder/tools/keyboard/base.py +77 -0
- telegrinder/tools/keyboard/buttons/__init__.py +14 -0
- telegrinder/tools/keyboard/buttons/base.py +18 -0
- telegrinder/tools/{buttons.py → keyboard/buttons/buttons.py} +71 -23
- telegrinder/tools/keyboard/buttons/static_buttons.py +56 -0
- telegrinder/tools/keyboard/buttons/tools.py +18 -0
- telegrinder/tools/keyboard/data.py +20 -0
- telegrinder/tools/keyboard/keyboard.py +131 -0
- telegrinder/tools/keyboard/static_keyboard.py +83 -0
- telegrinder/tools/lifespan.py +87 -51
- telegrinder/tools/limited_dict.py +4 -1
- telegrinder/tools/loop_wrapper.py +332 -0
- telegrinder/tools/magic/__init__.py +32 -0
- telegrinder/tools/magic/annotations.py +165 -0
- telegrinder/tools/magic/dictionary.py +20 -0
- telegrinder/tools/magic/function.py +246 -0
- telegrinder/tools/magic/shortcut.py +111 -0
- telegrinder/tools/parse_mode.py +9 -3
- telegrinder/tools/singleton/__init__.py +4 -0
- telegrinder/tools/singleton/abc.py +14 -0
- telegrinder/tools/singleton/singleton.py +18 -0
- telegrinder/tools/state_storage/__init__.py +0 -0
- telegrinder/tools/state_storage/abc.py +6 -1
- telegrinder/tools/state_storage/memory.py +1 -1
- telegrinder/tools/strings.py +0 -0
- telegrinder/types/__init__.py +307 -268
- telegrinder/types/enums.py +68 -37
- telegrinder/types/input_file.py +3 -3
- telegrinder/types/methods.py +5699 -5055
- telegrinder/types/methods_utils.py +62 -0
- telegrinder/types/objects.py +1782 -994
- telegrinder/verification_utils.py +3 -1
- telegrinder-0.5.1.dist-info/METADATA +162 -0
- telegrinder-0.5.1.dist-info/RECORD +200 -0
- {telegrinder-0.4.2.dist-info → telegrinder-0.5.1.dist-info}/licenses/LICENSE +2 -2
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +0 -20
- telegrinder/bot/rules/id.py +0 -24
- telegrinder/bot/rules/message.py +0 -15
- telegrinder/client/sonic.py +0 -212
- telegrinder/msgspec_utils.py +0 -478
- telegrinder/tools/adapter/__init__.py +0 -19
- telegrinder/tools/adapter/abc.py +0 -49
- telegrinder/tools/adapter/dataclass.py +0 -56
- telegrinder/tools/adapter/errors.py +0 -5
- telegrinder/tools/adapter/event.py +0 -61
- telegrinder/tools/adapter/node.py +0 -46
- telegrinder/tools/adapter/raw_event.py +0 -27
- telegrinder/tools/adapter/raw_update.py +0 -30
- telegrinder/tools/callback_data_serilization/__init__.py +0 -5
- telegrinder/tools/error_handler/__init__.py +0 -10
- telegrinder/tools/error_handler/abc.py +0 -30
- telegrinder/tools/error_handler/error.py +0 -9
- telegrinder/tools/error_handler/error_handler.py +0 -179
- telegrinder/tools/formatting/spec_html_formats.py +0 -75
- telegrinder/tools/functional.py +0 -8
- telegrinder/tools/global_context/telegrinder_ctx.py +0 -27
- telegrinder/tools/i18n/__init__.py +0 -12
- telegrinder/tools/i18n/abc.py +0 -32
- telegrinder/tools/i18n/middleware/__init__.py +0 -3
- telegrinder/tools/i18n/middleware/abc.py +0 -22
- telegrinder/tools/i18n/simple.py +0 -43
- telegrinder/tools/keyboard.py +0 -132
- telegrinder/tools/loop_wrapper/__init__.py +0 -4
- telegrinder/tools/loop_wrapper/abc.py +0 -20
- telegrinder/tools/loop_wrapper/loop_wrapper.py +0 -169
- telegrinder/tools/magic.py +0 -344
- telegrinder-0.4.2.dist-info/METADATA +0 -151
- telegrinder-0.4.2.dist-info/RECORD +0 -182
- {telegrinder-0.4.2.dist-info → telegrinder-0.5.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import types
|
|
2
|
+
import typing
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from datetime import timedelta
|
|
5
|
+
from urllib.parse import urlencode
|
|
6
|
+
|
|
7
|
+
from telegrinder.tools.magic.function import get_func_annotations
|
|
8
|
+
|
|
9
|
+
type DeepLinkFunction[**P] = typing.Callable[P, str]
|
|
10
|
+
type NoValue = types.EllipsisType
|
|
11
|
+
|
|
12
|
+
Parameter = typing.Annotated
|
|
13
|
+
|
|
14
|
+
NO_VALUE: typing.Final[NoValue] = typing.cast("NoValue", ...)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_query_params(
|
|
18
|
+
func: DeepLinkFunction[...],
|
|
19
|
+
kwargs: dict[str, typing.Any],
|
|
20
|
+
order_params: set[str] | None = None,
|
|
21
|
+
) -> dict[str, typing.Any]:
|
|
22
|
+
annotations = get_func_annotations(func)
|
|
23
|
+
params = OrderedDict()
|
|
24
|
+
param_names = (
|
|
25
|
+
[*order_params, *(p for p in annotations if p not in order_params)] if order_params else annotations
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
for param_name in param_names:
|
|
29
|
+
annotation = annotations[param_name]
|
|
30
|
+
if param_name in kwargs:
|
|
31
|
+
value = kwargs[param_name]
|
|
32
|
+
if typing.get_origin(annotation) is Parameter:
|
|
33
|
+
param_name, validator = get_parameter_metadata(annotation)
|
|
34
|
+
value = validator(value) if validator is not None else value
|
|
35
|
+
|
|
36
|
+
params[param_name] = value
|
|
37
|
+
|
|
38
|
+
return params
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse_query_params(
|
|
42
|
+
params: dict[str, typing.Any],
|
|
43
|
+
no_value_params: set[str] | None = None,
|
|
44
|
+
/,
|
|
45
|
+
) -> tuple[set[str], dict[str, typing.Any]]:
|
|
46
|
+
no_value_params = no_value_params or set()
|
|
47
|
+
params_: dict[str, typing.Any] = {}
|
|
48
|
+
|
|
49
|
+
for key, value in params.items():
|
|
50
|
+
if value in (False, None):
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
if value in (True, NO_VALUE):
|
|
54
|
+
no_value_params.add(key)
|
|
55
|
+
continue
|
|
56
|
+
if isinstance(value, timedelta):
|
|
57
|
+
value = int(value.total_seconds())
|
|
58
|
+
|
|
59
|
+
params_[key] = value
|
|
60
|
+
|
|
61
|
+
return (no_value_params, params_)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_parameter_metadata(
|
|
65
|
+
parameter: typing.Any,
|
|
66
|
+
) -> tuple[str, typing.Callable[[typing.Any], typing.Any] | None]:
|
|
67
|
+
meta: tuple[typing.Any, ...] = getattr(parameter, "__metadata__")
|
|
68
|
+
return meta if len(meta) == 2 else (meta[0], None)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def parse_deep_link(
|
|
72
|
+
*,
|
|
73
|
+
link: str,
|
|
74
|
+
params: dict[str, typing.Any],
|
|
75
|
+
no_value_params: set[str] | None = None,
|
|
76
|
+
) -> str:
|
|
77
|
+
no_value_params, params = parse_query_params(params, no_value_params)
|
|
78
|
+
query = urlencode(params, encoding="UTF-8") + ("&" if no_value_params else "") + "&".join(no_value_params)
|
|
79
|
+
return f"{link}?{query}"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
__all__ = (
|
|
83
|
+
"NO_VALUE",
|
|
84
|
+
"NoValue",
|
|
85
|
+
"Parameter",
|
|
86
|
+
"get_parameter_metadata",
|
|
87
|
+
"get_query_params",
|
|
88
|
+
"parse_deep_link",
|
|
89
|
+
"parse_query_params",
|
|
90
|
+
)
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import dataclasses
|
|
4
3
|
import html
|
|
5
4
|
import string
|
|
6
5
|
import typing
|
|
7
6
|
from contextlib import suppress
|
|
8
7
|
|
|
8
|
+
from telegrinder.tools.formatting.deep_links import tg_mention_link
|
|
9
9
|
from telegrinder.tools.parse_mode import ParseMode
|
|
10
10
|
from telegrinder.types.enums import ProgrammingLanguage
|
|
11
11
|
|
|
12
|
-
from .deep_links import tg_mention_link
|
|
13
|
-
from .spec_html_formats import SpecialFormat, is_spec_format
|
|
14
|
-
|
|
15
12
|
type HTMLFormat = str | TagFormat
|
|
16
13
|
|
|
17
14
|
HTML_UNION_SPECIFIERS_SEPARATOR: typing.Final[str] = "+"
|
|
@@ -54,18 +51,13 @@ class StringFormatter(string.Formatter):
|
|
|
54
51
|
|
|
55
52
|
return fmt
|
|
56
53
|
|
|
57
|
-
def get_spec_formatter(self, value: SpecialFormat) -> typing.Callable[..., TagFormat]:
|
|
58
|
-
return globals()[value.__formatter_name__]
|
|
59
|
-
|
|
60
54
|
def make_tag_format(self, value: typing.Any, fmts: list[HTMLFormat]) -> TagFormat:
|
|
61
|
-
if is_spec_format(value):
|
|
62
|
-
value = value.string
|
|
63
|
-
|
|
64
55
|
current_format = globals()[fmts.pop(0)](
|
|
65
56
|
str(value)
|
|
66
57
|
if isinstance(value, TagFormat)
|
|
67
58
|
else escape(FormatString(value) if not isinstance(value, str) else value)
|
|
68
59
|
)
|
|
60
|
+
|
|
69
61
|
for fmt in fmts:
|
|
70
62
|
current_format = globals()[fmt](current_format)
|
|
71
63
|
|
|
@@ -81,20 +73,7 @@ class StringFormatter(string.Formatter):
|
|
|
81
73
|
|
|
82
74
|
def format_field(self, value: typing.Any, fmt: str) -> HTMLFormatter:
|
|
83
75
|
with suppress(ValueError):
|
|
84
|
-
return HTMLFormatter(
|
|
85
|
-
format(
|
|
86
|
-
(
|
|
87
|
-
value.formatting()
|
|
88
|
-
if isinstance(value, TagFormat)
|
|
89
|
-
else (
|
|
90
|
-
self.get_spec_formatter(value)(**dataclasses.asdict(value)).formatting()
|
|
91
|
-
if is_spec_format(value)
|
|
92
|
-
else value
|
|
93
|
-
)
|
|
94
|
-
),
|
|
95
|
-
fmt,
|
|
96
|
-
)
|
|
97
|
-
)
|
|
76
|
+
return HTMLFormatter(format(value.formatting() if isinstance(value, TagFormat) else value, fmt))
|
|
98
77
|
|
|
99
78
|
fmts = list(
|
|
100
79
|
map(
|
|
@@ -102,13 +81,7 @@ class StringFormatter(string.Formatter):
|
|
|
102
81
|
fmt.split(HTML_UNION_SPECIFIERS_SEPARATOR),
|
|
103
82
|
),
|
|
104
83
|
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if is_spec_format(value):
|
|
108
|
-
value.string = tag_format
|
|
109
|
-
tag_format = self.get_spec_formatter(value)(**dataclasses.asdict(value))
|
|
110
|
-
|
|
111
|
-
return tag_format.formatting()
|
|
84
|
+
return self.make_tag_format(value, fmts).formatting()
|
|
112
85
|
|
|
113
86
|
def format(self, __string: str, *args: object, **kwargs: object) -> HTMLFormatter:
|
|
114
87
|
return HTMLFormatter(super().format(__string, *args, **kwargs))
|
|
@@ -192,15 +165,15 @@ class TagFormat(FormatString):
|
|
|
192
165
|
|
|
193
166
|
class HTMLFormatter(FormatString):
|
|
194
167
|
""">>> HTMLFormatter(bold("Hello, World"))
|
|
195
|
-
|
|
168
|
+
'<b>Hello, World</b>'
|
|
196
169
|
>>> HTMLFormatter("Hi, {name:italic}").format(name="Max")
|
|
197
|
-
|
|
170
|
+
'Hi, <i>Max</i>'
|
|
198
171
|
"""
|
|
199
172
|
|
|
200
|
-
PARSE_MODE = ParseMode.HTML
|
|
173
|
+
PARSE_MODE: typing.Final[str] = ParseMode.HTML
|
|
201
174
|
|
|
202
175
|
|
|
203
|
-
def escape(string: str) -> EscapedString:
|
|
176
|
+
def escape(string: str, /) -> EscapedString:
|
|
204
177
|
if isinstance(string, EscapedString | HTMLFormatter):
|
|
205
178
|
return EscapedString(string)
|
|
206
179
|
return EscapedString(html.escape(string, quote=False))
|
|
@@ -226,45 +199,45 @@ def italic(string: str) -> TagFormat:
|
|
|
226
199
|
return TagFormat(string, tag="i")
|
|
227
200
|
|
|
228
201
|
|
|
229
|
-
def link(href: str,
|
|
202
|
+
def link(href: str, /, *, text: str | None = None) -> TagFormat:
|
|
230
203
|
return TagFormat(
|
|
231
|
-
|
|
204
|
+
text or href,
|
|
232
205
|
tag="a",
|
|
233
206
|
href=QUOT_MARK + href + QUOT_MARK,
|
|
234
207
|
)
|
|
235
208
|
|
|
236
209
|
|
|
237
|
-
def pre_code(string: str, lang: str | ProgrammingLanguage | None = None) -> TagFormat:
|
|
210
|
+
def pre_code(string: str, /, *, lang: str | ProgrammingLanguage | None = None) -> TagFormat:
|
|
238
211
|
if lang is None:
|
|
239
212
|
return TagFormat(string, tag="pre")
|
|
213
|
+
|
|
240
214
|
lang = lang.value if isinstance(lang, ProgrammingLanguage) else lang
|
|
241
215
|
return pre_code(TagFormat(string, tag="code", **{"class": f"language-{lang}"}))
|
|
242
216
|
|
|
243
217
|
|
|
244
|
-
def spoiler(string: str) -> TagFormat:
|
|
218
|
+
def spoiler(string: str, /) -> TagFormat:
|
|
245
219
|
return TagFormat(string, tag="tg-spoiler")
|
|
246
220
|
|
|
247
221
|
|
|
248
|
-
def strike(string: str) -> TagFormat:
|
|
222
|
+
def strike(string: str, /) -> TagFormat:
|
|
249
223
|
return TagFormat(string, tag="s")
|
|
250
224
|
|
|
251
225
|
|
|
252
|
-
def mention(string: str, user_id: int) -> TagFormat:
|
|
253
|
-
return link(tg_mention_link(user_id=user_id), string)
|
|
226
|
+
def mention(string: str, /, *, user_id: int) -> TagFormat:
|
|
227
|
+
return link(tg_mention_link(user_id=user_id), text=string)
|
|
254
228
|
|
|
255
229
|
|
|
256
|
-
def tg_emoji(string: str, emoji_id: int) -> TagFormat:
|
|
230
|
+
def tg_emoji(string: str, /, *, emoji_id: int) -> TagFormat:
|
|
257
231
|
return TagFormat(string, tag="tg-emoji", emoji_id=emoji_id)
|
|
258
232
|
|
|
259
233
|
|
|
260
|
-
def underline(string: str) -> TagFormat:
|
|
234
|
+
def underline(string: str, /) -> TagFormat:
|
|
261
235
|
return TagFormat(string, tag="u")
|
|
262
236
|
|
|
263
237
|
|
|
264
238
|
__all__ = (
|
|
265
239
|
"FormatString",
|
|
266
240
|
"HTMLFormatter",
|
|
267
|
-
"SpecialFormat",
|
|
268
241
|
"block_quote",
|
|
269
242
|
"bold",
|
|
270
243
|
"code_inline",
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import builtins
|
|
2
|
+
import inspect
|
|
3
|
+
import os.path
|
|
4
|
+
import sys
|
|
5
|
+
import types
|
|
6
|
+
|
|
7
|
+
import typing_extensions as typing
|
|
8
|
+
|
|
9
|
+
type RoutineMethodType = (
|
|
10
|
+
types.MethodType | types.MethodDescriptorType | types.MethodWrapperType | types.BuiltinMethodType
|
|
11
|
+
)
|
|
12
|
+
type RoutineDescriptorType = types.MethodDescriptorType | types.GetSetDescriptorType
|
|
13
|
+
|
|
14
|
+
_BUILTINS: typing.Final[frozenset[typing.Any]] = frozenset(
|
|
15
|
+
x for name in dir(builtins) if getattr((x := getattr(builtins, name)), "__module__", None) == "builtins"
|
|
16
|
+
)
|
|
17
|
+
_CACHE_KEY: typing.Final[str] = "__fullname_cache__"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _is_builtin(obj: typing.Any, /) -> bool:
|
|
21
|
+
return inspect.isbuiltin(obj) or obj in _BUILTINS
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _is_routine_method(obj: typing.Any, /) -> typing.TypeIs[RoutineMethodType]:
|
|
25
|
+
return inspect.isbuiltin(obj) or inspect.ismethod(obj) or inspect.ismethodwrapper(obj)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _is_routine_descriptor(obj: typing.Any, /) -> typing.TypeIs[RoutineDescriptorType]:
|
|
29
|
+
return inspect.ismethoddescriptor(obj) or inspect.isgetsetdescriptor(obj)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _module_name(module: types.ModuleType, /) -> str:
|
|
33
|
+
if (mod_name := module.__name__) != "__main__":
|
|
34
|
+
return mod_name
|
|
35
|
+
|
|
36
|
+
mod_package = module.__package__ or ""
|
|
37
|
+
mod_file = module.__file__
|
|
38
|
+
if mod_file is None:
|
|
39
|
+
return mod_package
|
|
40
|
+
|
|
41
|
+
mod_fname = os.path.basename(mod_file).removesuffix(".py")
|
|
42
|
+
return mod_package if mod_package in ("__init__", "__main__") else mod_fname
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def fullname(obj: object, /) -> str:
|
|
46
|
+
"""The full name (`__module__.__name__`) of the object."""
|
|
47
|
+
|
|
48
|
+
if isinstance(obj, staticmethod | classmethod):
|
|
49
|
+
obj = obj.__func__
|
|
50
|
+
|
|
51
|
+
elif (
|
|
52
|
+
not inspect.isroutine(obj)
|
|
53
|
+
and not inspect.isgetsetdescriptor(obj)
|
|
54
|
+
and not isinstance(obj, type)
|
|
55
|
+
and not inspect.ismodule(obj)
|
|
56
|
+
):
|
|
57
|
+
obj = type(obj)
|
|
58
|
+
|
|
59
|
+
if (name := fullname.__dict__.setdefault(_CACHE_KEY, dict()).get(obj)) is not None:
|
|
60
|
+
return name
|
|
61
|
+
|
|
62
|
+
if inspect.ismodule(obj):
|
|
63
|
+
fullname.__dict__[_CACHE_KEY][obj] = name = _module_name(obj)
|
|
64
|
+
return name
|
|
65
|
+
|
|
66
|
+
qualname = obj.__qualname__
|
|
67
|
+
orig_obj = obj
|
|
68
|
+
|
|
69
|
+
if _is_routine_method(obj) or _is_routine_descriptor(obj):
|
|
70
|
+
obj_cls = obj.__objclass__ if _is_routine_descriptor(obj) else obj.__self__
|
|
71
|
+
obj = type(obj_cls) if not isinstance(obj_cls, type) else obj_cls
|
|
72
|
+
|
|
73
|
+
module: str = getattr(orig_obj, "__module__", obj.__module__)
|
|
74
|
+
if _is_builtin(obj) and module != builtins.__name__:
|
|
75
|
+
module = builtins.__name__
|
|
76
|
+
else:
|
|
77
|
+
module = _module_name(sys.modules[module])
|
|
78
|
+
|
|
79
|
+
fullname.__dict__[_CACHE_KEY][orig_obj] = name = ".".join((module, qualname))
|
|
80
|
+
return name
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
__all__ = ("fullname",)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from .abc import ABCGlobalContext, CtxVar, GlobalCtxVar
|
|
2
|
-
from .global_context import
|
|
3
|
-
from .
|
|
1
|
+
from telegrinder.tools.global_context.abc import ABCGlobalContext, CtxVar, GlobalCtxVar
|
|
2
|
+
from telegrinder.tools.global_context.builtin_context import TelegrinderContext
|
|
3
|
+
from telegrinder.tools.global_context.global_context import GlobalContext, ctx_var, runtime_init
|
|
4
4
|
|
|
5
5
|
__all__ = (
|
|
6
6
|
"ABCGlobalContext",
|
|
@@ -9,4 +9,5 @@ __all__ = (
|
|
|
9
9
|
"GlobalCtxVar",
|
|
10
10
|
"TelegrinderContext",
|
|
11
11
|
"ctx_var",
|
|
12
|
+
"runtime_init",
|
|
12
13
|
)
|
|
@@ -7,38 +7,41 @@ import typing_extensions as typing
|
|
|
7
7
|
|
|
8
8
|
T = typing.TypeVar("T", default=typing.Any)
|
|
9
9
|
|
|
10
|
+
NODEFAULT: typing.Final[object] = object()
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
|
|
13
|
+
@dataclasses.dataclass(frozen=True)
|
|
12
14
|
class CtxVar(typing.Generic[T]):
|
|
13
15
|
value: T
|
|
16
|
+
factory: typing.Any = dataclasses.field(default=NODEFAULT, kw_only=True)
|
|
14
17
|
const: bool = dataclasses.field(default=False, kw_only=True)
|
|
15
18
|
|
|
16
|
-
def __repr__(self) -> str:
|
|
17
|
-
return "<{}(value={!r})>".format(
|
|
18
|
-
("Const" if self.const else "") + CtxVar.__name__,
|
|
19
|
-
self.value,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
19
|
|
|
23
20
|
@dataclasses.dataclass(repr=False, frozen=True)
|
|
24
|
-
class GlobalCtxVar(typing.Generic[T]):
|
|
21
|
+
class GlobalCtxVar(CtxVar[T], typing.Generic[T]):
|
|
25
22
|
name: str
|
|
26
23
|
value: T
|
|
24
|
+
factory: typing.Any = dataclasses.field(default=NODEFAULT, kw_only=True)
|
|
27
25
|
const: bool = dataclasses.field(default=False, kw_only=True)
|
|
28
26
|
|
|
29
27
|
def __repr__(self) -> str:
|
|
30
28
|
return "<{}({}={})>".format(
|
|
31
29
|
self.__class__.__name__,
|
|
32
30
|
self.name,
|
|
33
|
-
repr(CtxVar(self.value, const=self.const)),
|
|
31
|
+
repr(CtxVar(self.value, const=self.const, factory=self.factory)),
|
|
34
32
|
)
|
|
35
33
|
|
|
36
34
|
@classmethod
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
def from_var(
|
|
36
|
+
cls,
|
|
37
|
+
name: str,
|
|
38
|
+
ctx_value: T | CtxVariable[T],
|
|
39
|
+
const: bool = False,
|
|
40
|
+
) -> typing.Self:
|
|
41
|
+
var = CtxVar(ctx_value, const=const) if not isinstance(ctx_value, CtxVar | GlobalCtxVar) else ctx_value
|
|
42
|
+
if var.value is NODEFAULT and var.factory is not NODEFAULT:
|
|
43
|
+
var = dataclasses.replace(var, value=var.factory())
|
|
44
|
+
return cls(**dict(var.__dict__) | dict(name=name))
|
|
42
45
|
|
|
43
46
|
|
|
44
47
|
class ABCGlobalContext(ABC, typing.Generic[T]):
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
from fntypes.option import Nothing, Option
|
|
7
|
+
from vbml.patcher.abc import ABCPatcher
|
|
8
|
+
from vbml.patcher.patcher import Patcher
|
|
9
|
+
|
|
10
|
+
from telegrinder.tools.global_context.global_context import GlobalContext, ctx_var, runtime_init
|
|
11
|
+
from telegrinder.tools.loop_wrapper import LoopWrapper
|
|
12
|
+
|
|
13
|
+
if typing.TYPE_CHECKING:
|
|
14
|
+
from telegrinder.node.composer import Composer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@runtime_init
|
|
18
|
+
class TelegrinderContext(GlobalContext):
|
|
19
|
+
"""The type-hinted telegrinder context called `telegrinder`.
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
```
|
|
23
|
+
from telegrinder.tools.global_context import GlobalContext, TelegrinderContext
|
|
24
|
+
|
|
25
|
+
telegrinder_ctx = TelegrinderContext(...) # with type-hints
|
|
26
|
+
assert telegrinder_ctx == GlobalContext("telegrinder") # ok
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
__ctx_name__ = "telegrinder"
|
|
32
|
+
|
|
33
|
+
composer: Option[Composer] = ctx_var(default=Nothing(), init=False)
|
|
34
|
+
vbml_pattern_flags: re.RegexFlag | None = ctx_var(default=None, init=False)
|
|
35
|
+
vbml_patcher: ABCPatcher = ctx_var(default_factory=Patcher, init=False)
|
|
36
|
+
loop_wrapper: LoopWrapper = ctx_var(default_factory=LoopWrapper, init=False)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
__all__ = ("TelegrinderContext",)
|