telegrinder 0.3.0.post2__py3-none-any.whl → 0.3.2__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 +144 -144
- telegrinder/api/__init__.py +8 -8
- telegrinder/api/api.py +93 -93
- telegrinder/api/error.py +16 -16
- telegrinder/api/response.py +20 -20
- telegrinder/api/token.py +36 -36
- telegrinder/bot/__init__.py +66 -66
- telegrinder/bot/bot.py +76 -76
- telegrinder/bot/cute_types/__init__.py +11 -11
- telegrinder/bot/cute_types/base.py +258 -234
- telegrinder/bot/cute_types/callback_query.py +382 -382
- telegrinder/bot/cute_types/chat_join_request.py +61 -61
- telegrinder/bot/cute_types/chat_member_updated.py +160 -160
- telegrinder/bot/cute_types/inline_query.py +53 -53
- telegrinder/bot/cute_types/message.py +2631 -2631
- telegrinder/bot/cute_types/update.py +75 -75
- telegrinder/bot/cute_types/utils.py +92 -92
- telegrinder/bot/dispatch/__init__.py +55 -55
- telegrinder/bot/dispatch/abc.py +77 -77
- telegrinder/bot/dispatch/context.py +92 -92
- telegrinder/bot/dispatch/dispatch.py +202 -201
- telegrinder/bot/dispatch/handler/__init__.py +13 -13
- telegrinder/bot/dispatch/handler/abc.py +24 -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 +128 -123
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -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 +16 -16
- telegrinder/bot/dispatch/process.py +132 -132
- telegrinder/bot/dispatch/return_manager/__init__.py +13 -13
- telegrinder/bot/dispatch/return_manager/abc.py +108 -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/view/__init__.py +13 -13
- telegrinder/bot/dispatch/view/abc.py +41 -41
- telegrinder/bot/dispatch/view/base.py +200 -211
- telegrinder/bot/dispatch/view/box.py +129 -129
- telegrinder/bot/dispatch/view/callback_query.py +17 -17
- telegrinder/bot/dispatch/view/chat_join_request.py +16 -16
- telegrinder/bot/dispatch/view/chat_member.py +39 -39
- telegrinder/bot/dispatch/view/inline_query.py +17 -17
- telegrinder/bot/dispatch/view/message.py +44 -44
- telegrinder/bot/dispatch/view/raw.py +114 -118
- telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
- telegrinder/bot/dispatch/waiter_machine/actions.py +13 -13
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +57 -57
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +53 -53
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
- telegrinder/bot/dispatch/waiter_machine/machine.py +168 -170
- telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
- telegrinder/bot/dispatch/waiter_machine/short_state.py +65 -65
- telegrinder/bot/polling/__init__.py +4 -4
- telegrinder/bot/polling/abc.py +25 -25
- telegrinder/bot/polling/polling.py +131 -131
- telegrinder/bot/rules/__init__.py +62 -62
- telegrinder/bot/rules/abc.py +238 -233
- telegrinder/bot/rules/adapter/__init__.py +9 -9
- telegrinder/bot/rules/adapter/abc.py +29 -29
- telegrinder/bot/rules/adapter/errors.py +5 -5
- telegrinder/bot/rules/adapter/event.py +76 -76
- telegrinder/bot/rules/adapter/node.py +48 -48
- telegrinder/bot/rules/adapter/raw_update.py +30 -30
- telegrinder/bot/rules/callback_data.py +171 -171
- telegrinder/bot/rules/chat_join.py +48 -48
- telegrinder/bot/rules/command.py +126 -126
- telegrinder/bot/rules/enum_text.py +36 -33
- telegrinder/bot/rules/func.py +26 -26
- telegrinder/bot/rules/fuzzy.py +24 -24
- telegrinder/bot/rules/inline.py +60 -60
- telegrinder/bot/rules/integer.py +20 -20
- telegrinder/bot/rules/is_from.py +146 -146
- telegrinder/bot/rules/markup.py +43 -43
- telegrinder/bot/rules/mention.py +14 -14
- telegrinder/bot/rules/message.py +17 -17
- telegrinder/bot/rules/message_entities.py +35 -35
- telegrinder/bot/rules/node.py +27 -27
- telegrinder/bot/rules/regex.py +37 -37
- telegrinder/bot/rules/rule_enum.py +72 -72
- telegrinder/bot/rules/start.py +42 -42
- telegrinder/bot/rules/state.py +37 -37
- telegrinder/bot/rules/text.py +33 -33
- telegrinder/bot/rules/update.py +15 -15
- telegrinder/bot/scenario/__init__.py +5 -5
- telegrinder/bot/scenario/abc.py +19 -19
- telegrinder/bot/scenario/checkbox.py +167 -139
- telegrinder/bot/scenario/choice.py +46 -44
- telegrinder/client/__init__.py +4 -4
- telegrinder/client/abc.py +75 -75
- telegrinder/client/aiohttp.py +130 -130
- telegrinder/model.py +244 -244
- telegrinder/modules.py +237 -237
- telegrinder/msgspec_json.py +14 -14
- telegrinder/msgspec_utils.py +410 -410
- telegrinder/node/__init__.py +20 -20
- telegrinder/node/attachment.py +92 -92
- telegrinder/node/base.py +143 -144
- telegrinder/node/callback_query.py +14 -14
- telegrinder/node/command.py +33 -33
- telegrinder/node/composer.py +196 -184
- telegrinder/node/container.py +27 -27
- telegrinder/node/event.py +71 -73
- telegrinder/node/me.py +16 -16
- telegrinder/node/message.py +14 -14
- telegrinder/node/polymorphic.py +48 -52
- telegrinder/node/rule.py +76 -76
- telegrinder/node/scope.py +38 -38
- telegrinder/node/source.py +71 -71
- telegrinder/node/text.py +21 -21
- telegrinder/node/tools/__init__.py +3 -3
- telegrinder/node/tools/generator.py +40 -40
- telegrinder/node/update.py +15 -15
- telegrinder/rules.py +0 -0
- telegrinder/tools/__init__.py +74 -74
- telegrinder/tools/buttons.py +79 -79
- telegrinder/tools/error_handler/__init__.py +7 -7
- telegrinder/tools/error_handler/abc.py +33 -33
- telegrinder/tools/error_handler/error.py +9 -9
- telegrinder/tools/error_handler/error_handler.py +193 -193
- telegrinder/tools/formatting/__init__.py +46 -46
- telegrinder/tools/formatting/html.py +308 -308
- telegrinder/tools/formatting/links.py +33 -33
- telegrinder/tools/formatting/spec_html_formats.py +111 -111
- telegrinder/tools/functional.py +12 -12
- telegrinder/tools/global_context/__init__.py +7 -7
- telegrinder/tools/global_context/abc.py +63 -63
- telegrinder/tools/global_context/global_context.py +412 -412
- telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
- telegrinder/tools/i18n/__init__.py +12 -12
- telegrinder/tools/i18n/abc.py +32 -32
- telegrinder/tools/i18n/middleware/__init__.py +3 -3
- telegrinder/tools/i18n/middleware/abc.py +25 -25
- telegrinder/tools/i18n/simple.py +43 -43
- telegrinder/tools/kb_set/__init__.py +4 -4
- telegrinder/tools/kb_set/base.py +15 -15
- telegrinder/tools/kb_set/yaml.py +63 -63
- telegrinder/tools/keyboard.py +128 -128
- telegrinder/tools/limited_dict.py +37 -37
- telegrinder/tools/loop_wrapper/__init__.py +4 -4
- telegrinder/tools/loop_wrapper/abc.py +15 -15
- telegrinder/tools/loop_wrapper/loop_wrapper.py +216 -216
- telegrinder/tools/magic.py +168 -164
- telegrinder/tools/parse_mode.py +6 -6
- telegrinder/tools/state_storage/__init__.py +4 -4
- telegrinder/tools/state_storage/abc.py +35 -35
- telegrinder/tools/state_storage/memory.py +25 -25
- telegrinder/types/__init__.py +6 -6
- telegrinder/types/enums.py +672 -672
- telegrinder/types/methods.py +4633 -4633
- telegrinder/types/objects.py +6317 -6317
- telegrinder/verification_utils.py +32 -32
- {telegrinder-0.3.0.post2.dist-info → telegrinder-0.3.2.dist-info}/LICENSE +22 -22
- {telegrinder-0.3.0.post2.dist-info → telegrinder-0.3.2.dist-info}/METADATA +1 -1
- telegrinder-0.3.2.dist-info/RECORD +164 -0
- telegrinder-0.3.0.post2.dist-info/RECORD +0 -164
- {telegrinder-0.3.0.post2.dist-info → telegrinder-0.3.2.dist-info}/WHEEL +0 -0
telegrinder/tools/keyboard.py
CHANGED
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
import typing
|
|
3
|
-
from abc import ABC, abstractmethod
|
|
4
|
-
from types import NoneType
|
|
5
|
-
|
|
6
|
-
from fntypes.option import Nothing, Some
|
|
7
|
-
|
|
8
|
-
from telegrinder.types.objects import (
|
|
9
|
-
InlineKeyboardMarkup,
|
|
10
|
-
ReplyKeyboardMarkup,
|
|
11
|
-
ReplyKeyboardRemove,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
from .buttons import Button, InlineButton, KeyboardButton, RowButtons
|
|
15
|
-
|
|
16
|
-
DictStrAny: typing.TypeAlias = dict[str, typing.Any]
|
|
17
|
-
AnyMarkup: typing.TypeAlias = InlineKeyboardMarkup | ReplyKeyboardMarkup
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def copy_keyboard(keyboard: list[list[DictStrAny]]) -> list[list[DictStrAny]]:
|
|
21
|
-
return [row.copy() for row in keyboard]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@dataclasses.dataclass(kw_only=True, slots=True)
|
|
25
|
-
class KeyboardModel:
|
|
26
|
-
resize_keyboard: bool
|
|
27
|
-
one_time_keyboard: bool
|
|
28
|
-
selective: bool
|
|
29
|
-
is_persistent: bool
|
|
30
|
-
keyboard: list[list[DictStrAny]]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class ABCMarkup(ABC, typing.Generic[KeyboardButton]):
|
|
34
|
-
BUTTON: type[KeyboardButton]
|
|
35
|
-
keyboard: list[list[DictStrAny]]
|
|
36
|
-
|
|
37
|
-
@abstractmethod
|
|
38
|
-
def dict(self) -> DictStrAny:
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
|
-
@abstractmethod
|
|
42
|
-
def get_markup(self) -> AnyMarkup:
|
|
43
|
-
pass
|
|
44
|
-
|
|
45
|
-
@classmethod
|
|
46
|
-
def get_empty_markup(cls) -> AnyMarkup:
|
|
47
|
-
return cls().get_markup()
|
|
48
|
-
|
|
49
|
-
def add(self, row_or_button: RowButtons[KeyboardButton] | KeyboardButton) -> typing.Self:
|
|
50
|
-
if not len(self.keyboard):
|
|
51
|
-
self.row()
|
|
52
|
-
|
|
53
|
-
if isinstance(row_or_button, RowButtons):
|
|
54
|
-
self.keyboard[-1].extend(row_or_button.get_data())
|
|
55
|
-
if row_or_button.auto_row:
|
|
56
|
-
self.row()
|
|
57
|
-
return self
|
|
58
|
-
|
|
59
|
-
self.keyboard[-1].append(row_or_button.get_data())
|
|
60
|
-
return self
|
|
61
|
-
|
|
62
|
-
def row(self) -> typing.Self:
|
|
63
|
-
if len(self.keyboard) and not len(self.keyboard[-1]):
|
|
64
|
-
raise RuntimeError("Last row is empty!")
|
|
65
|
-
|
|
66
|
-
self.keyboard.append([])
|
|
67
|
-
return self
|
|
68
|
-
|
|
69
|
-
def format(self, **format_data: str) -> typing.Self:
|
|
70
|
-
copy_keyboard = self.__class__()
|
|
71
|
-
for row in self.keyboard:
|
|
72
|
-
for button in row:
|
|
73
|
-
copy_button = button.copy()
|
|
74
|
-
copy_button["text"] = copy_button["text"].format(**format_data)
|
|
75
|
-
copy_keyboard.add(self.BUTTON(**copy_button))
|
|
76
|
-
copy_keyboard.row()
|
|
77
|
-
return copy_keyboard
|
|
78
|
-
|
|
79
|
-
def merge(self, other: typing.Self) -> typing.Self:
|
|
80
|
-
self.keyboard.extend(copy_keyboard(other.keyboard))
|
|
81
|
-
return self
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@dataclasses.dataclass(kw_only=True, slots=True)
|
|
85
|
-
class Keyboard(ABCMarkup[Button], KeyboardModel):
|
|
86
|
-
BUTTON = Button
|
|
87
|
-
|
|
88
|
-
keyboard: list[list[DictStrAny]] = dataclasses.field(
|
|
89
|
-
default_factory=lambda: [[]],
|
|
90
|
-
init=False,
|
|
91
|
-
)
|
|
92
|
-
resize_keyboard: bool = dataclasses.field(default=True)
|
|
93
|
-
one_time_keyboard: bool = dataclasses.field(default=False)
|
|
94
|
-
selective: bool = dataclasses.field(default=False)
|
|
95
|
-
is_persistent: bool = dataclasses.field(default=False)
|
|
96
|
-
|
|
97
|
-
def dict(self) -> DictStrAny:
|
|
98
|
-
self.keyboard = [row for row in self.keyboard if row]
|
|
99
|
-
return {
|
|
100
|
-
k: v.unwrap() if v and isinstance(v, Some) else v
|
|
101
|
-
for k, v in dataclasses.asdict(self).items()
|
|
102
|
-
if type(v) not in (NoneType, Nothing)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
def get_markup(self) -> ReplyKeyboardMarkup:
|
|
106
|
-
return ReplyKeyboardMarkup(**self.dict())
|
|
107
|
-
|
|
108
|
-
def keyboard_remove(self, *, selective: bool = False) -> ReplyKeyboardRemove:
|
|
109
|
-
return ReplyKeyboardRemove(remove_keyboard=True, selective=Some(selective))
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
class InlineKeyboard(ABCMarkup[InlineButton]):
|
|
113
|
-
BUTTON = InlineButton
|
|
114
|
-
|
|
115
|
-
def __init__(self) -> None:
|
|
116
|
-
self.keyboard = [[]]
|
|
117
|
-
|
|
118
|
-
def dict(self) -> DictStrAny:
|
|
119
|
-
self.keyboard = [row for row in self.keyboard if row]
|
|
120
|
-
return dict(inline_keyboard=self.keyboard)
|
|
121
|
-
|
|
122
|
-
def get_markup(self) -> InlineKeyboardMarkup:
|
|
123
|
-
return InlineKeyboardMarkup(**self.dict())
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
__all__ = (
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from types import NoneType
|
|
5
|
+
|
|
6
|
+
from fntypes.option import Nothing, Some
|
|
7
|
+
|
|
8
|
+
from telegrinder.types.objects import (
|
|
9
|
+
InlineKeyboardMarkup,
|
|
10
|
+
ReplyKeyboardMarkup,
|
|
11
|
+
ReplyKeyboardRemove,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .buttons import Button, InlineButton, KeyboardButton, RowButtons
|
|
15
|
+
|
|
16
|
+
DictStrAny: typing.TypeAlias = dict[str, typing.Any]
|
|
17
|
+
AnyMarkup: typing.TypeAlias = InlineKeyboardMarkup | ReplyKeyboardMarkup
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def copy_keyboard(keyboard: list[list[DictStrAny]]) -> list[list[DictStrAny]]:
|
|
21
|
+
return [row.copy() for row in keyboard]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclasses.dataclass(kw_only=True, slots=True)
|
|
25
|
+
class KeyboardModel:
|
|
26
|
+
resize_keyboard: bool
|
|
27
|
+
one_time_keyboard: bool
|
|
28
|
+
selective: bool
|
|
29
|
+
is_persistent: bool
|
|
30
|
+
keyboard: list[list[DictStrAny]]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ABCMarkup(ABC, typing.Generic[KeyboardButton]):
|
|
34
|
+
BUTTON: type[KeyboardButton]
|
|
35
|
+
keyboard: list[list[DictStrAny]]
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def dict(self) -> DictStrAny:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def get_markup(self) -> AnyMarkup:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def get_empty_markup(cls) -> AnyMarkup:
|
|
47
|
+
return cls().get_markup()
|
|
48
|
+
|
|
49
|
+
def add(self, row_or_button: RowButtons[KeyboardButton] | KeyboardButton) -> typing.Self:
|
|
50
|
+
if not len(self.keyboard):
|
|
51
|
+
self.row()
|
|
52
|
+
|
|
53
|
+
if isinstance(row_or_button, RowButtons):
|
|
54
|
+
self.keyboard[-1].extend(row_or_button.get_data())
|
|
55
|
+
if row_or_button.auto_row:
|
|
56
|
+
self.row()
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
self.keyboard[-1].append(row_or_button.get_data())
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def row(self) -> typing.Self:
|
|
63
|
+
if len(self.keyboard) and not len(self.keyboard[-1]):
|
|
64
|
+
raise RuntimeError("Last row is empty!")
|
|
65
|
+
|
|
66
|
+
self.keyboard.append([])
|
|
67
|
+
return self
|
|
68
|
+
|
|
69
|
+
def format(self, **format_data: str) -> typing.Self:
|
|
70
|
+
copy_keyboard = self.__class__()
|
|
71
|
+
for row in self.keyboard:
|
|
72
|
+
for button in row:
|
|
73
|
+
copy_button = button.copy()
|
|
74
|
+
copy_button["text"] = copy_button["text"].format(**format_data)
|
|
75
|
+
copy_keyboard.add(self.BUTTON(**copy_button))
|
|
76
|
+
copy_keyboard.row()
|
|
77
|
+
return copy_keyboard
|
|
78
|
+
|
|
79
|
+
def merge(self, other: typing.Self) -> typing.Self:
|
|
80
|
+
self.keyboard.extend(copy_keyboard(other.keyboard))
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclasses.dataclass(kw_only=True, slots=True)
|
|
85
|
+
class Keyboard(ABCMarkup[Button], KeyboardModel):
|
|
86
|
+
BUTTON = Button
|
|
87
|
+
|
|
88
|
+
keyboard: list[list[DictStrAny]] = dataclasses.field(
|
|
89
|
+
default_factory=lambda: [[]],
|
|
90
|
+
init=False,
|
|
91
|
+
)
|
|
92
|
+
resize_keyboard: bool = dataclasses.field(default=True)
|
|
93
|
+
one_time_keyboard: bool = dataclasses.field(default=False)
|
|
94
|
+
selective: bool = dataclasses.field(default=False)
|
|
95
|
+
is_persistent: bool = dataclasses.field(default=False)
|
|
96
|
+
|
|
97
|
+
def dict(self) -> DictStrAny:
|
|
98
|
+
self.keyboard = [row for row in self.keyboard if row]
|
|
99
|
+
return {
|
|
100
|
+
k: v.unwrap() if v and isinstance(v, Some) else v
|
|
101
|
+
for k, v in dataclasses.asdict(self).items()
|
|
102
|
+
if type(v) not in (NoneType, Nothing)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def get_markup(self) -> ReplyKeyboardMarkup:
|
|
106
|
+
return ReplyKeyboardMarkup(**self.dict())
|
|
107
|
+
|
|
108
|
+
def keyboard_remove(self, *, selective: bool = False) -> ReplyKeyboardRemove:
|
|
109
|
+
return ReplyKeyboardRemove(remove_keyboard=True, selective=Some(selective))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class InlineKeyboard(ABCMarkup[InlineButton]):
|
|
113
|
+
BUTTON = InlineButton
|
|
114
|
+
|
|
115
|
+
def __init__(self) -> None:
|
|
116
|
+
self.keyboard = [[]]
|
|
117
|
+
|
|
118
|
+
def dict(self) -> DictStrAny:
|
|
119
|
+
self.keyboard = [row for row in self.keyboard if row]
|
|
120
|
+
return dict(inline_keyboard=self.keyboard)
|
|
121
|
+
|
|
122
|
+
def get_markup(self) -> InlineKeyboardMarkup:
|
|
123
|
+
return InlineKeyboardMarkup(**self.dict())
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
__all__ = (
|
|
127
127
|
"ABCMarkup",
|
|
128
128
|
"InlineKeyboard",
|
|
129
129
|
"Keyboard",
|
|
130
130
|
"KeyboardModel",
|
|
131
|
-
"copy_keyboard",
|
|
132
|
-
)
|
|
131
|
+
"copy_keyboard",
|
|
132
|
+
)
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
from collections import UserDict, deque
|
|
3
|
-
|
|
4
|
-
KT = typing.TypeVar("KT")
|
|
5
|
-
VT = typing.TypeVar("VT")
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class LimitedDict(UserDict[KT, VT]):
|
|
9
|
-
def __init__(self, *, maxlimit: int = 1000) -> None:
|
|
10
|
-
super().__init__()
|
|
11
|
-
self.maxlimit = maxlimit
|
|
12
|
-
self.queue: deque[KT] = deque(maxlen=maxlimit)
|
|
13
|
-
|
|
14
|
-
def set(self, key: KT, value: VT, /) -> VT | None:
|
|
15
|
-
"""Set item in the dictionary.
|
|
16
|
-
Returns a value that was deleted when the limit in the dictionary
|
|
17
|
-
was reached, otherwise None.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
deleted_item = None
|
|
21
|
-
if len(self.queue) >= self.maxlimit:
|
|
22
|
-
deleted_item = self.pop(self.queue.popleft(), None)
|
|
23
|
-
if key not in self.queue:
|
|
24
|
-
self.queue.append(key)
|
|
25
|
-
super().__setitem__(key, value)
|
|
26
|
-
return deleted_item
|
|
27
|
-
|
|
28
|
-
def __setitem__(self, key: KT, value: VT, /) -> None:
|
|
29
|
-
self.set(key, value)
|
|
30
|
-
|
|
31
|
-
def __delitem__(self, key: KT) -> None:
|
|
32
|
-
if key in self.queue:
|
|
33
|
-
self.queue.remove(key)
|
|
34
|
-
return super().__delitem__(key)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
__all__ = ("LimitedDict",)
|
|
1
|
+
import typing
|
|
2
|
+
from collections import UserDict, deque
|
|
3
|
+
|
|
4
|
+
KT = typing.TypeVar("KT")
|
|
5
|
+
VT = typing.TypeVar("VT")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LimitedDict(UserDict[KT, VT]):
|
|
9
|
+
def __init__(self, *, maxlimit: int = 1000) -> None:
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.maxlimit = maxlimit
|
|
12
|
+
self.queue: deque[KT] = deque(maxlen=maxlimit)
|
|
13
|
+
|
|
14
|
+
def set(self, key: KT, value: VT, /) -> VT | None:
|
|
15
|
+
"""Set item in the dictionary.
|
|
16
|
+
Returns a value that was deleted when the limit in the dictionary
|
|
17
|
+
was reached, otherwise None.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
deleted_item = None
|
|
21
|
+
if len(self.queue) >= self.maxlimit:
|
|
22
|
+
deleted_item = self.pop(self.queue.popleft(), None)
|
|
23
|
+
if key not in self.queue:
|
|
24
|
+
self.queue.append(key)
|
|
25
|
+
super().__setitem__(key, value)
|
|
26
|
+
return deleted_item
|
|
27
|
+
|
|
28
|
+
def __setitem__(self, key: KT, value: VT, /) -> None:
|
|
29
|
+
self.set(key, value)
|
|
30
|
+
|
|
31
|
+
def __delitem__(self, key: KT) -> None:
|
|
32
|
+
if key in self.queue:
|
|
33
|
+
self.queue.remove(key)
|
|
34
|
+
return super().__delitem__(key)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = ("LimitedDict",)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .abc import ABCLoopWrapper
|
|
2
|
-
from .loop_wrapper import DelayedTask, Lifespan, LoopWrapper
|
|
3
|
-
|
|
4
|
-
__all__ = ("ABCLoopWrapper", "DelayedTask", "Lifespan", "LoopWrapper")
|
|
1
|
+
from .abc import ABCLoopWrapper
|
|
2
|
+
from .loop_wrapper import DelayedTask, Lifespan, LoopWrapper
|
|
3
|
+
|
|
4
|
+
__all__ = ("ABCLoopWrapper", "DelayedTask", "Lifespan", "LoopWrapper")
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
from abc import ABC, abstractmethod
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ABCLoopWrapper(ABC):
|
|
6
|
-
@abstractmethod
|
|
7
|
-
def add_task(self, task: typing.Any) -> None:
|
|
8
|
-
pass
|
|
9
|
-
|
|
10
|
-
@abstractmethod
|
|
11
|
-
def run_event_loop(self) -> None:
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
__all__ = ("ABCLoopWrapper",)
|
|
1
|
+
import typing
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ABCLoopWrapper(ABC):
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def add_task(self, task: typing.Any) -> None:
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def run_event_loop(self) -> None:
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ("ABCLoopWrapper",)
|