telegrinder 0.4.2__py3-none-any.whl → 0.5.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 +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 +2621 -2590
- 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 +64 -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 +7846 -7058
- telegrinder/verification_utils.py +3 -1
- telegrinder-0.5.0.dist-info/METADATA +162 -0
- telegrinder-0.5.0.dist-info/RECORD +200 -0
- {telegrinder-0.4.2.dist-info → telegrinder-0.5.0.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.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import enum
|
|
5
|
+
import inspect
|
|
6
|
+
import types
|
|
7
|
+
import typing
|
|
8
|
+
from functools import cached_property, wraps
|
|
9
|
+
|
|
10
|
+
from telegrinder.tools.magic.annotations import Annotations
|
|
11
|
+
|
|
12
|
+
type Function[**P, R] = typing.Callable[P, R]
|
|
13
|
+
type AnyFunction = Function[..., typing.Any]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _to_str(obj: typing.Any, /) -> str:
|
|
17
|
+
if isinstance(obj, enum.Enum):
|
|
18
|
+
return str(obj.value)
|
|
19
|
+
return str(obj) if not isinstance(obj, str) else obj
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _resolve_arg_names(
|
|
23
|
+
func: AnyFunction,
|
|
24
|
+
/,
|
|
25
|
+
*,
|
|
26
|
+
start_idx: int,
|
|
27
|
+
stop_idx: int,
|
|
28
|
+
exclude: set[str] | None = None,
|
|
29
|
+
) -> tuple[str, ...]:
|
|
30
|
+
exclude = exclude or set()
|
|
31
|
+
varnames = func.__code__.co_varnames[start_idx:stop_idx]
|
|
32
|
+
return tuple(name for name in varnames if name not in exclude)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FunctionParameters(typing.TypedDict):
|
|
36
|
+
args: list[tuple[str, typing.Any | inspect.Parameter.empty]]
|
|
37
|
+
kwargs: list[tuple[str, typing.Any | inspect.Parameter.empty]]
|
|
38
|
+
var_star_args: typing.NotRequired[str]
|
|
39
|
+
var_star_kwargs: typing.NotRequired[str]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclasses.dataclass(frozen=True, repr=False)
|
|
43
|
+
class Bundle[R]:
|
|
44
|
+
function: Function[..., R]
|
|
45
|
+
start_idx: int
|
|
46
|
+
context: types.MappingProxyType[str, typing.Any]
|
|
47
|
+
|
|
48
|
+
@cached_property
|
|
49
|
+
def args(self) -> tuple[typing.Any, ...]:
|
|
50
|
+
return tuple(
|
|
51
|
+
self.context[name]
|
|
52
|
+
for name in resolve_posonly_arg_names(self.function, start_idx=self.start_idx)
|
|
53
|
+
if name in self.context
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@cached_property
|
|
57
|
+
def kwargs(self) -> dict[str, typing.Any]:
|
|
58
|
+
posonly_arg_names = resolve_posonly_arg_names(self.function, start_idx=self.start_idx)
|
|
59
|
+
return {name: value for name, value in self.context.items() if name not in posonly_arg_names}
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def from_context(
|
|
63
|
+
cls,
|
|
64
|
+
function: Function[..., R],
|
|
65
|
+
context: typing.Mapping[str, typing.Any],
|
|
66
|
+
/,
|
|
67
|
+
*,
|
|
68
|
+
start_idx: int = 1,
|
|
69
|
+
) -> typing.Self:
|
|
70
|
+
return cls(function, start_idx, types.MappingProxyType(context))
|
|
71
|
+
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
return "<{}: function={!r} bundle args={!r} kwargs={!r}>".format(
|
|
74
|
+
type(self).__name__,
|
|
75
|
+
self.function,
|
|
76
|
+
self.args,
|
|
77
|
+
self.kwargs,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> R:
|
|
81
|
+
return self.function(*args, *self.args, **kwargs, **self.kwargs)
|
|
82
|
+
|
|
83
|
+
def __and__(self, other: object, /) -> typing.Self:
|
|
84
|
+
if not isinstance(other, Bundle):
|
|
85
|
+
return NotImplemented
|
|
86
|
+
|
|
87
|
+
if self.function != other.function:
|
|
88
|
+
raise ValueError(
|
|
89
|
+
f"Cannot merge contexts because bundle {other!r} is intended for a different function.",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return dataclasses.replace(
|
|
93
|
+
self,
|
|
94
|
+
context=types.MappingProxyType(mapping=self.context | other.context),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def __iand__(self, other: object, /) -> typing.Self:
|
|
98
|
+
return self.__and__(other)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def function_context[**P, R](key: str, /) -> Function[[Function[P, R]], Function[P, R]]:
|
|
102
|
+
@lambda wrapper: typing.cast("Function[[Function[P, R]], Function[P, R]]", wrapper)
|
|
103
|
+
def wrapper(func: Function[typing.Concatenate[AnyFunction, P], R], /) -> AnyFunction:
|
|
104
|
+
@wraps(func)
|
|
105
|
+
def inner(passed_function: AnyFunction, /, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
106
|
+
sentinel = object()
|
|
107
|
+
context: dict[str, typing.Any] = passed_function.__dict__.setdefault("__function_context__", {})
|
|
108
|
+
|
|
109
|
+
if (value := context.get(key, sentinel)) is not sentinel:
|
|
110
|
+
return value
|
|
111
|
+
|
|
112
|
+
context[key] = result = func(passed_function, *args, **kwargs)
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
return inner
|
|
116
|
+
|
|
117
|
+
return wrapper
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def resolve_arg_names(
|
|
121
|
+
func: AnyFunction,
|
|
122
|
+
/,
|
|
123
|
+
*,
|
|
124
|
+
start_idx: int = 1,
|
|
125
|
+
exclude: set[str] | None = None,
|
|
126
|
+
) -> tuple[str, ...]:
|
|
127
|
+
return _resolve_arg_names(
|
|
128
|
+
func,
|
|
129
|
+
start_idx=start_idx,
|
|
130
|
+
stop_idx=func.__code__.co_argcount + func.__code__.co_kwonlyargcount,
|
|
131
|
+
exclude=exclude,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def resolve_kwonly_arg_names(
|
|
136
|
+
func: AnyFunction,
|
|
137
|
+
/,
|
|
138
|
+
*,
|
|
139
|
+
start_idx: int = 1,
|
|
140
|
+
exclude: set[str] | None = None,
|
|
141
|
+
) -> tuple[str, ...]:
|
|
142
|
+
return _resolve_arg_names(
|
|
143
|
+
func,
|
|
144
|
+
start_idx=func.__code__.co_argcount + start_idx,
|
|
145
|
+
stop_idx=func.__code__.co_argcount + func.__code__.co_kwonlyargcount,
|
|
146
|
+
exclude=exclude,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def resolve_posonly_arg_names(
|
|
151
|
+
func: AnyFunction,
|
|
152
|
+
/,
|
|
153
|
+
*,
|
|
154
|
+
start_idx: int = 1,
|
|
155
|
+
exclude: set[str] | None = None,
|
|
156
|
+
) -> tuple[str, ...]:
|
|
157
|
+
return _resolve_arg_names(
|
|
158
|
+
func,
|
|
159
|
+
start_idx=start_idx,
|
|
160
|
+
stop_idx=func.__code__.co_posonlyargcount,
|
|
161
|
+
exclude=exclude,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@function_context("default_arguments")
|
|
166
|
+
def get_default_args(func: AnyFunction, /) -> dict[str, typing.Any]:
|
|
167
|
+
parameters = get_func_parameters(func)
|
|
168
|
+
return {
|
|
169
|
+
key: value
|
|
170
|
+
for sublist in (parameters["args"], parameters["kwargs"])
|
|
171
|
+
for key, value in sublist
|
|
172
|
+
if value is not inspect.Parameter.empty
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@function_context("signature_parameters")
|
|
177
|
+
def get_func_parameters(func: AnyFunction, /) -> FunctionParameters:
|
|
178
|
+
func_params = FunctionParameters(args=[], kwargs=[])
|
|
179
|
+
|
|
180
|
+
for k, p in inspect.signature(func).parameters.items():
|
|
181
|
+
if k in ("self", "cls"):
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
match p.kind:
|
|
185
|
+
case p.POSITIONAL_OR_KEYWORD | p.POSITIONAL_ONLY:
|
|
186
|
+
func_params["args"].append((k, p.default))
|
|
187
|
+
case p.KEYWORD_ONLY:
|
|
188
|
+
func_params["kwargs"].append((k, p.default))
|
|
189
|
+
case p.VAR_POSITIONAL:
|
|
190
|
+
func_params["var_star_args"] = k
|
|
191
|
+
case p.VAR_KEYWORD:
|
|
192
|
+
func_params["var_star_kwargs"] = k
|
|
193
|
+
|
|
194
|
+
return func_params
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@function_context("resolved_annotations")
|
|
198
|
+
def get_func_annotations(func: AnyFunction, /) -> typing.Mapping[str, typing.Any]:
|
|
199
|
+
return Annotations(obj=func).get(
|
|
200
|
+
ignore_failed_evals=True,
|
|
201
|
+
exclude_forward_refs=True,
|
|
202
|
+
allow_return_type=False,
|
|
203
|
+
cache=False,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def bundle[R](
|
|
208
|
+
function: Function[..., R],
|
|
209
|
+
context: dict[typing.Any, typing.Any],
|
|
210
|
+
/,
|
|
211
|
+
*,
|
|
212
|
+
start_idx: int = 1,
|
|
213
|
+
bundle_kwargs: bool = False,
|
|
214
|
+
typebundle: bool = False,
|
|
215
|
+
omit_defaults: bool = False,
|
|
216
|
+
) -> Bundle[R]:
|
|
217
|
+
if typebundle:
|
|
218
|
+
return Bundle.from_context(
|
|
219
|
+
function,
|
|
220
|
+
{name: context[ann] for name, ann in get_func_annotations(function).items() if ann in context},
|
|
221
|
+
start_idx=start_idx,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
kwargs = {_to_str(k): v for k, v in context.items()}
|
|
225
|
+
if not bundle_kwargs or "var_star_kwargs" not in get_func_parameters(function):
|
|
226
|
+
names = resolve_arg_names(function, start_idx=start_idx, exclude={"cls", "self"})
|
|
227
|
+
kwargs = {k: v for k, v in kwargs.items() if k in names}
|
|
228
|
+
|
|
229
|
+
return Bundle.from_context(
|
|
230
|
+
function,
|
|
231
|
+
kwargs if omit_defaults else get_default_args(function) | kwargs,
|
|
232
|
+
start_idx=start_idx,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
__all__ = (
|
|
237
|
+
"Bundle",
|
|
238
|
+
"bundle",
|
|
239
|
+
"function_context",
|
|
240
|
+
"get_default_args",
|
|
241
|
+
"get_func_annotations",
|
|
242
|
+
"get_func_parameters",
|
|
243
|
+
"resolve_arg_names",
|
|
244
|
+
"resolve_kwonly_arg_names",
|
|
245
|
+
"resolve_posonly_arg_names",
|
|
246
|
+
)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import inspect
|
|
5
|
+
import typing
|
|
6
|
+
from collections import OrderedDict
|
|
7
|
+
from functools import wraps
|
|
8
|
+
|
|
9
|
+
from fntypes.result import Result
|
|
10
|
+
|
|
11
|
+
from telegrinder.tools.magic.function import get_func_parameters
|
|
12
|
+
from telegrinder.types.methods_utils import get_params
|
|
13
|
+
|
|
14
|
+
type Executor[T] = typing.Callable[
|
|
15
|
+
[T, str, dict[str, typing.Any]],
|
|
16
|
+
typing.Awaitable[Result[typing.Any, APIError]],
|
|
17
|
+
]
|
|
18
|
+
type CuteMethod[T, **P, R] = typing.Callable[
|
|
19
|
+
typing.Concatenate[T, P],
|
|
20
|
+
typing.Awaitable[Result[R, APIError]],
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
if typing.TYPE_CHECKING:
|
|
24
|
+
from telegrinder.api.error import APIError
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ShortcutMethod[T, **P, R](typing.Protocol):
|
|
28
|
+
__name__: str
|
|
29
|
+
__shortcut__: Shortcut[T]
|
|
30
|
+
|
|
31
|
+
async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Result[R, APIError]: ...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclasses.dataclass(slots=True, frozen=True)
|
|
35
|
+
class Shortcut[T]:
|
|
36
|
+
method_name: str
|
|
37
|
+
executor: Executor[T] | None = dataclasses.field(default=None, kw_only=True)
|
|
38
|
+
custom_params: set[str] = dataclasses.field(default_factory=lambda: set[str](), kw_only=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@typing.overload
|
|
42
|
+
def shortcut[T, **P, R](
|
|
43
|
+
method_name: str,
|
|
44
|
+
/,
|
|
45
|
+
*,
|
|
46
|
+
custom_params: set[str] = ...,
|
|
47
|
+
) -> typing.Callable[[CuteMethod[T, P, R]], ShortcutMethod[T, P, R]]: ...
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@typing.overload
|
|
51
|
+
def shortcut[T, **P, R](
|
|
52
|
+
method_name: str,
|
|
53
|
+
/,
|
|
54
|
+
*,
|
|
55
|
+
executor: Executor[T],
|
|
56
|
+
custom_params: set[str] = ...,
|
|
57
|
+
) -> typing.Callable[[CuteMethod[T, P, R]], ShortcutMethod[T, P, R]]: ...
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def shortcut[T, **P, R](
|
|
61
|
+
method_name: str,
|
|
62
|
+
/,
|
|
63
|
+
*,
|
|
64
|
+
executor: Executor[T] | None = None,
|
|
65
|
+
custom_params: set[str] | None = None,
|
|
66
|
+
) -> typing.Callable[[CuteMethod[T, P, R]], ShortcutMethod[T, P, R]]:
|
|
67
|
+
"""Decorate a cute method as a shortcut."""
|
|
68
|
+
|
|
69
|
+
def wrapper(func: CuteMethod[T, P, R]) -> ShortcutMethod[T, P, R]:
|
|
70
|
+
@wraps(func)
|
|
71
|
+
async def inner(
|
|
72
|
+
self: T,
|
|
73
|
+
*args: P.args,
|
|
74
|
+
**kwargs: P.kwargs,
|
|
75
|
+
) -> Result[R, typing.Any]:
|
|
76
|
+
if executor is None:
|
|
77
|
+
return await func(self, *args, **kwargs)
|
|
78
|
+
|
|
79
|
+
params: dict[str, typing.Any] = OrderedDict()
|
|
80
|
+
func_params = get_func_parameters(func)
|
|
81
|
+
|
|
82
|
+
for index, (arg, default) in enumerate(func_params["args"]):
|
|
83
|
+
if len(args) > index:
|
|
84
|
+
params[arg] = args[index]
|
|
85
|
+
elif default is not inspect.Parameter.empty:
|
|
86
|
+
params[arg] = default
|
|
87
|
+
|
|
88
|
+
if var_args := func_params.get("var_star_args"):
|
|
89
|
+
params[var_args] = args[len(func_params["args"]) :]
|
|
90
|
+
|
|
91
|
+
for kwarg, default in func_params["kwargs"]:
|
|
92
|
+
params[kwarg] = (
|
|
93
|
+
kwargs.pop(kwarg, default) if default is not inspect.Parameter.empty else kwargs.pop(kwarg)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if var_kwargs := func_params.get("var_star_kwargs"):
|
|
97
|
+
params[var_kwargs] = kwargs.copy()
|
|
98
|
+
|
|
99
|
+
return await executor(self, method_name, get_params(params))
|
|
100
|
+
|
|
101
|
+
inner.__shortcut__ = Shortcut( # type: ignore
|
|
102
|
+
method_name=method_name,
|
|
103
|
+
executor=executor,
|
|
104
|
+
custom_params=custom_params or set(),
|
|
105
|
+
)
|
|
106
|
+
return inner # type: ignore
|
|
107
|
+
|
|
108
|
+
return wrapper
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
__all__ = ("Shortcut", "shortcut")
|
telegrinder/tools/parse_mode.py
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from telegrinder.tools.final import Final
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@typing.final
|
|
7
|
+
class ParseMode(Final):
|
|
8
|
+
MARKDOWNV2: typing.Final[str] = "MarkdownV2"
|
|
9
|
+
HTML: typing.Final[str] = "HTML"
|
|
4
10
|
|
|
5
11
|
|
|
6
12
|
__all__ = ("ParseMode",)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
|
|
3
|
+
from telegrinder.tools.singleton.singleton import SingletonMeta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ABCSingletonMeta(abc.ABCMeta, SingletonMeta):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ABCSingleton(metaclass=ABCSingletonMeta):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ("ABCSingleton", "ABCSingletonMeta")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SingletonMeta(type):
|
|
5
|
+
if not typing.TYPE_CHECKING:
|
|
6
|
+
__instance = None
|
|
7
|
+
|
|
8
|
+
def __call__(cls, *args, **kwargs):
|
|
9
|
+
if cls.__instance is None:
|
|
10
|
+
cls.__instance = super().__call__(*args, **kwargs)
|
|
11
|
+
return cls.__instance
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Singleton(metaclass=SingletonMeta):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ("Singleton", "SingletonMeta")
|
|
File without changes
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import abc
|
|
2
4
|
import dataclasses
|
|
3
5
|
import enum
|
|
@@ -7,11 +9,14 @@ from fntypes.option import Option
|
|
|
7
9
|
from telegrinder.bot.rules.state import State, StateMeta
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
@dataclasses.dataclass
|
|
12
|
+
@dataclasses.dataclass
|
|
11
13
|
class StateData[Payload]:
|
|
12
14
|
key: str | enum.Enum
|
|
13
15
|
payload: Payload
|
|
14
16
|
|
|
17
|
+
async def save(self, user_id: int, storage: ABCStateStorage[Payload]) -> None:
|
|
18
|
+
await storage.set(user_id, key=self.key, payload=self.payload)
|
|
19
|
+
|
|
15
20
|
|
|
16
21
|
class ABCStateStorage[Payload](abc.ABC):
|
|
17
22
|
@abc.abstractmethod
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
+
from fntypes.misc import from_optional
|
|
3
4
|
from fntypes.option import Option
|
|
4
5
|
|
|
5
|
-
from telegrinder.tools.functional import from_optional
|
|
6
6
|
from telegrinder.tools.state_storage.abc import ABCStateStorage, StateData
|
|
7
7
|
|
|
8
8
|
type Payload = dict[str, typing.Any]
|
telegrinder/tools/strings.py
CHANGED
|
File without changes
|