telegrinder 0.1.dev161__py3-none-any.whl → 0.1.dev162__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/api/api.py +4 -2
- telegrinder/api/error.py +3 -3
- telegrinder/bot/bot.py +2 -2
- telegrinder/bot/cute_types/base.py +1 -4
- telegrinder/bot/cute_types/message.py +140 -0
- telegrinder/bot/dispatch/composition.py +1 -1
- telegrinder/bot/dispatch/dispatch.py +1 -1
- telegrinder/bot/dispatch/waiter_machine/short_state.py +1 -1
- telegrinder/bot/scenario/checkbox.py +3 -4
- telegrinder/modules.py +5 -3
- telegrinder/msgspec_json.py +3 -3
- telegrinder/msgspec_utils.py +34 -35
- telegrinder/tools/__init__.py +6 -0
- telegrinder/tools/buttons.py +8 -13
- telegrinder/tools/formatting/__init__.py +6 -0
- telegrinder/tools/formatting/html.py +10 -0
- telegrinder/tools/formatting/links.py +7 -0
- telegrinder/tools/formatting/spec_html_formats.py +27 -15
- telegrinder/tools/keyboard.py +3 -3
- telegrinder/tools/loop_wrapper/abc.py +4 -4
- telegrinder/types/enums.py +4 -0
- telegrinder/types/methods.py +175 -41
- telegrinder/types/objects.py +425 -201
- {telegrinder-0.1.dev161.dist-info → telegrinder-0.1.dev162.dist-info}/METADATA +1 -1
- {telegrinder-0.1.dev161.dist-info → telegrinder-0.1.dev162.dist-info}/RECORD +27 -27
- {telegrinder-0.1.dev161.dist-info → telegrinder-0.1.dev162.dist-info}/WHEEL +1 -1
- {telegrinder-0.1.dev161.dist-info → telegrinder-0.1.dev162.dist-info}/LICENSE +0 -0
|
@@ -37,7 +37,7 @@ class Composition:
|
|
|
37
37
|
return None
|
|
38
38
|
return NodeCollection(nodes)
|
|
39
39
|
|
|
40
|
-
async def __call__(self, **kwargs) -> typing.Any:
|
|
40
|
+
async def __call__(self, **kwargs: typing.Any) -> typing.Any:
|
|
41
41
|
return await self.func(**magic_bundle(self.func, kwargs, start_idx=0, bundle_ctx=False)) # type: ignore
|
|
42
42
|
|
|
43
43
|
|
|
@@ -11,7 +11,7 @@ if typing.TYPE_CHECKING:
|
|
|
11
11
|
from .machine import Identificator
|
|
12
12
|
|
|
13
13
|
EventModel = typing.TypeVar("EventModel", bound=BaseCute)
|
|
14
|
-
Behaviour = ABCHandler | None
|
|
14
|
+
Behaviour: typing.TypeAlias = ABCHandler | None
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class ShortState(typing.Generic[EventModel]):
|
|
@@ -43,7 +43,7 @@ class Checkbox(ABCScenario[CallbackQueryCute]):
|
|
|
43
43
|
self.choices: list[Choice] = []
|
|
44
44
|
self.ready = ready_text
|
|
45
45
|
self.max_in_row = max_in_row
|
|
46
|
-
self.random_code = secrets.token_hex(
|
|
46
|
+
self.random_code = secrets.token_hex(8)
|
|
47
47
|
self.waiter_machine = waiter_machine
|
|
48
48
|
|
|
49
49
|
def get_markup(self) -> InlineKeyboardMarkup:
|
|
@@ -73,7 +73,7 @@ class Checkbox(ABCScenario[CallbackQueryCute]):
|
|
|
73
73
|
is_picked: bool = False,
|
|
74
74
|
) -> typing.Self:
|
|
75
75
|
self.choices.append(
|
|
76
|
-
Choice(name, is_picked, default_text, picked_text, secrets.token_hex(
|
|
76
|
+
Choice(name, is_picked, default_text, picked_text, secrets.token_hex(8)),
|
|
77
77
|
)
|
|
78
78
|
return self
|
|
79
79
|
|
|
@@ -103,7 +103,7 @@ class Checkbox(ABCScenario[CallbackQueryCute]):
|
|
|
103
103
|
assert len(self.choices) > 1
|
|
104
104
|
message = (
|
|
105
105
|
await api.send_message(
|
|
106
|
-
self.chat_id,
|
|
106
|
+
chat_id=self.chat_id,
|
|
107
107
|
text=self.msg,
|
|
108
108
|
parse_mode=self.PARSE_MODE,
|
|
109
109
|
reply_markup=self.get_markup(),
|
|
@@ -111,7 +111,6 @@ class Checkbox(ABCScenario[CallbackQueryCute]):
|
|
|
111
111
|
).unwrap()
|
|
112
112
|
|
|
113
113
|
while True:
|
|
114
|
-
q: CallbackQueryCute
|
|
115
114
|
q, _ = await self.waiter_machine.wait(view, (api, message.message_id))
|
|
116
115
|
should_continue = await self.handle(q)
|
|
117
116
|
await q.answer(self.CALLBACK_ANSWER)
|
telegrinder/modules.py
CHANGED
|
@@ -4,14 +4,16 @@ import typing
|
|
|
4
4
|
from choicelib import choice_in_order
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
@typing.runtime_checkable
|
|
7
8
|
class JSONModule(typing.Protocol):
|
|
8
|
-
def loads(self, s: str | bytes) ->
|
|
9
|
+
def loads(self, s: str | bytes) -> typing.Any:
|
|
9
10
|
...
|
|
10
11
|
|
|
11
|
-
def dumps(self, o:
|
|
12
|
+
def dumps(self, o: typing.Any) -> str:
|
|
12
13
|
...
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
@typing.runtime_checkable
|
|
15
17
|
class LoggerModule(typing.Protocol):
|
|
16
18
|
def debug(self, __msg: object, *args: object, **kwargs: object) -> None:
|
|
17
19
|
...
|
|
@@ -47,7 +49,7 @@ class LoggerModule(typing.Protocol):
|
|
|
47
49
|
|
|
48
50
|
logger: LoggerModule
|
|
49
51
|
json: JSONModule = choice_in_order(
|
|
50
|
-
["
|
|
52
|
+
["orjson", "ujson", "hyperjson"], do_import=True, default="telegrinder.msgspec_json"
|
|
51
53
|
)
|
|
52
54
|
logging_module = choice_in_order(["loguru"], default="logging")
|
|
53
55
|
logging_level = os.getenv("LOGGER_LEVEL", default="DEBUG").upper()
|
telegrinder/msgspec_json.py
CHANGED
|
@@ -3,11 +3,11 @@ import typing
|
|
|
3
3
|
from .msgspec_utils import decoder, encoder
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def loads(s: str | bytes) ->
|
|
7
|
-
return decoder.decode(s
|
|
6
|
+
def loads(s: str | bytes) -> typing.Any:
|
|
7
|
+
return decoder.decode(s)
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def dumps(o:
|
|
10
|
+
def dumps(o: typing.Any) -> str:
|
|
11
11
|
return encoder.encode(o)
|
|
12
12
|
|
|
13
13
|
|
telegrinder/msgspec_utils.py
CHANGED
|
@@ -8,7 +8,6 @@ T = typing.TypeVar("T")
|
|
|
8
8
|
Ts = typing.TypeVarTuple("Ts")
|
|
9
9
|
|
|
10
10
|
if typing.TYPE_CHECKING:
|
|
11
|
-
import types
|
|
12
11
|
from datetime import datetime
|
|
13
12
|
|
|
14
13
|
from fntypes.option import Option
|
|
@@ -48,10 +47,6 @@ def msgspec_convert(obj: typing.Any, t: type[T]) -> Result[T, msgspec.Validation
|
|
|
48
47
|
return Error(exc)
|
|
49
48
|
|
|
50
49
|
|
|
51
|
-
def datetime_dec_hook(tp: type[datetime], obj: int | float) -> datetime:
|
|
52
|
-
return tp.fromtimestamp(obj)
|
|
53
|
-
|
|
54
|
-
|
|
55
50
|
def option_dec_hook(tp: type[Option[typing.Any]], obj: typing.Any) -> Option[typing.Any]:
|
|
56
51
|
if obj is None:
|
|
57
52
|
return Nothing
|
|
@@ -88,37 +83,23 @@ def variative_dec_hook(tp: type[Variative], obj: typing.Any) -> Variative:
|
|
|
88
83
|
|
|
89
84
|
raise TypeError(
|
|
90
85
|
"Object of type `{}` does not belong to types `{}`".format(
|
|
91
|
-
repr_type(
|
|
86
|
+
repr_type(obj.__class__),
|
|
92
87
|
" | ".join(map(repr_type, union_types)),
|
|
93
88
|
)
|
|
94
89
|
)
|
|
95
90
|
|
|
96
91
|
|
|
97
|
-
def datetime_enc_hook(obj: datetime) -> int:
|
|
98
|
-
return int(obj.timestamp())
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def option_enc_hook(obj: Option[typing.Any]) -> typing.Any | None:
|
|
102
|
-
return obj.value if isinstance(obj, fntypes.option.Some) else None
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def variative_enc_hook(obj: Variative[typing.Any]) -> typing.Any:
|
|
106
|
-
return obj.v
|
|
107
|
-
|
|
108
|
-
|
|
109
92
|
class Decoder:
|
|
110
93
|
def __init__(self) -> None:
|
|
111
|
-
self.dec_hooks: dict[
|
|
112
|
-
typing.Union[type[typing.Any], "types.UnionType"], DecHook[typing.Any]
|
|
113
|
-
] = {
|
|
94
|
+
self.dec_hooks: dict[typing.Any, DecHook[typing.Any]] = {
|
|
114
95
|
Option: option_dec_hook,
|
|
115
96
|
Variative: variative_dec_hook,
|
|
116
|
-
datetime:
|
|
97
|
+
datetime: lambda t, obj: t.fromtimestamp(obj),
|
|
117
98
|
}
|
|
118
99
|
|
|
119
|
-
def add_dec_hook(self,
|
|
100
|
+
def add_dec_hook(self, t: T): # type: ignore
|
|
120
101
|
def decorator(func: DecHook[T]) -> DecHook[T]:
|
|
121
|
-
return self.dec_hooks.setdefault(get_origin(
|
|
102
|
+
return self.dec_hooks.setdefault(get_origin(t), func) # type: ignore
|
|
122
103
|
|
|
123
104
|
return decorator
|
|
124
105
|
|
|
@@ -150,12 +131,30 @@ class Decoder:
|
|
|
150
131
|
builtin_types=builtin_types,
|
|
151
132
|
str_keys=str_keys,
|
|
152
133
|
)
|
|
134
|
+
|
|
135
|
+
@typing.overload
|
|
136
|
+
def decode(self, buf: str | bytes) -> typing.Any:
|
|
137
|
+
...
|
|
138
|
+
|
|
139
|
+
@typing.overload
|
|
140
|
+
def decode(self, buf: str | bytes, *, strict: bool = True) -> typing.Any:
|
|
141
|
+
...
|
|
153
142
|
|
|
143
|
+
@typing.overload
|
|
154
144
|
def decode(
|
|
155
145
|
self,
|
|
156
146
|
buf: str | bytes,
|
|
157
147
|
*,
|
|
158
|
-
type: type[T]
|
|
148
|
+
type: type[T],
|
|
149
|
+
strict: bool = True,
|
|
150
|
+
) -> T:
|
|
151
|
+
...
|
|
152
|
+
|
|
153
|
+
def decode(
|
|
154
|
+
self,
|
|
155
|
+
buf: str | bytes,
|
|
156
|
+
*,
|
|
157
|
+
type: type[T] = typing.Any, # type: ignore
|
|
159
158
|
strict: bool = True,
|
|
160
159
|
) -> T:
|
|
161
160
|
return msgspec.json.decode(
|
|
@@ -168,11 +167,11 @@ class Decoder:
|
|
|
168
167
|
|
|
169
168
|
class Encoder:
|
|
170
169
|
def __init__(self) -> None:
|
|
171
|
-
self.enc_hooks: dict[
|
|
172
|
-
fntypes.option.Some:
|
|
173
|
-
fntypes.option.Nothing:
|
|
174
|
-
Variative:
|
|
175
|
-
datetime:
|
|
170
|
+
self.enc_hooks: dict[typing.Any, EncHook[typing.Any]] = {
|
|
171
|
+
fntypes.option.Some: lambda opt: opt.value,
|
|
172
|
+
fntypes.option.Nothing: lambda _: None,
|
|
173
|
+
Variative: lambda variative: variative.v,
|
|
174
|
+
datetime: lambda date: int(date.timestamp()),
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
def add_dec_hook(self, tp: type[T]):
|
|
@@ -182,13 +181,17 @@ class Encoder:
|
|
|
182
181
|
return decorator
|
|
183
182
|
|
|
184
183
|
def enc_hook(self, obj: object) -> object:
|
|
185
|
-
origin_type = get_origin(
|
|
184
|
+
origin_type = get_origin(obj.__class__)
|
|
186
185
|
if origin_type not in self.enc_hooks:
|
|
187
186
|
raise NotImplementedError(
|
|
188
187
|
"Not implemented encode hook for "
|
|
189
188
|
f"object of type `{repr_type(origin_type)}`."
|
|
190
189
|
)
|
|
191
190
|
return self.enc_hooks[origin_type](obj)
|
|
191
|
+
|
|
192
|
+
@typing.overload
|
|
193
|
+
def encode(self, obj: typing.Any) -> str:
|
|
194
|
+
...
|
|
192
195
|
|
|
193
196
|
@typing.overload
|
|
194
197
|
def encode(self, obj: typing.Any, *, as_str: typing.Literal[True] = True) -> str:
|
|
@@ -215,12 +218,8 @@ __all__ = (
|
|
|
215
218
|
"get_origin",
|
|
216
219
|
"repr_type",
|
|
217
220
|
"msgspec_convert",
|
|
218
|
-
"datetime_dec_hook",
|
|
219
|
-
"datetime_enc_hook",
|
|
220
221
|
"option_dec_hook",
|
|
221
|
-
"option_enc_hook",
|
|
222
222
|
"variative_dec_hook",
|
|
223
|
-
"variative_enc_hook",
|
|
224
223
|
"datetime",
|
|
225
224
|
"decoder",
|
|
226
225
|
"encoder",
|
telegrinder/tools/__init__.py
CHANGED
|
@@ -14,6 +14,7 @@ from .formatting import (
|
|
|
14
14
|
StartBotLink,
|
|
15
15
|
StartGroupLink,
|
|
16
16
|
TgEmoji,
|
|
17
|
+
UserOpenMessage,
|
|
17
18
|
block_quote,
|
|
18
19
|
bold,
|
|
19
20
|
channel_boost_link,
|
|
@@ -37,6 +38,8 @@ from .formatting import (
|
|
|
37
38
|
strike,
|
|
38
39
|
tg_emoji,
|
|
39
40
|
underline,
|
|
41
|
+
user_open_message,
|
|
42
|
+
user_open_message_link,
|
|
40
43
|
)
|
|
41
44
|
from .global_context import (
|
|
42
45
|
ABCGlobalContext,
|
|
@@ -109,6 +112,7 @@ __all__ = (
|
|
|
109
112
|
"StartGroupLink",
|
|
110
113
|
"TelegrinderCtx",
|
|
111
114
|
"TgEmoji",
|
|
115
|
+
"UserOpenMessage",
|
|
112
116
|
"block_quote",
|
|
113
117
|
"bold",
|
|
114
118
|
"channel_boost_link",
|
|
@@ -135,4 +139,6 @@ __all__ = (
|
|
|
135
139
|
"strike",
|
|
136
140
|
"tg_emoji",
|
|
137
141
|
"underline",
|
|
142
|
+
"user_open_message",
|
|
143
|
+
"user_open_message_link",
|
|
138
144
|
)
|
telegrinder/tools/buttons.py
CHANGED
|
@@ -26,13 +26,11 @@ class DataclassInstance(typing.Protocol):
|
|
|
26
26
|
class BaseButton:
|
|
27
27
|
def get_data(self) -> dict[str, typing.Any]:
|
|
28
28
|
return {
|
|
29
|
-
k: v
|
|
30
|
-
if k != "callback_data" or isinstance(v, str)
|
|
31
|
-
else encoder.encode(v)
|
|
29
|
+
k: v if k != "callback_data" or isinstance(v, str) else encoder.encode(v)
|
|
32
30
|
for k, v in dataclasses.asdict(self).items()
|
|
33
31
|
if v is not None
|
|
34
32
|
}
|
|
35
|
-
|
|
33
|
+
|
|
36
34
|
|
|
37
35
|
class RowButtons(typing.Generic[ButtonT]):
|
|
38
36
|
buttons: list[ButtonT]
|
|
@@ -65,18 +63,15 @@ class InlineButton(BaseButton):
|
|
|
65
63
|
url: str | None = None
|
|
66
64
|
login_url: dict[str, typing.Any] | LoginUrl | None = None
|
|
67
65
|
pay: bool | None = None
|
|
68
|
-
callback_data:
|
|
69
|
-
str,
|
|
70
|
-
|
|
71
|
-
DataclassInstance,
|
|
72
|
-
msgspec.Struct,
|
|
73
|
-
] | None = None
|
|
66
|
+
callback_data: (
|
|
67
|
+
str | dict[str, typing.Any] | DataclassInstance | msgspec.Struct | None
|
|
68
|
+
) = None
|
|
74
69
|
callback_game: dict[str, typing.Any] | CallbackGame | None = None
|
|
75
70
|
switch_inline_query: str | None = None
|
|
76
71
|
switch_inline_query_current_chat: str | None = None
|
|
77
|
-
switch_inline_query_chosen_chat:
|
|
78
|
-
str, typing.Any
|
|
79
|
-
|
|
72
|
+
switch_inline_query_chosen_chat: (
|
|
73
|
+
dict[str, typing.Any] | SwitchInlineQueryChosenChat | None
|
|
74
|
+
) = None
|
|
80
75
|
web_app: dict[str, typing.Any] | WebAppInfo | None = None
|
|
81
76
|
|
|
82
77
|
|
|
@@ -18,6 +18,7 @@ from .html import (
|
|
|
18
18
|
strike,
|
|
19
19
|
tg_emoji,
|
|
20
20
|
underline,
|
|
21
|
+
user_open_message,
|
|
21
22
|
)
|
|
22
23
|
from .links import (
|
|
23
24
|
get_channel_boost_link,
|
|
@@ -26,6 +27,7 @@ from .links import (
|
|
|
26
27
|
get_resolve_domain_link,
|
|
27
28
|
get_start_bot_link,
|
|
28
29
|
get_start_group_link,
|
|
30
|
+
user_open_message_link,
|
|
29
31
|
)
|
|
30
32
|
from .spec_html_formats import (
|
|
31
33
|
BaseSpecFormat,
|
|
@@ -39,6 +41,7 @@ from .spec_html_formats import (
|
|
|
39
41
|
StartBotLink,
|
|
40
42
|
StartGroupLink,
|
|
41
43
|
TgEmoji,
|
|
44
|
+
UserOpenMessage,
|
|
42
45
|
)
|
|
43
46
|
|
|
44
47
|
__all__ = (
|
|
@@ -55,6 +58,7 @@ __all__ = (
|
|
|
55
58
|
"StartBotLink",
|
|
56
59
|
"StartGroupLink",
|
|
57
60
|
"TgEmoji",
|
|
61
|
+
"UserOpenMessage",
|
|
58
62
|
"block_quote",
|
|
59
63
|
"bold",
|
|
60
64
|
"channel_boost_link",
|
|
@@ -78,4 +82,6 @@ __all__ = (
|
|
|
78
82
|
"strike",
|
|
79
83
|
"tg_emoji",
|
|
80
84
|
"underline",
|
|
85
|
+
"user_open_message",
|
|
86
|
+
"user_open_message_link",
|
|
81
87
|
)
|
|
@@ -13,6 +13,7 @@ from .links import (
|
|
|
13
13
|
get_resolve_domain_link,
|
|
14
14
|
get_start_bot_link,
|
|
15
15
|
get_start_group_link,
|
|
16
|
+
user_open_message_link,
|
|
16
17
|
)
|
|
17
18
|
from .spec_html_formats import SpecialFormat, is_spec_format
|
|
18
19
|
|
|
@@ -274,6 +275,14 @@ def underline(string: str) -> TagFormat:
|
|
|
274
275
|
return TagFormat(string, tag="u")
|
|
275
276
|
|
|
276
277
|
|
|
278
|
+
def user_open_message(
|
|
279
|
+
user_id: int,
|
|
280
|
+
message: str | None = None,
|
|
281
|
+
string: str | None = None,
|
|
282
|
+
) -> TagFormat:
|
|
283
|
+
return link(user_open_message_link(user_id, message), string)
|
|
284
|
+
|
|
285
|
+
|
|
277
286
|
__all__ = (
|
|
278
287
|
"FormatString",
|
|
279
288
|
"HTMLFormatter",
|
|
@@ -301,4 +310,5 @@ __all__ = (
|
|
|
301
310
|
"strike",
|
|
302
311
|
"tg_emoji",
|
|
303
312
|
"underline",
|
|
313
|
+
"user_open_message",
|
|
304
314
|
)
|
|
@@ -22,6 +22,12 @@ def get_invite_chat_link(invite_link: str) -> str:
|
|
|
22
22
|
return f"tg://join?invite={invite_link}"
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def user_open_message_link(user_id: int, message: str | None = None) -> str:
|
|
26
|
+
return f"tg://openmessage?user_id={user_id}" + (
|
|
27
|
+
"" if not message else f"&msg?text={message}"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
25
31
|
__all__ = (
|
|
26
32
|
"get_channel_boost_link",
|
|
27
33
|
"get_invite_chat_link",
|
|
@@ -29,4 +35,5 @@ __all__ = (
|
|
|
29
35
|
"get_resolve_domain_link",
|
|
30
36
|
"get_start_bot_link",
|
|
31
37
|
"get_start_group_link",
|
|
38
|
+
"user_open_message_link",
|
|
32
39
|
)
|
|
@@ -5,14 +5,16 @@ from telegrinder.types.enums import ProgrammingLanguage
|
|
|
5
5
|
|
|
6
6
|
SpecialFormat = typing.Union[
|
|
7
7
|
"ChannelBoostLink",
|
|
8
|
-
"
|
|
8
|
+
"InviteChatLink",
|
|
9
9
|
"Link",
|
|
10
|
+
"Mention",
|
|
10
11
|
"PreCode",
|
|
11
|
-
"
|
|
12
|
+
"ResolveDomain",
|
|
13
|
+
"SpecialFormat",
|
|
12
14
|
"StartBotLink",
|
|
13
15
|
"StartGroupLink",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
+
"TgEmoji",
|
|
17
|
+
"UserOpenMessage",
|
|
16
18
|
]
|
|
17
19
|
|
|
18
20
|
|
|
@@ -26,13 +28,13 @@ def is_spec_format(obj: typing.Any) -> typing.TypeGuard[SpecialFormat]:
|
|
|
26
28
|
|
|
27
29
|
@dataclasses.dataclass(repr=False)
|
|
28
30
|
class BaseSpecFormat:
|
|
29
|
-
__formatter_name__: typing.ClassVar[str]
|
|
31
|
+
__formatter_name__: typing.ClassVar[str] = dataclasses.field(init=False, repr=False)
|
|
30
32
|
|
|
31
33
|
def __repr__(self) -> str:
|
|
32
|
-
return f"<{self.__class__.__name__!r}
|
|
34
|
+
return f"<Special formatter {self.__class__.__name__!r} -> {self.__formatter_name__!r}>"
|
|
33
35
|
|
|
34
36
|
|
|
35
|
-
@dataclasses.dataclass
|
|
37
|
+
@dataclasses.dataclass(repr=False)
|
|
36
38
|
class ChannelBoostLink(BaseSpecFormat):
|
|
37
39
|
__formatter_name__ = "channel_boost_link"
|
|
38
40
|
|
|
@@ -40,7 +42,7 @@ class ChannelBoostLink(BaseSpecFormat):
|
|
|
40
42
|
string: str | None = None
|
|
41
43
|
|
|
42
44
|
|
|
43
|
-
@dataclasses.dataclass
|
|
45
|
+
@dataclasses.dataclass(repr=False)
|
|
44
46
|
class InviteChatLink(BaseSpecFormat):
|
|
45
47
|
__formatter_name__ = "invite_chat_link"
|
|
46
48
|
|
|
@@ -48,7 +50,7 @@ class InviteChatLink(BaseSpecFormat):
|
|
|
48
50
|
string: str | None = None
|
|
49
51
|
|
|
50
52
|
|
|
51
|
-
@dataclasses.dataclass
|
|
53
|
+
@dataclasses.dataclass(repr=False)
|
|
52
54
|
class Mention(BaseSpecFormat):
|
|
53
55
|
__formatter_name__ = "mention"
|
|
54
56
|
|
|
@@ -56,7 +58,7 @@ class Mention(BaseSpecFormat):
|
|
|
56
58
|
user_id: int
|
|
57
59
|
|
|
58
60
|
|
|
59
|
-
@dataclasses.dataclass
|
|
61
|
+
@dataclasses.dataclass(repr=False)
|
|
60
62
|
class Link(BaseSpecFormat):
|
|
61
63
|
__formatter_name__ = "link"
|
|
62
64
|
|
|
@@ -64,7 +66,7 @@ class Link(BaseSpecFormat):
|
|
|
64
66
|
string: str | None = None
|
|
65
67
|
|
|
66
68
|
|
|
67
|
-
@dataclasses.dataclass
|
|
69
|
+
@dataclasses.dataclass(repr=False)
|
|
68
70
|
class PreCode(BaseSpecFormat):
|
|
69
71
|
__formatter_name__ = "pre_code"
|
|
70
72
|
|
|
@@ -72,7 +74,7 @@ class PreCode(BaseSpecFormat):
|
|
|
72
74
|
lang: str | ProgrammingLanguage | None = None
|
|
73
75
|
|
|
74
76
|
|
|
75
|
-
@dataclasses.dataclass
|
|
77
|
+
@dataclasses.dataclass(repr=False)
|
|
76
78
|
class TgEmoji(BaseSpecFormat):
|
|
77
79
|
__formatter_name__ = "tg_emoji"
|
|
78
80
|
|
|
@@ -80,7 +82,7 @@ class TgEmoji(BaseSpecFormat):
|
|
|
80
82
|
emoji_id: int
|
|
81
83
|
|
|
82
84
|
|
|
83
|
-
@dataclasses.dataclass
|
|
85
|
+
@dataclasses.dataclass(repr=False)
|
|
84
86
|
class StartBotLink(BaseSpecFormat):
|
|
85
87
|
__formatter_name__ = "start_bot_link"
|
|
86
88
|
|
|
@@ -89,7 +91,7 @@ class StartBotLink(BaseSpecFormat):
|
|
|
89
91
|
string: str | None
|
|
90
92
|
|
|
91
93
|
|
|
92
|
-
@dataclasses.dataclass
|
|
94
|
+
@dataclasses.dataclass(repr=False)
|
|
93
95
|
class StartGroupLink(BaseSpecFormat):
|
|
94
96
|
__formatter_name__ = "start_group_link"
|
|
95
97
|
|
|
@@ -98,7 +100,7 @@ class StartGroupLink(BaseSpecFormat):
|
|
|
98
100
|
string: str | None = None
|
|
99
101
|
|
|
100
102
|
|
|
101
|
-
@dataclasses.dataclass
|
|
103
|
+
@dataclasses.dataclass(repr=False)
|
|
102
104
|
class ResolveDomain(BaseSpecFormat):
|
|
103
105
|
__formatter_name__ = "resolve_domain"
|
|
104
106
|
|
|
@@ -106,6 +108,15 @@ class ResolveDomain(BaseSpecFormat):
|
|
|
106
108
|
string: str | None = None
|
|
107
109
|
|
|
108
110
|
|
|
111
|
+
@dataclasses.dataclass(repr=False)
|
|
112
|
+
class UserOpenMessage(BaseSpecFormat):
|
|
113
|
+
__formatter_name__ = "user_open_message"
|
|
114
|
+
|
|
115
|
+
user_id: int
|
|
116
|
+
message: str | None = None
|
|
117
|
+
string: str | None = None
|
|
118
|
+
|
|
119
|
+
|
|
109
120
|
__all__ = (
|
|
110
121
|
"BaseSpecFormat",
|
|
111
122
|
"ChannelBoostLink",
|
|
@@ -118,4 +129,5 @@ __all__ = (
|
|
|
118
129
|
"StartBotLink",
|
|
119
130
|
"StartGroupLink",
|
|
120
131
|
"TgEmoji",
|
|
132
|
+
"UserOpenMessage",
|
|
121
133
|
)
|
telegrinder/tools/keyboard.py
CHANGED
|
@@ -91,9 +91,6 @@ class Keyboard(ABCMarkup[Button], KeyboardModel):
|
|
|
91
91
|
selective: bool = dataclasses.field(default=False)
|
|
92
92
|
is_persistent: bool = dataclasses.field(default=False)
|
|
93
93
|
|
|
94
|
-
def get_empty_markup(self, *, selective: bool = False) -> ReplyKeyboardRemove:
|
|
95
|
-
return ReplyKeyboardRemove(remove_keyboard=True, selective=selective) # type: ignore
|
|
96
|
-
|
|
97
94
|
def dict(self) -> DictStrAny:
|
|
98
95
|
self.keyboard = [row for row in self.keyboard if row]
|
|
99
96
|
return {
|
|
@@ -105,6 +102,9 @@ class Keyboard(ABCMarkup[Button], KeyboardModel):
|
|
|
105
102
|
def get_markup(self) -> ReplyKeyboardMarkup:
|
|
106
103
|
return ReplyKeyboardMarkup(**self.dict())
|
|
107
104
|
|
|
105
|
+
def get_empty_markup(self, *, selective: bool = False) -> ReplyKeyboardRemove:
|
|
106
|
+
return ReplyKeyboardRemove(remove_keyboard=True, selective=Some(selective))
|
|
107
|
+
|
|
108
108
|
|
|
109
109
|
class InlineKeyboard(ABCMarkup[InlineButton]):
|
|
110
110
|
BUTTON = InlineButton
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
|
|
4
|
-
CoroutineTask = typing.Coroutine[typing.Any, typing.Any, typing.Any]
|
|
5
|
-
CoroutineFunc = typing.Callable[..., CoroutineTask]
|
|
4
|
+
CoroutineTask: typing.TypeAlias = typing.Coroutine[typing.Any, typing.Any, typing.Any]
|
|
5
|
+
CoroutineFunc: typing.TypeAlias = typing.Callable[..., CoroutineTask]
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class ABCLoopWrapper(ABC):
|
|
9
9
|
@abstractmethod
|
|
10
10
|
def add_task(self, task: CoroutineFunc | CoroutineTask) -> None:
|
|
11
|
-
|
|
11
|
+
pass
|
|
12
12
|
|
|
13
13
|
@abstractmethod
|
|
14
14
|
def run_event_loop(self) -> None:
|
|
15
|
-
|
|
15
|
+
pass
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
__all__ = ("ABCLoopWrapper",)
|
telegrinder/types/enums.py
CHANGED
|
@@ -415,6 +415,10 @@ class UpdateType(str, enum.Enum):
|
|
|
415
415
|
CHAT_JOIN_REQUEST = "chat_join_request"
|
|
416
416
|
CHAT_BOOST = "chat_boost"
|
|
417
417
|
REMOVED_CHAT_BOOST = "removed_chat_boost"
|
|
418
|
+
BUSINESS_CONNECTION = "business_connection"
|
|
419
|
+
BUSINESS_MESSAGE = "business_message"
|
|
420
|
+
EDITED_BUSINESS_MESSAGE = "edited_business_message"
|
|
421
|
+
DELETE_BUSINESS_MESSAGE = "delete_business_messages"
|
|
418
422
|
|
|
419
423
|
|
|
420
424
|
class BotCommandScopeType(str, enum.Enum):
|