telegrinder 0.3.4__py3-none-any.whl → 0.4.0__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 +148 -149
- telegrinder/api/__init__.py +9 -8
- telegrinder/api/api.py +101 -93
- telegrinder/api/error.py +20 -16
- telegrinder/api/response.py +20 -20
- telegrinder/api/token.py +36 -36
- telegrinder/bot/__init__.py +72 -66
- telegrinder/bot/bot.py +83 -76
- telegrinder/bot/cute_types/__init__.py +19 -17
- telegrinder/bot/cute_types/base.py +184 -258
- telegrinder/bot/cute_types/callback_query.py +400 -385
- telegrinder/bot/cute_types/chat_join_request.py +62 -61
- telegrinder/bot/cute_types/chat_member_updated.py +157 -160
- telegrinder/bot/cute_types/inline_query.py +44 -43
- telegrinder/bot/cute_types/message.py +2590 -2637
- telegrinder/bot/cute_types/pre_checkout_query.py +42 -0
- telegrinder/bot/cute_types/update.py +112 -104
- telegrinder/bot/cute_types/utils.py +62 -95
- telegrinder/bot/dispatch/__init__.py +59 -55
- telegrinder/bot/dispatch/abc.py +76 -77
- telegrinder/bot/dispatch/context.py +96 -98
- telegrinder/bot/dispatch/dispatch.py +254 -202
- telegrinder/bot/dispatch/handler/__init__.py +13 -13
- telegrinder/bot/dispatch/handler/abc.py +23 -24
- telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
- telegrinder/bot/dispatch/handler/base.py +57 -57
- telegrinder/bot/dispatch/handler/document_reply.py +44 -44
- telegrinder/bot/dispatch/handler/func.py +129 -135
- telegrinder/bot/dispatch/handler/media_group_reply.py +44 -43
- telegrinder/bot/dispatch/handler/message_reply.py +36 -36
- telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
- telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
- telegrinder/bot/dispatch/handler/video_reply.py +44 -44
- telegrinder/bot/dispatch/middleware/__init__.py +3 -3
- telegrinder/bot/dispatch/middleware/abc.py +97 -22
- telegrinder/bot/dispatch/middleware/global_middleware.py +70 -0
- telegrinder/bot/dispatch/process.py +151 -157
- telegrinder/bot/dispatch/return_manager/__init__.py +15 -13
- telegrinder/bot/dispatch/return_manager/abc.py +104 -108
- telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
- telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
- telegrinder/bot/dispatch/return_manager/message.py +36 -36
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +20 -0
- telegrinder/bot/dispatch/view/__init__.py +15 -13
- telegrinder/bot/dispatch/view/abc.py +45 -41
- telegrinder/bot/dispatch/view/base.py +231 -200
- telegrinder/bot/dispatch/view/box.py +140 -129
- telegrinder/bot/dispatch/view/callback_query.py +16 -17
- telegrinder/bot/dispatch/view/chat_join_request.py +11 -16
- telegrinder/bot/dispatch/view/chat_member.py +37 -39
- telegrinder/bot/dispatch/view/inline_query.py +16 -17
- telegrinder/bot/dispatch/view/message.py +43 -44
- telegrinder/bot/dispatch/view/pre_checkout_query.py +16 -0
- telegrinder/bot/dispatch/view/raw.py +116 -114
- telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
- telegrinder/bot/dispatch/waiter_machine/actions.py +14 -13
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +59 -57
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +20 -19
- telegrinder/bot/dispatch/waiter_machine/machine.py +251 -172
- telegrinder/bot/dispatch/waiter_machine/middleware.py +94 -89
- telegrinder/bot/dispatch/waiter_machine/short_state.py +57 -68
- telegrinder/bot/polling/__init__.py +4 -4
- telegrinder/bot/polling/abc.py +25 -25
- telegrinder/bot/polling/polling.py +139 -131
- telegrinder/bot/rules/__init__.py +85 -62
- telegrinder/bot/rules/abc.py +213 -206
- telegrinder/bot/rules/callback_data.py +122 -163
- telegrinder/bot/rules/chat_join.py +45 -43
- telegrinder/bot/rules/command.py +126 -126
- telegrinder/bot/rules/enum_text.py +33 -36
- telegrinder/bot/rules/func.py +28 -26
- telegrinder/bot/rules/fuzzy.py +24 -24
- telegrinder/bot/rules/id.py +24 -0
- telegrinder/bot/rules/inline.py +58 -56
- telegrinder/bot/rules/integer.py +21 -20
- telegrinder/bot/rules/is_from.py +127 -127
- telegrinder/bot/rules/logic.py +18 -0
- telegrinder/bot/rules/markup.py +42 -43
- telegrinder/bot/rules/mention.py +14 -14
- telegrinder/bot/rules/message.py +15 -17
- telegrinder/bot/rules/message_entities.py +33 -35
- telegrinder/bot/rules/node.py +33 -27
- telegrinder/bot/rules/payload.py +81 -0
- telegrinder/bot/rules/payment_invoice.py +29 -0
- telegrinder/bot/rules/regex.py +36 -37
- telegrinder/bot/rules/rule_enum.py +72 -72
- telegrinder/bot/rules/start.py +42 -42
- telegrinder/bot/rules/state.py +35 -37
- telegrinder/bot/rules/text.py +38 -33
- telegrinder/bot/rules/update.py +15 -15
- telegrinder/bot/scenario/__init__.py +5 -5
- telegrinder/bot/scenario/abc.py +17 -19
- telegrinder/bot/scenario/checkbox.py +174 -176
- telegrinder/bot/scenario/choice.py +48 -51
- telegrinder/client/__init__.py +12 -4
- telegrinder/client/abc.py +100 -75
- telegrinder/client/aiohttp.py +134 -130
- telegrinder/client/form_data.py +31 -0
- telegrinder/client/sonic.py +212 -0
- telegrinder/model.py +208 -315
- telegrinder/modules.py +239 -237
- telegrinder/msgspec_json.py +14 -14
- telegrinder/msgspec_utils.py +478 -410
- telegrinder/node/__init__.py +86 -25
- telegrinder/node/attachment.py +163 -87
- telegrinder/node/base.py +288 -160
- telegrinder/node/callback_query.py +54 -53
- telegrinder/node/command.py +34 -33
- telegrinder/node/composer.py +163 -198
- telegrinder/node/container.py +33 -27
- telegrinder/node/either.py +82 -0
- telegrinder/node/event.py +54 -65
- telegrinder/node/file.py +51 -0
- telegrinder/node/me.py +15 -16
- telegrinder/node/payload.py +78 -0
- telegrinder/node/polymorphic.py +67 -48
- telegrinder/node/rule.py +72 -76
- telegrinder/node/scope.py +36 -38
- telegrinder/node/source.py +87 -71
- telegrinder/node/text.py +53 -41
- telegrinder/node/tools/__init__.py +3 -3
- telegrinder/node/tools/generator.py +36 -40
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +1 -62
- telegrinder/tools/__init__.py +152 -93
- telegrinder/tools/adapter/__init__.py +19 -0
- telegrinder/tools/adapter/abc.py +49 -0
- telegrinder/tools/adapter/dataclass.py +56 -0
- telegrinder/{bot/rules → tools}/adapter/errors.py +5 -5
- telegrinder/{bot/rules → tools}/adapter/event.py +63 -65
- telegrinder/{bot/rules → tools}/adapter/node.py +46 -48
- telegrinder/{bot/rules → tools}/adapter/raw_event.py +27 -27
- telegrinder/{bot/rules → tools}/adapter/raw_update.py +30 -30
- telegrinder/tools/buttons.py +106 -80
- telegrinder/tools/callback_data_serilization/__init__.py +5 -0
- telegrinder/tools/callback_data_serilization/abc.py +51 -0
- telegrinder/tools/callback_data_serilization/json_ser.py +60 -0
- telegrinder/tools/callback_data_serilization/msgpack_ser.py +172 -0
- telegrinder/tools/error_handler/__init__.py +7 -7
- telegrinder/tools/error_handler/abc.py +30 -33
- telegrinder/tools/error_handler/error.py +9 -9
- telegrinder/tools/error_handler/error_handler.py +179 -193
- telegrinder/tools/formatting/__init__.py +83 -63
- telegrinder/tools/formatting/deep_links.py +541 -0
- telegrinder/tools/formatting/{html.py → html_formatter.py} +266 -294
- telegrinder/tools/formatting/spec_html_formats.py +71 -117
- telegrinder/tools/functional.py +8 -12
- telegrinder/tools/global_context/__init__.py +7 -7
- telegrinder/tools/global_context/abc.py +63 -63
- telegrinder/tools/global_context/global_context.py +387 -412
- telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
- telegrinder/tools/i18n/__init__.py +7 -7
- telegrinder/tools/i18n/abc.py +30 -30
- telegrinder/tools/i18n/middleware/__init__.py +3 -3
- telegrinder/tools/i18n/middleware/abc.py +22 -25
- telegrinder/tools/i18n/simple.py +43 -43
- telegrinder/tools/input_file_directory.py +30 -0
- telegrinder/tools/keyboard.py +128 -128
- telegrinder/tools/lifespan.py +105 -0
- telegrinder/tools/limited_dict.py +32 -37
- telegrinder/tools/loop_wrapper/__init__.py +4 -4
- telegrinder/tools/loop_wrapper/abc.py +20 -15
- telegrinder/tools/loop_wrapper/loop_wrapper.py +169 -224
- telegrinder/tools/magic.py +307 -157
- telegrinder/tools/parse_mode.py +6 -6
- telegrinder/tools/state_storage/__init__.py +4 -4
- telegrinder/tools/state_storage/abc.py +31 -35
- telegrinder/tools/state_storage/memory.py +25 -25
- telegrinder/tools/strings.py +13 -0
- telegrinder/types/__init__.py +268 -260
- telegrinder/types/enums.py +711 -701
- telegrinder/types/input_file.py +51 -0
- telegrinder/types/methods.py +5055 -4633
- telegrinder/types/objects.py +7058 -6950
- telegrinder/verification_utils.py +30 -32
- {telegrinder-0.3.4.dist-info → telegrinder-0.4.0.dist-info}/LICENSE +22 -22
- telegrinder-0.4.0.dist-info/METADATA +144 -0
- telegrinder-0.4.0.dist-info/RECORD +182 -0
- {telegrinder-0.3.4.dist-info → telegrinder-0.4.0.dist-info}/WHEEL +1 -1
- telegrinder/bot/rules/adapter/__init__.py +0 -17
- telegrinder/bot/rules/adapter/abc.py +0 -31
- telegrinder/node/message.py +0 -14
- telegrinder/node/update.py +0 -15
- telegrinder/tools/formatting/links.py +0 -38
- telegrinder/tools/kb_set/__init__.py +0 -4
- telegrinder/tools/kb_set/base.py +0 -15
- telegrinder/tools/kb_set/yaml.py +0 -63
- telegrinder-0.3.4.dist-info/METADATA +0 -110
- telegrinder-0.3.4.dist-info/RECORD +0 -165
|
@@ -1,258 +1,184 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
exclude_fields:
|
|
50
|
-
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if not cls.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"""
|
|
186
|
-
|
|
187
|
-
default_params = default_params or set()
|
|
188
|
-
validators = validators or {}
|
|
189
|
-
|
|
190
|
-
for param in default_params:
|
|
191
|
-
param_name = param if isinstance(param, str) else param[0]
|
|
192
|
-
if param_name not in params:
|
|
193
|
-
if param_name in validators and not validators[param_name](update):
|
|
194
|
-
continue
|
|
195
|
-
params[param_name] = getattr(update, param if isinstance(param, str) else param[1])
|
|
196
|
-
|
|
197
|
-
return params
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def shortcut(
|
|
201
|
-
method_name: str,
|
|
202
|
-
*,
|
|
203
|
-
executor: Executor[Cute] | None = None,
|
|
204
|
-
custom_params: set[str] | None = None,
|
|
205
|
-
):
|
|
206
|
-
def wrapper(func: F) -> F:
|
|
207
|
-
@wraps(func)
|
|
208
|
-
async def inner(
|
|
209
|
-
self: Cute,
|
|
210
|
-
*args: typing.Any,
|
|
211
|
-
**kwargs: typing.Any,
|
|
212
|
-
) -> typing.Any:
|
|
213
|
-
if executor is None:
|
|
214
|
-
return await func(self, *args, **kwargs)
|
|
215
|
-
|
|
216
|
-
if not hasattr(func, "_signature_params"):
|
|
217
|
-
setattr(
|
|
218
|
-
func,
|
|
219
|
-
"_signature_params",
|
|
220
|
-
{k: p for k, p in inspect.signature(func).parameters.items() if k != "self"},
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
signature_params: dict[str, inspect.Parameter] = getattr(func, "_signature_params")
|
|
224
|
-
params: dict[str, typing.Any] = {}
|
|
225
|
-
index = 0
|
|
226
|
-
|
|
227
|
-
for k, p in signature_params.items():
|
|
228
|
-
if p.kind in (p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY) and len(args) > index:
|
|
229
|
-
params[k] = args[index]
|
|
230
|
-
index += 1
|
|
231
|
-
continue
|
|
232
|
-
|
|
233
|
-
if p.kind in (p.VAR_KEYWORD, p.VAR_POSITIONAL):
|
|
234
|
-
params[k] = kwargs.copy() if p.kind is p.VAR_KEYWORD else args[index:]
|
|
235
|
-
continue
|
|
236
|
-
|
|
237
|
-
params[k] = kwargs.pop(k, p.default) if p.default is not p.empty else kwargs.pop(k)
|
|
238
|
-
|
|
239
|
-
return await executor(self, method_name, get_params(params))
|
|
240
|
-
|
|
241
|
-
inner.__shortcut__ = Shortcut( # type: ignore
|
|
242
|
-
method_name=method_name,
|
|
243
|
-
executor=executor,
|
|
244
|
-
custom_params=custom_params or set(),
|
|
245
|
-
)
|
|
246
|
-
return inner # type: ignore
|
|
247
|
-
|
|
248
|
-
return wrapper
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
@dataclasses.dataclass(slots=True, frozen=True)
|
|
252
|
-
class Shortcut:
|
|
253
|
-
method_name: str
|
|
254
|
-
executor: Executor | None = dataclasses.field(default=None, kw_only=True)
|
|
255
|
-
custom_params: set[str] = dataclasses.field(default_factory=lambda: set(), kw_only=True)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
__all__ = ("BaseCute", "Shortcut", "compose_method_params", "shortcut")
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
import msgspec
|
|
4
|
+
|
|
5
|
+
from telegrinder.api.api import API
|
|
6
|
+
from telegrinder.model import Model, is_none
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def compose_method_params[Cute: BaseCute](
|
|
10
|
+
params: dict[str, typing.Any],
|
|
11
|
+
update: Cute,
|
|
12
|
+
*,
|
|
13
|
+
default_params: set[str | tuple[str, str]] | None = None,
|
|
14
|
+
validators: dict[str, typing.Callable[[Cute], bool]] | None = None,
|
|
15
|
+
) -> dict[str, typing.Any]:
|
|
16
|
+
default_params = default_params or set()
|
|
17
|
+
validators = validators or {}
|
|
18
|
+
|
|
19
|
+
for param in default_params:
|
|
20
|
+
param_name = param if isinstance(param, str) else param[0]
|
|
21
|
+
if param_name not in params:
|
|
22
|
+
if param_name in validators and not validators[param_name](update):
|
|
23
|
+
continue
|
|
24
|
+
params[param_name] = getattr(update, param if isinstance(param, str) else param[1])
|
|
25
|
+
|
|
26
|
+
return params
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if typing.TYPE_CHECKING:
|
|
30
|
+
from telegrinder.node.base import Node
|
|
31
|
+
|
|
32
|
+
class BaseCute[Update: Model](Model):
|
|
33
|
+
api: API
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def as_node(cls) -> type[Node]: ...
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_update(cls, update: Update, bound_api: API) -> typing.Self: ...
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def ctx_api(self) -> API: ...
|
|
43
|
+
|
|
44
|
+
def to_dict(
|
|
45
|
+
self,
|
|
46
|
+
*,
|
|
47
|
+
exclude_fields: set[str] | None = None,
|
|
48
|
+
) -> dict[str, typing.Any]:
|
|
49
|
+
""":param exclude_fields: Cute model field names to exclude from the dictionary representation of this cute model.
|
|
50
|
+
:return: A dictionary representation of this cute model.
|
|
51
|
+
"""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
def to_full_dict(
|
|
55
|
+
self,
|
|
56
|
+
*,
|
|
57
|
+
exclude_fields: set[str] | None = None,
|
|
58
|
+
) -> dict[str, typing.Any]:
|
|
59
|
+
""":param exclude_fields: Cute model field names to exclude from the dictionary representation of this cute model.
|
|
60
|
+
:return: A dictionary representation of this model including all models, structs, custom types.
|
|
61
|
+
"""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
else:
|
|
65
|
+
import msgspec
|
|
66
|
+
from fntypes.co import Nothing, Some, Variative
|
|
67
|
+
|
|
68
|
+
from telegrinder.msgspec_utils import Option, decoder, encoder, struct_as_dict
|
|
69
|
+
from telegrinder.msgspec_utils import get_class_annotations as _get_class_annotations
|
|
70
|
+
|
|
71
|
+
def _get_cute_from_generic(generic_args, /):
|
|
72
|
+
for arg in generic_args:
|
|
73
|
+
orig_arg = typing.get_origin(arg) or arg
|
|
74
|
+
|
|
75
|
+
if not isinstance(orig_arg, type):
|
|
76
|
+
continue
|
|
77
|
+
if orig_arg in (Variative, Some, Option):
|
|
78
|
+
return _get_cute_from_generic(typing.get_args(arg))
|
|
79
|
+
if issubclass(arg, BaseCute):
|
|
80
|
+
return arg
|
|
81
|
+
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
def _get_cute_annotations(annotations, /):
|
|
85
|
+
cute_annotations = {}
|
|
86
|
+
|
|
87
|
+
for key, hint in annotations.items():
|
|
88
|
+
if not isinstance(hint, type):
|
|
89
|
+
if (cute := _get_cute_from_generic(typing.get_args(hint))) is not None:
|
|
90
|
+
cute_annotations[key] = cute
|
|
91
|
+
|
|
92
|
+
elif issubclass(hint, BaseCute):
|
|
93
|
+
cute_annotations[key] = hint
|
|
94
|
+
|
|
95
|
+
return cute_annotations
|
|
96
|
+
|
|
97
|
+
def _validate_value(value, /):
|
|
98
|
+
while isinstance(value, Variative | Some):
|
|
99
|
+
if isinstance(value, Variative):
|
|
100
|
+
value = value.v
|
|
101
|
+
if isinstance(value, Some):
|
|
102
|
+
value = value.value
|
|
103
|
+
return value
|
|
104
|
+
|
|
105
|
+
class BaseCute[Update]:
|
|
106
|
+
api: API
|
|
107
|
+
|
|
108
|
+
def __init_subclass__(cls, *args, **kwargs):
|
|
109
|
+
super().__init_subclass__(*args, **kwargs)
|
|
110
|
+
|
|
111
|
+
if not cls.__bases__ or not issubclass(cls.__bases__[0], BaseCute):
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
cls.__is_solved_annotations__ = False
|
|
115
|
+
cls.__cute_annotations__ = None
|
|
116
|
+
cls.__event_node__ = None
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def as_node(cls):
|
|
120
|
+
if cls.__event_node__ is None:
|
|
121
|
+
from telegrinder.node.event import _EventNode
|
|
122
|
+
|
|
123
|
+
cls.__event_node__ = _EventNode[cls]
|
|
124
|
+
return cls.__event_node__
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
def from_update(cls, update, bound_api):
|
|
128
|
+
if not cls.__is_solved_annotations__:
|
|
129
|
+
cls.__is_solved_annotations__ = True
|
|
130
|
+
cls.__annotations__ = _get_class_annotations(cls)
|
|
131
|
+
|
|
132
|
+
if cls.__cute_annotations__ is None:
|
|
133
|
+
cls.__cute_annotations__ = _get_cute_annotations(cls.__annotations__)
|
|
134
|
+
|
|
135
|
+
return cls(
|
|
136
|
+
**{
|
|
137
|
+
field: decoder.convert(
|
|
138
|
+
cls.__cute_annotations__[field].from_update(_validate_value(value), bound_api=bound_api),
|
|
139
|
+
type=cls.__annotations__[field],
|
|
140
|
+
)
|
|
141
|
+
if field in cls.__cute_annotations__ and not isinstance(value, Nothing | msgspec.UnsetType)
|
|
142
|
+
else value
|
|
143
|
+
for field, value in update.to_dict().items()
|
|
144
|
+
},
|
|
145
|
+
api=bound_api,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def ctx_api(self):
|
|
150
|
+
return self.api
|
|
151
|
+
|
|
152
|
+
def _to_dict(self, dct_name, exclude_fields, full):
|
|
153
|
+
if dct_name not in self.__dict__:
|
|
154
|
+
self.__dict__[dct_name] = (
|
|
155
|
+
struct_as_dict(self)
|
|
156
|
+
if not full
|
|
157
|
+
else encoder.to_builtins(
|
|
158
|
+
{
|
|
159
|
+
k: field.to_dict(exclude_fields=exclude_fields)
|
|
160
|
+
if isinstance(field, BaseCute)
|
|
161
|
+
else field
|
|
162
|
+
for k in self.__struct_fields__
|
|
163
|
+
if k not in exclude_fields
|
|
164
|
+
and not isinstance(field := _validate_value(getattr(self, k)), msgspec.UnsetType)
|
|
165
|
+
and not is_none(field)
|
|
166
|
+
},
|
|
167
|
+
order="deterministic",
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if not exclude_fields:
|
|
172
|
+
return self.__dict__[dct_name]
|
|
173
|
+
|
|
174
|
+
return {key: value for key, value in self.__dict__[dct_name].items() if key not in exclude_fields}
|
|
175
|
+
|
|
176
|
+
def to_dict(self, *, exclude_fields=None, full=False):
|
|
177
|
+
exclude_fields = exclude_fields or set()
|
|
178
|
+
return self._to_dict("model_as_dict", exclude_fields={"api"} | exclude_fields, full=full)
|
|
179
|
+
|
|
180
|
+
def to_full_dict(self, *, exclude_fields=None):
|
|
181
|
+
return self.to_dict(exclude_fields=exclude_fields, full=True)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
__all__ = ("BaseCute", "compose_method_params")
|