telegrinder 1.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- telegrinder/__init__.py +258 -0
- telegrinder/__meta__.py +1 -0
- telegrinder/api/__init__.py +15 -0
- telegrinder/api/api.py +175 -0
- telegrinder/api/error.py +50 -0
- telegrinder/api/response.py +23 -0
- telegrinder/api/token.py +30 -0
- telegrinder/api/validators.py +30 -0
- telegrinder/bot/__init__.py +144 -0
- telegrinder/bot/bot.py +70 -0
- telegrinder/bot/cute_types/__init__.py +41 -0
- telegrinder/bot/cute_types/base.py +228 -0
- telegrinder/bot/cute_types/base.pyi +49 -0
- telegrinder/bot/cute_types/business_connection.py +9 -0
- telegrinder/bot/cute_types/business_messages_deleted.py +9 -0
- telegrinder/bot/cute_types/callback_query.py +248 -0
- telegrinder/bot/cute_types/chat_boost_removed.py +9 -0
- telegrinder/bot/cute_types/chat_boost_updated.py +9 -0
- telegrinder/bot/cute_types/chat_join_request.py +59 -0
- telegrinder/bot/cute_types/chat_member_updated.py +158 -0
- telegrinder/bot/cute_types/chosen_inline_result.py +11 -0
- telegrinder/bot/cute_types/inline_query.py +41 -0
- telegrinder/bot/cute_types/message.py +2809 -0
- telegrinder/bot/cute_types/message_reaction_count_updated.py +9 -0
- telegrinder/bot/cute_types/message_reaction_updated.py +9 -0
- telegrinder/bot/cute_types/paid_media_purchased.py +11 -0
- telegrinder/bot/cute_types/poll.py +9 -0
- telegrinder/bot/cute_types/poll_answer.py +9 -0
- telegrinder/bot/cute_types/pre_checkout_query.py +36 -0
- telegrinder/bot/cute_types/shipping_query.py +11 -0
- telegrinder/bot/cute_types/update.py +209 -0
- telegrinder/bot/cute_types/utils.py +141 -0
- telegrinder/bot/dispatch/__init__.py +99 -0
- telegrinder/bot/dispatch/abc.py +74 -0
- telegrinder/bot/dispatch/action.py +99 -0
- telegrinder/bot/dispatch/context.py +162 -0
- telegrinder/bot/dispatch/dispatch.py +362 -0
- telegrinder/bot/dispatch/handler/__init__.py +23 -0
- telegrinder/bot/dispatch/handler/abc.py +25 -0
- telegrinder/bot/dispatch/handler/audio_reply.py +43 -0
- telegrinder/bot/dispatch/handler/base.py +34 -0
- telegrinder/bot/dispatch/handler/document_reply.py +43 -0
- telegrinder/bot/dispatch/handler/func.py +73 -0
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -0
- telegrinder/bot/dispatch/handler/message_reply.py +35 -0
- telegrinder/bot/dispatch/handler/photo_reply.py +43 -0
- telegrinder/bot/dispatch/handler/sticker_reply.py +36 -0
- telegrinder/bot/dispatch/handler/video_reply.py +43 -0
- telegrinder/bot/dispatch/middleware/__init__.py +13 -0
- telegrinder/bot/dispatch/middleware/abc.py +112 -0
- telegrinder/bot/dispatch/middleware/box.py +32 -0
- telegrinder/bot/dispatch/middleware/filter.py +88 -0
- telegrinder/bot/dispatch/middleware/media_group.py +69 -0
- telegrinder/bot/dispatch/process.py +93 -0
- telegrinder/bot/dispatch/return_manager/__init__.py +21 -0
- telegrinder/bot/dispatch/return_manager/abc.py +107 -0
- telegrinder/bot/dispatch/return_manager/callback_query.py +19 -0
- telegrinder/bot/dispatch/return_manager/inline_query.py +14 -0
- telegrinder/bot/dispatch/return_manager/message.py +34 -0
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +19 -0
- telegrinder/bot/dispatch/return_manager/utils.py +20 -0
- telegrinder/bot/dispatch/router/__init__.py +4 -0
- telegrinder/bot/dispatch/router/abc.py +15 -0
- telegrinder/bot/dispatch/router/base.py +154 -0
- telegrinder/bot/dispatch/view/__init__.py +15 -0
- telegrinder/bot/dispatch/view/abc.py +15 -0
- telegrinder/bot/dispatch/view/base.py +226 -0
- telegrinder/bot/dispatch/view/box.py +207 -0
- telegrinder/bot/dispatch/view/media_group.py +25 -0
- telegrinder/bot/dispatch/waiter_machine/__init__.py +25 -0
- telegrinder/bot/dispatch/waiter_machine/actions.py +16 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +13 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +53 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +61 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +49 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +264 -0
- telegrinder/bot/dispatch/waiter_machine/middleware.py +77 -0
- telegrinder/bot/dispatch/waiter_machine/short_state.py +105 -0
- telegrinder/bot/polling/__init__.py +4 -0
- telegrinder/bot/polling/abc.py +25 -0
- telegrinder/bot/polling/error_handler.py +93 -0
- telegrinder/bot/polling/polling.py +167 -0
- telegrinder/bot/polling/utils.py +12 -0
- telegrinder/bot/rules/__init__.py +166 -0
- telegrinder/bot/rules/abc.py +150 -0
- telegrinder/bot/rules/button.py +20 -0
- telegrinder/bot/rules/callback_data.py +109 -0
- telegrinder/bot/rules/chat_join.py +28 -0
- telegrinder/bot/rules/chat_member_updated.py +145 -0
- telegrinder/bot/rules/command.py +137 -0
- telegrinder/bot/rules/enum_text.py +29 -0
- telegrinder/bot/rules/func.py +21 -0
- telegrinder/bot/rules/fuzzy.py +21 -0
- telegrinder/bot/rules/inline.py +45 -0
- telegrinder/bot/rules/integer.py +19 -0
- telegrinder/bot/rules/is_from.py +213 -0
- telegrinder/bot/rules/logic.py +22 -0
- telegrinder/bot/rules/magic.py +60 -0
- telegrinder/bot/rules/markup.py +51 -0
- telegrinder/bot/rules/media.py +13 -0
- telegrinder/bot/rules/mention.py +15 -0
- telegrinder/bot/rules/message_entities.py +37 -0
- telegrinder/bot/rules/node.py +43 -0
- telegrinder/bot/rules/payload.py +89 -0
- telegrinder/bot/rules/payment_invoice.py +14 -0
- telegrinder/bot/rules/regex.py +34 -0
- telegrinder/bot/rules/rule_enum.py +71 -0
- telegrinder/bot/rules/start.py +73 -0
- telegrinder/bot/rules/state.py +35 -0
- telegrinder/bot/rules/text.py +27 -0
- telegrinder/bot/rules/update.py +14 -0
- telegrinder/bot/scenario/__init__.py +5 -0
- telegrinder/bot/scenario/abc.py +16 -0
- telegrinder/bot/scenario/checkbox.py +183 -0
- telegrinder/bot/scenario/choice.py +44 -0
- telegrinder/client/__init__.py +11 -0
- telegrinder/client/abc.py +136 -0
- telegrinder/client/form_data.py +34 -0
- telegrinder/client/rnet.py +198 -0
- telegrinder/model.py +133 -0
- telegrinder/model.pyi +57 -0
- telegrinder/modules.py +1081 -0
- telegrinder/msgspec_utils/__init__.py +42 -0
- telegrinder/msgspec_utils/abc.py +16 -0
- telegrinder/msgspec_utils/custom_types/__init__.py +6 -0
- telegrinder/msgspec_utils/custom_types/datetime.py +24 -0
- telegrinder/msgspec_utils/custom_types/enum_meta.py +61 -0
- telegrinder/msgspec_utils/custom_types/literal.py +25 -0
- telegrinder/msgspec_utils/custom_types/option.py +17 -0
- telegrinder/msgspec_utils/decoder.py +388 -0
- telegrinder/msgspec_utils/encoder.py +204 -0
- telegrinder/msgspec_utils/json.py +15 -0
- telegrinder/msgspec_utils/tools.py +80 -0
- telegrinder/node/__init__.py +80 -0
- telegrinder/node/compose.py +193 -0
- telegrinder/node/nodes/__init__.py +96 -0
- telegrinder/node/nodes/attachment.py +169 -0
- telegrinder/node/nodes/callback_query.py +25 -0
- telegrinder/node/nodes/channel.py +97 -0
- telegrinder/node/nodes/command.py +33 -0
- telegrinder/node/nodes/error.py +43 -0
- telegrinder/node/nodes/event.py +70 -0
- telegrinder/node/nodes/file.py +39 -0
- telegrinder/node/nodes/global_node.py +66 -0
- telegrinder/node/nodes/i18n.py +110 -0
- telegrinder/node/nodes/me.py +26 -0
- telegrinder/node/nodes/message_entities.py +15 -0
- telegrinder/node/nodes/payload.py +84 -0
- telegrinder/node/nodes/reply_message.py +14 -0
- telegrinder/node/nodes/source.py +172 -0
- telegrinder/node/nodes/state_mutator.py +71 -0
- telegrinder/node/nodes/text.py +62 -0
- telegrinder/node/scope.py +88 -0
- telegrinder/node/utils.py +38 -0
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +1 -0
- telegrinder/tools/__init__.py +183 -0
- telegrinder/tools/aio.py +147 -0
- telegrinder/tools/final.py +21 -0
- telegrinder/tools/formatting/__init__.py +85 -0
- telegrinder/tools/formatting/deep_links/__init__.py +39 -0
- telegrinder/tools/formatting/deep_links/links.py +468 -0
- telegrinder/tools/formatting/deep_links/parsing.py +88 -0
- telegrinder/tools/formatting/deep_links/validators.py +8 -0
- telegrinder/tools/formatting/html.py +241 -0
- telegrinder/tools/fullname.py +82 -0
- telegrinder/tools/global_context/__init__.py +13 -0
- telegrinder/tools/global_context/abc.py +63 -0
- telegrinder/tools/global_context/builtin_context.py +45 -0
- telegrinder/tools/global_context/global_context.py +614 -0
- telegrinder/tools/input_file_directory.py +30 -0
- telegrinder/tools/keyboard/__init__.py +6 -0
- telegrinder/tools/keyboard/abc.py +84 -0
- telegrinder/tools/keyboard/base.py +108 -0
- telegrinder/tools/keyboard/button.py +181 -0
- telegrinder/tools/keyboard/data.py +31 -0
- telegrinder/tools/keyboard/keyboard.py +160 -0
- telegrinder/tools/keyboard/utils.py +95 -0
- telegrinder/tools/lifespan.py +188 -0
- telegrinder/tools/limited_dict.py +35 -0
- telegrinder/tools/loop_wrapper.py +271 -0
- telegrinder/tools/magic/__init__.py +29 -0
- telegrinder/tools/magic/annotations.py +172 -0
- telegrinder/tools/magic/descriptors.py +57 -0
- telegrinder/tools/magic/function.py +254 -0
- telegrinder/tools/magic/inspect.py +16 -0
- telegrinder/tools/magic/shortcut.py +107 -0
- telegrinder/tools/member_descriptor_proxy.py +95 -0
- telegrinder/tools/parse_mode.py +12 -0
- telegrinder/tools/serialization/__init__.py +5 -0
- telegrinder/tools/serialization/abc.py +34 -0
- telegrinder/tools/serialization/json_ser.py +60 -0
- telegrinder/tools/serialization/msgpack_ser.py +197 -0
- telegrinder/tools/serialization/utils.py +18 -0
- telegrinder/tools/singleton/__init__.py +4 -0
- telegrinder/tools/singleton/abc.py +14 -0
- telegrinder/tools/singleton/singleton.py +18 -0
- telegrinder/tools/state_mutator/__init__.py +4 -0
- telegrinder/tools/state_mutator/mutation.py +85 -0
- telegrinder/tools/state_storage/__init__.py +4 -0
- telegrinder/tools/state_storage/abc.py +38 -0
- telegrinder/tools/state_storage/memory.py +27 -0
- telegrinder/tools/strings.py +22 -0
- telegrinder/types/__init__.py +323 -0
- telegrinder/types/enums.py +754 -0
- telegrinder/types/input_file.py +51 -0
- telegrinder/types/methods.py +6143 -0
- telegrinder/types/methods_utils.py +66 -0
- telegrinder/types/objects.py +8184 -0
- telegrinder/types/webapp.py +129 -0
- telegrinder/verification_utils.py +35 -0
- telegrinder-1.0.0rc1.dist-info/METADATA +166 -0
- telegrinder-1.0.0rc1.dist-info/RECORD +215 -0
- telegrinder-1.0.0rc1.dist-info/WHEEL +4 -0
- telegrinder-1.0.0rc1.dist-info/licenses/LICENSE +22 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import html
|
|
3
|
+
import types
|
|
4
|
+
import typing
|
|
5
|
+
from string.templatelib import Template
|
|
6
|
+
|
|
7
|
+
from telegrinder.tools.formatting.deep_links.links import tg_mention_link
|
|
8
|
+
from telegrinder.tools.parse_mode import ParseMode
|
|
9
|
+
|
|
10
|
+
type FormatString = object | Template
|
|
11
|
+
type Formatter = typing.Callable[[FormatString], TagFormat]
|
|
12
|
+
|
|
13
|
+
TAG_FORMAT: typing.Final = "<{tag}{data}>{content}</{tag}>"
|
|
14
|
+
UNION_SPECIFIERS_SEPARATOR: typing.Final = "+"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def blockquote(s: FormatString, /, *, expandable: bool = False) -> TagFormat:
|
|
18
|
+
return TagFormat(s, tag=Tag.BLOCK_QUOTE, **dict(expandable=None) if expandable is True else dict())
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def bold(s: FormatString, /) -> TagFormat:
|
|
22
|
+
return TagFormat(s, tag=Tag.BOLD)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def code_inline(s: FormatString, /) -> TagFormat:
|
|
26
|
+
return TagFormat(s, tag=Tag.CODE)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def expandable_blockquote(s: FormatString, /) -> TagFormat:
|
|
30
|
+
return blockquote(s, expandable=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
monospace = code_inline
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def italic(s: FormatString, /) -> TagFormat:
|
|
37
|
+
return TagFormat(s, tag=Tag.ITALIC)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def link(href: FormatString, /, *, text: str | None = None) -> TagFormat:
|
|
41
|
+
return TagFormat(
|
|
42
|
+
text or href,
|
|
43
|
+
tag=Tag.HYPERLINK,
|
|
44
|
+
href=f'"{href}"',
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def pre_code(s: FormatString, /, *, lang: str | None = None) -> TagFormat:
|
|
49
|
+
if not lang:
|
|
50
|
+
return TagFormat(s, tag=Tag.PRE)
|
|
51
|
+
return pre_code(TagFormat(s, tag=Tag.CODE, **{"class": f"language-{lang}"}))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def spoiler(s: FormatString, /) -> TagFormat:
|
|
55
|
+
return TagFormat(s, tag=Tag.SPOILER)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def strike(s: FormatString, /) -> TagFormat:
|
|
59
|
+
return TagFormat(s, tag=Tag.STRIKE)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def mention(s: FormatString, /, *, user_id: int) -> TagFormat:
|
|
63
|
+
text = escape(s) if isinstance(s, Template) else str(s)
|
|
64
|
+
return link(tg_mention_link(user_id=user_id), text=text)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def tg_emoji(s: FormatString, /, *, emoji_id: int) -> TagFormat:
|
|
68
|
+
return TagFormat(s, tag=Tag.EMOJI, emoji_id=emoji_id)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def underline(s: FormatString, /) -> TagFormat:
|
|
72
|
+
return TagFormat(s, tag=Tag.UNDERLINE)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _apply_formats(value: typing.Any, format_spec: str | None = None) -> str:
|
|
76
|
+
if not format_spec:
|
|
77
|
+
return html.escape(str(value))
|
|
78
|
+
|
|
79
|
+
result: FormatString = html.escape(str(value))
|
|
80
|
+
|
|
81
|
+
for fmt in (f.strip() for f in format_spec.split(UNION_SPECIFIERS_SEPARATOR)):
|
|
82
|
+
if fmt in FORMATTERS:
|
|
83
|
+
result = FORMATTERS[fmt](result)
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError(f"Unknown format: `{fmt}`")
|
|
86
|
+
|
|
87
|
+
return result.formatting() if isinstance(result, TagFormat) else result
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def escape(s: FormatString, /) -> str:
|
|
91
|
+
if isinstance(s, Template):
|
|
92
|
+
parts: list[str] = []
|
|
93
|
+
|
|
94
|
+
for item in s:
|
|
95
|
+
if isinstance(item, str):
|
|
96
|
+
parts.append(html.escape(item))
|
|
97
|
+
else:
|
|
98
|
+
value = item.value
|
|
99
|
+
|
|
100
|
+
if isinstance(value, TagFormat):
|
|
101
|
+
parts.append(value.formatting())
|
|
102
|
+
elif item.format_spec:
|
|
103
|
+
parts.append(_apply_formats(value, item.format_spec))
|
|
104
|
+
else:
|
|
105
|
+
parts.append(html.escape(str(value)))
|
|
106
|
+
|
|
107
|
+
return "".join(parts)
|
|
108
|
+
|
|
109
|
+
return html.escape(str(s))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class HTMLMeta(type):
|
|
113
|
+
def __lshift__[T](cls: typing.Callable[..., T], other: object, /) -> T:
|
|
114
|
+
if not isinstance(other, str | Template | TagFormat):
|
|
115
|
+
return NotImplemented
|
|
116
|
+
return cls(other)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Tag(enum.StrEnum):
|
|
120
|
+
HYPERLINK = "a"
|
|
121
|
+
BOLD = "b"
|
|
122
|
+
ITALIC = "i"
|
|
123
|
+
UNDERLINE = "u"
|
|
124
|
+
STRIKE = "s"
|
|
125
|
+
CODE = "code"
|
|
126
|
+
PRE = "pre"
|
|
127
|
+
SPOILER = "tg-spoiler"
|
|
128
|
+
BLOCK_QUOTE = "blockquote"
|
|
129
|
+
EMOJI = "tg-emoji"
|
|
130
|
+
|
|
131
|
+
def __str__(self) -> str:
|
|
132
|
+
return self.value
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class TagFormat(str):
|
|
136
|
+
__slots__ = ("data", "tag")
|
|
137
|
+
|
|
138
|
+
tag: Tag
|
|
139
|
+
data: dict[str, typing.Any]
|
|
140
|
+
|
|
141
|
+
def __new__(cls, s: FormatString, /, *, tag: Tag, **data: typing.Any) -> typing.Self:
|
|
142
|
+
s = escape(s) if not isinstance(s, TagFormat) else s.formatting()
|
|
143
|
+
obj = super().__new__(cls, s)
|
|
144
|
+
obj.data = data
|
|
145
|
+
obj.tag = tag
|
|
146
|
+
return obj
|
|
147
|
+
|
|
148
|
+
def __str__(self) -> str:
|
|
149
|
+
return self.formatting()
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def content(self) -> str:
|
|
153
|
+
return super().__str__()
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def tag_data(self) -> str:
|
|
157
|
+
return "".join(f" {k}={v}" if v is not None else f" {k}" for k, v in self.data.items())
|
|
158
|
+
|
|
159
|
+
def formatting(self) -> str:
|
|
160
|
+
return TAG_FORMAT.format(
|
|
161
|
+
tag=self.tag,
|
|
162
|
+
data=self.tag_data,
|
|
163
|
+
content=self.content,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class HTML(str, metaclass=HTMLMeta):
|
|
168
|
+
"""A class for creating and formatting HTML strings.
|
|
169
|
+
|
|
170
|
+
>>> HTML << "Hello, " << bold("World!")
|
|
171
|
+
'Hello, <b>World!</b>'
|
|
172
|
+
|
|
173
|
+
>>> HTML << t"Hello, {name:underline}! " << "You are <b>{age}</b> years old."
|
|
174
|
+
'Hello, <u>Arseny</u>! You are <b>20</b> years old.'
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
PARSE_MODE: typing.Final = ParseMode.HTML
|
|
178
|
+
|
|
179
|
+
__slots__ = ()
|
|
180
|
+
|
|
181
|
+
def __new__(cls, s: str | Template | TagFormat, /) -> typing.Self:
|
|
182
|
+
if isinstance(s, Template):
|
|
183
|
+
content = escape(s)
|
|
184
|
+
elif isinstance(s, TagFormat):
|
|
185
|
+
content = s.formatting()
|
|
186
|
+
else:
|
|
187
|
+
content = s
|
|
188
|
+
|
|
189
|
+
return super().__new__(cls, content)
|
|
190
|
+
|
|
191
|
+
def __lshift__(self, other: object, /) -> typing.Self:
|
|
192
|
+
if isinstance(other, TagFormat):
|
|
193
|
+
addition = other.formatting()
|
|
194
|
+
elif isinstance(other, Template):
|
|
195
|
+
addition = escape(other)
|
|
196
|
+
else:
|
|
197
|
+
addition = str(other)
|
|
198
|
+
|
|
199
|
+
return self.__class__.__new__(self.__class__, self + addition)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
FORMATTERS: types.MappingProxyType[str, Formatter] = types.MappingProxyType(
|
|
203
|
+
mapping=dict(
|
|
204
|
+
bold=bold,
|
|
205
|
+
b=bold,
|
|
206
|
+
code=code_inline,
|
|
207
|
+
c=code_inline,
|
|
208
|
+
monospace=monospace,
|
|
209
|
+
italic=italic,
|
|
210
|
+
i=italic,
|
|
211
|
+
spoiler=spoiler,
|
|
212
|
+
sp=spoiler,
|
|
213
|
+
strike=strike,
|
|
214
|
+
s=strike,
|
|
215
|
+
underline=underline,
|
|
216
|
+
u=underline,
|
|
217
|
+
blockquote=blockquote,
|
|
218
|
+
expandable_blockquote=expandable_blockquote,
|
|
219
|
+
),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
__all__ = (
|
|
224
|
+
"HTML",
|
|
225
|
+
"Tag",
|
|
226
|
+
"TagFormat",
|
|
227
|
+
"blockquote",
|
|
228
|
+
"bold",
|
|
229
|
+
"code_inline",
|
|
230
|
+
"escape",
|
|
231
|
+
"expandable_blockquote",
|
|
232
|
+
"italic",
|
|
233
|
+
"link",
|
|
234
|
+
"mention",
|
|
235
|
+
"monospace",
|
|
236
|
+
"pre_code",
|
|
237
|
+
"spoiler",
|
|
238
|
+
"strike",
|
|
239
|
+
"tg_emoji",
|
|
240
|
+
"underline",
|
|
241
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import builtins
|
|
2
|
+
import inspect
|
|
3
|
+
import os.path
|
|
4
|
+
import sys
|
|
5
|
+
import types
|
|
6
|
+
import typing
|
|
7
|
+
|
|
8
|
+
type RoutineMethodType = (
|
|
9
|
+
types.MethodType | types.MethodDescriptorType | types.MethodWrapperType | types.BuiltinMethodType
|
|
10
|
+
)
|
|
11
|
+
type RoutineDescriptorType = types.MethodDescriptorType | types.GetSetDescriptorType
|
|
12
|
+
|
|
13
|
+
_BUILTINS: typing.Final[frozenset[typing.Any]] = frozenset(
|
|
14
|
+
x for name in dir(builtins) if getattr((x := getattr(builtins, name)), "__module__", None) == "builtins"
|
|
15
|
+
)
|
|
16
|
+
_CACHE_KEY: typing.Final = "__fullname_cache__"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _is_builtin(obj: typing.Any, /) -> bool:
|
|
20
|
+
return inspect.isbuiltin(obj) or obj in _BUILTINS
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _is_routine_method(obj: typing.Any, /) -> typing.TypeIs[RoutineMethodType]:
|
|
24
|
+
return inspect.isbuiltin(obj) or inspect.ismethod(obj) or inspect.ismethodwrapper(obj)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _is_routine_descriptor(obj: typing.Any, /) -> typing.TypeIs[RoutineDescriptorType]:
|
|
28
|
+
return inspect.ismethoddescriptor(obj) or inspect.isgetsetdescriptor(obj)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _module_name(module: types.ModuleType, /) -> str:
|
|
32
|
+
if (mod_name := module.__name__) != "__main__":
|
|
33
|
+
return mod_name
|
|
34
|
+
|
|
35
|
+
mod_package = module.__package__ or ""
|
|
36
|
+
mod_file = module.__file__
|
|
37
|
+
if mod_file is None:
|
|
38
|
+
return mod_package
|
|
39
|
+
|
|
40
|
+
mod_fname = os.path.basename(mod_file).removesuffix(".py")
|
|
41
|
+
return mod_package if mod_package in ("__init__", "__main__") else mod_fname
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def fullname(obj: object, /) -> str:
|
|
45
|
+
"""The full name (`__module__.__name__`) of the object."""
|
|
46
|
+
|
|
47
|
+
if isinstance(obj, staticmethod | classmethod):
|
|
48
|
+
obj = obj.__func__
|
|
49
|
+
|
|
50
|
+
elif (
|
|
51
|
+
not inspect.isroutine(obj)
|
|
52
|
+
and not inspect.isgetsetdescriptor(obj)
|
|
53
|
+
and not isinstance(obj, type)
|
|
54
|
+
and not inspect.ismodule(obj)
|
|
55
|
+
):
|
|
56
|
+
obj = type(obj)
|
|
57
|
+
|
|
58
|
+
if (name := fullname.__dict__.setdefault(_CACHE_KEY, dict()).get(obj)) is not None:
|
|
59
|
+
return name
|
|
60
|
+
|
|
61
|
+
if inspect.ismodule(obj):
|
|
62
|
+
fullname.__dict__[_CACHE_KEY][obj] = name = _module_name(obj)
|
|
63
|
+
return name
|
|
64
|
+
|
|
65
|
+
qualname = obj.__qualname__
|
|
66
|
+
orig_obj = obj
|
|
67
|
+
|
|
68
|
+
if _is_routine_method(obj) or _is_routine_descriptor(obj):
|
|
69
|
+
obj_cls = obj.__objclass__ if _is_routine_descriptor(obj) else obj.__self__
|
|
70
|
+
obj = type(obj_cls) if not isinstance(obj_cls, type) else obj_cls
|
|
71
|
+
|
|
72
|
+
module: str = getattr(orig_obj, "__module__", None) or obj.__module__
|
|
73
|
+
if _is_builtin(obj) and module != builtins.__name__:
|
|
74
|
+
module = builtins.__name__
|
|
75
|
+
else:
|
|
76
|
+
module = _module_name(sys.modules[module])
|
|
77
|
+
|
|
78
|
+
fullname.__dict__[_CACHE_KEY][orig_obj] = name = ".".join((module, qualname))
|
|
79
|
+
return name
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
__all__ = ("fullname",)
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"ABCGlobalContext",
|
|
7
|
+
"CtxVar",
|
|
8
|
+
"GlobalContext",
|
|
9
|
+
"GlobalCtxVar",
|
|
10
|
+
"TelegrinderContext",
|
|
11
|
+
"ctx_var",
|
|
12
|
+
"runtime_init",
|
|
13
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
type CtxVariable[T = typing.Any] = CtxVar[T] | GlobalCtxVar[T]
|
|
6
|
+
|
|
7
|
+
NOVALUE: typing.Final = object()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclasses.dataclass(frozen=True)
|
|
11
|
+
class CtxVar[T = typing.Any]:
|
|
12
|
+
value: T
|
|
13
|
+
factory: typing.Any = dataclasses.field(default=NOVALUE, kw_only=True)
|
|
14
|
+
const: bool = dataclasses.field(default=False, kw_only=True)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclasses.dataclass(repr=False, frozen=True)
|
|
18
|
+
class GlobalCtxVar[T = typing.Any](CtxVar[T]):
|
|
19
|
+
name: str
|
|
20
|
+
value: T
|
|
21
|
+
factory: typing.Any = dataclasses.field(default=NOVALUE, kw_only=True)
|
|
22
|
+
const: bool = dataclasses.field(default=False, kw_only=True)
|
|
23
|
+
|
|
24
|
+
def __repr__(self) -> str:
|
|
25
|
+
return "<{}({}={})>".format(
|
|
26
|
+
type(self).__name__,
|
|
27
|
+
self.name,
|
|
28
|
+
repr(CtxVar(self.value, const=self.const, factory=self.factory)),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_var(
|
|
33
|
+
cls,
|
|
34
|
+
name: str,
|
|
35
|
+
ctx_value: T | CtxVariable[T],
|
|
36
|
+
const: bool = False,
|
|
37
|
+
) -> typing.Self:
|
|
38
|
+
var = CtxVar(ctx_value, const=const) if not isinstance(ctx_value, CtxVar | GlobalCtxVar) else ctx_value
|
|
39
|
+
if var.value is NOVALUE and var.factory is not NOVALUE:
|
|
40
|
+
var = dataclasses.replace(var, value=var.factory())
|
|
41
|
+
return cls(**dict(var.__dict__) | dict(name=name))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ABCGlobalContext[T = typing.Any](ABC):
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def __getattr__(self, __name: str) -> typing.Any:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def __setattr__(self, __name: str, __value: T | CtxVariable[T]) -> None:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def __delattr__(self, __name: str) -> None:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
__all__ = (
|
|
59
|
+
"ABCGlobalContext",
|
|
60
|
+
"CtxVar",
|
|
61
|
+
"CtxVariable",
|
|
62
|
+
"GlobalCtxVar",
|
|
63
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
from nodnod.scope import Scope
|
|
7
|
+
from vbml.patcher.abc import ABCPatcher
|
|
8
|
+
from vbml.patcher.patcher import Patcher
|
|
9
|
+
|
|
10
|
+
from telegrinder.modules import logger
|
|
11
|
+
from telegrinder.tools.global_context.global_context import GlobalContext, ctx_var, runtime_init
|
|
12
|
+
from telegrinder.tools.loop_wrapper import LoopWrapper
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@runtime_init
|
|
16
|
+
class TelegrinderContext(GlobalContext, thread_safe=True):
|
|
17
|
+
"""The thread-safe type-hinted telegrinder context.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
```
|
|
21
|
+
from telegrinder.tools.global_context import GlobalContext, TelegrinderContext
|
|
22
|
+
|
|
23
|
+
telegrinder_ctx = TelegrinderContext(...) # with type-hints
|
|
24
|
+
assert telegrinder_ctx == GlobalContext("telegrinder") # ok
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
__ctx_name__ = "telegrinder"
|
|
30
|
+
|
|
31
|
+
node_global_scope: typing.Final[Scope] = ctx_var(
|
|
32
|
+
default_factory=lambda: Scope(detail="global"),
|
|
33
|
+
init=False,
|
|
34
|
+
const=True,
|
|
35
|
+
)
|
|
36
|
+
vbml_pattern_flags: re.RegexFlag | None = ctx_var(default=None, init=False)
|
|
37
|
+
vbml_patcher: ABCPatcher = ctx_var(default_factory=Patcher, init=False)
|
|
38
|
+
loop_wrapper: typing.Final[LoopWrapper] = ctx_var(default_factory=LoopWrapper, init=False, const=True)
|
|
39
|
+
|
|
40
|
+
async def close_global_scope(self) -> None:
|
|
41
|
+
await self.node_global_scope.close()
|
|
42
|
+
logger.debug("Node global scope closed")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = ("TelegrinderContext",)
|