telegrinder 0.3.4__py3-none-any.whl → 0.3.4.post1__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.

Files changed (165) hide show
  1. telegrinder/__init__.py +144 -144
  2. telegrinder/api/__init__.py +8 -8
  3. telegrinder/api/api.py +93 -93
  4. telegrinder/api/error.py +16 -16
  5. telegrinder/api/response.py +20 -20
  6. telegrinder/api/token.py +36 -36
  7. telegrinder/bot/__init__.py +66 -66
  8. telegrinder/bot/bot.py +76 -76
  9. telegrinder/bot/cute_types/__init__.py +17 -17
  10. telegrinder/bot/cute_types/base.py +258 -258
  11. telegrinder/bot/cute_types/callback_query.py +385 -385
  12. telegrinder/bot/cute_types/chat_join_request.py +61 -61
  13. telegrinder/bot/cute_types/chat_member_updated.py +160 -160
  14. telegrinder/bot/cute_types/inline_query.py +43 -43
  15. telegrinder/bot/cute_types/message.py +2637 -2637
  16. telegrinder/bot/cute_types/update.py +104 -104
  17. telegrinder/bot/cute_types/utils.py +95 -95
  18. telegrinder/bot/dispatch/__init__.py +55 -55
  19. telegrinder/bot/dispatch/abc.py +77 -77
  20. telegrinder/bot/dispatch/context.py +98 -98
  21. telegrinder/bot/dispatch/dispatch.py +202 -202
  22. telegrinder/bot/dispatch/handler/__init__.py +13 -13
  23. telegrinder/bot/dispatch/handler/abc.py +24 -24
  24. telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
  25. telegrinder/bot/dispatch/handler/base.py +57 -57
  26. telegrinder/bot/dispatch/handler/document_reply.py +44 -44
  27. telegrinder/bot/dispatch/handler/func.py +135 -135
  28. telegrinder/bot/dispatch/handler/media_group_reply.py +43 -43
  29. telegrinder/bot/dispatch/handler/message_reply.py +36 -36
  30. telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
  31. telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
  32. telegrinder/bot/dispatch/handler/video_reply.py +44 -44
  33. telegrinder/bot/dispatch/middleware/__init__.py +3 -3
  34. telegrinder/bot/dispatch/middleware/abc.py +22 -22
  35. telegrinder/bot/dispatch/process.py +157 -157
  36. telegrinder/bot/dispatch/return_manager/__init__.py +13 -13
  37. telegrinder/bot/dispatch/return_manager/abc.py +108 -108
  38. telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
  39. telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
  40. telegrinder/bot/dispatch/return_manager/message.py +36 -36
  41. telegrinder/bot/dispatch/view/__init__.py +13 -13
  42. telegrinder/bot/dispatch/view/abc.py +41 -41
  43. telegrinder/bot/dispatch/view/base.py +200 -200
  44. telegrinder/bot/dispatch/view/box.py +129 -129
  45. telegrinder/bot/dispatch/view/callback_query.py +17 -17
  46. telegrinder/bot/dispatch/view/chat_join_request.py +16 -16
  47. telegrinder/bot/dispatch/view/chat_member.py +39 -39
  48. telegrinder/bot/dispatch/view/inline_query.py +17 -17
  49. telegrinder/bot/dispatch/view/message.py +44 -44
  50. telegrinder/bot/dispatch/view/raw.py +114 -114
  51. telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
  52. telegrinder/bot/dispatch/waiter_machine/actions.py +13 -13
  53. telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
  54. telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
  55. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
  56. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
  57. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
  58. telegrinder/bot/dispatch/waiter_machine/machine.py +172 -172
  59. telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
  60. telegrinder/bot/dispatch/waiter_machine/short_state.py +68 -68
  61. telegrinder/bot/polling/__init__.py +4 -4
  62. telegrinder/bot/polling/abc.py +25 -25
  63. telegrinder/bot/polling/polling.py +131 -131
  64. telegrinder/bot/rules/__init__.py +62 -62
  65. telegrinder/bot/rules/abc.py +206 -206
  66. telegrinder/bot/rules/adapter/__init__.py +17 -17
  67. telegrinder/bot/rules/adapter/abc.py +31 -31
  68. telegrinder/bot/rules/adapter/errors.py +5 -5
  69. telegrinder/bot/rules/adapter/event.py +65 -65
  70. telegrinder/bot/rules/adapter/node.py +48 -48
  71. telegrinder/bot/rules/adapter/raw_event.py +27 -27
  72. telegrinder/bot/rules/adapter/raw_update.py +30 -30
  73. telegrinder/bot/rules/callback_data.py +163 -163
  74. telegrinder/bot/rules/chat_join.py +43 -43
  75. telegrinder/bot/rules/command.py +126 -126
  76. telegrinder/bot/rules/enum_text.py +36 -36
  77. telegrinder/bot/rules/func.py +26 -26
  78. telegrinder/bot/rules/fuzzy.py +24 -24
  79. telegrinder/bot/rules/inline.py +56 -56
  80. telegrinder/bot/rules/integer.py +20 -20
  81. telegrinder/bot/rules/is_from.py +127 -127
  82. telegrinder/bot/rules/markup.py +43 -43
  83. telegrinder/bot/rules/mention.py +14 -14
  84. telegrinder/bot/rules/message.py +17 -17
  85. telegrinder/bot/rules/message_entities.py +35 -35
  86. telegrinder/bot/rules/node.py +27 -27
  87. telegrinder/bot/rules/regex.py +37 -37
  88. telegrinder/bot/rules/rule_enum.py +72 -72
  89. telegrinder/bot/rules/start.py +42 -42
  90. telegrinder/bot/rules/state.py +37 -37
  91. telegrinder/bot/rules/text.py +33 -33
  92. telegrinder/bot/rules/update.py +15 -15
  93. telegrinder/bot/scenario/__init__.py +5 -5
  94. telegrinder/bot/scenario/abc.py +19 -19
  95. telegrinder/bot/scenario/checkbox.py +176 -176
  96. telegrinder/bot/scenario/choice.py +51 -51
  97. telegrinder/client/__init__.py +4 -4
  98. telegrinder/client/abc.py +75 -75
  99. telegrinder/client/aiohttp.py +130 -130
  100. telegrinder/model.py +313 -313
  101. telegrinder/modules.py +237 -237
  102. telegrinder/msgspec_json.py +14 -14
  103. telegrinder/msgspec_utils.py +410 -410
  104. telegrinder/node/__init__.py +20 -20
  105. telegrinder/node/attachment.py +87 -87
  106. telegrinder/node/base.py +157 -157
  107. telegrinder/node/callback_query.py +53 -53
  108. telegrinder/node/command.py +33 -33
  109. telegrinder/node/composer.py +198 -198
  110. telegrinder/node/container.py +27 -27
  111. telegrinder/node/event.py +65 -65
  112. telegrinder/node/me.py +16 -16
  113. telegrinder/node/message.py +14 -14
  114. telegrinder/node/polymorphic.py +48 -48
  115. telegrinder/node/rule.py +76 -76
  116. telegrinder/node/scope.py +38 -38
  117. telegrinder/node/source.py +71 -71
  118. telegrinder/node/text.py +41 -41
  119. telegrinder/node/tools/__init__.py +3 -3
  120. telegrinder/node/tools/generator.py +40 -40
  121. telegrinder/node/update.py +15 -15
  122. telegrinder/rules.py +5 -5
  123. telegrinder/tools/__init__.py +74 -74
  124. telegrinder/tools/buttons.py +79 -79
  125. telegrinder/tools/error_handler/__init__.py +7 -7
  126. telegrinder/tools/error_handler/abc.py +33 -33
  127. telegrinder/tools/error_handler/error.py +9 -9
  128. telegrinder/tools/error_handler/error_handler.py +193 -193
  129. telegrinder/tools/formatting/__init__.py +46 -46
  130. telegrinder/tools/formatting/html.py +283 -283
  131. telegrinder/tools/formatting/links.py +33 -33
  132. telegrinder/tools/formatting/spec_html_formats.py +111 -111
  133. telegrinder/tools/functional.py +12 -12
  134. telegrinder/tools/global_context/__init__.py +7 -7
  135. telegrinder/tools/global_context/abc.py +63 -63
  136. telegrinder/tools/global_context/global_context.py +412 -412
  137. telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
  138. telegrinder/tools/i18n/__init__.py +7 -7
  139. telegrinder/tools/i18n/abc.py +30 -30
  140. telegrinder/tools/i18n/middleware/__init__.py +3 -3
  141. telegrinder/tools/i18n/middleware/abc.py +25 -25
  142. telegrinder/tools/i18n/simple.py +43 -43
  143. telegrinder/tools/kb_set/__init__.py +4 -4
  144. telegrinder/tools/kb_set/base.py +15 -15
  145. telegrinder/tools/kb_set/yaml.py +63 -63
  146. telegrinder/tools/keyboard.py +128 -128
  147. telegrinder/tools/limited_dict.py +37 -37
  148. telegrinder/tools/loop_wrapper/__init__.py +4 -4
  149. telegrinder/tools/loop_wrapper/abc.py +15 -15
  150. telegrinder/tools/loop_wrapper/loop_wrapper.py +224 -224
  151. telegrinder/tools/magic.py +157 -157
  152. telegrinder/tools/parse_mode.py +6 -6
  153. telegrinder/tools/state_storage/__init__.py +4 -4
  154. telegrinder/tools/state_storage/abc.py +35 -35
  155. telegrinder/tools/state_storage/memory.py +25 -25
  156. telegrinder/types/__init__.py +260 -260
  157. telegrinder/types/enums.py +701 -701
  158. telegrinder/types/methods.py +4633 -4633
  159. telegrinder/types/objects.py +6950 -6950
  160. telegrinder/verification_utils.py +32 -32
  161. {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/LICENSE +22 -22
  162. {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/METADATA +1 -1
  163. telegrinder-0.3.4.post1.dist-info/RECORD +165 -0
  164. telegrinder-0.3.4.dist-info/RECORD +0 -165
  165. {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/WHEEL +0 -0
@@ -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=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
+ return self
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=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",)