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.

Files changed (192) hide show
  1. telegrinder/__init__.py +148 -149
  2. telegrinder/api/__init__.py +9 -8
  3. telegrinder/api/api.py +101 -93
  4. telegrinder/api/error.py +20 -16
  5. telegrinder/api/response.py +20 -20
  6. telegrinder/api/token.py +36 -36
  7. telegrinder/bot/__init__.py +72 -66
  8. telegrinder/bot/bot.py +83 -76
  9. telegrinder/bot/cute_types/__init__.py +19 -17
  10. telegrinder/bot/cute_types/base.py +184 -258
  11. telegrinder/bot/cute_types/callback_query.py +400 -385
  12. telegrinder/bot/cute_types/chat_join_request.py +62 -61
  13. telegrinder/bot/cute_types/chat_member_updated.py +157 -160
  14. telegrinder/bot/cute_types/inline_query.py +44 -43
  15. telegrinder/bot/cute_types/message.py +2590 -2637
  16. telegrinder/bot/cute_types/pre_checkout_query.py +42 -0
  17. telegrinder/bot/cute_types/update.py +112 -104
  18. telegrinder/bot/cute_types/utils.py +62 -95
  19. telegrinder/bot/dispatch/__init__.py +59 -55
  20. telegrinder/bot/dispatch/abc.py +76 -77
  21. telegrinder/bot/dispatch/context.py +96 -98
  22. telegrinder/bot/dispatch/dispatch.py +254 -202
  23. telegrinder/bot/dispatch/handler/__init__.py +13 -13
  24. telegrinder/bot/dispatch/handler/abc.py +23 -24
  25. telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
  26. telegrinder/bot/dispatch/handler/base.py +57 -57
  27. telegrinder/bot/dispatch/handler/document_reply.py +44 -44
  28. telegrinder/bot/dispatch/handler/func.py +129 -135
  29. telegrinder/bot/dispatch/handler/media_group_reply.py +44 -43
  30. telegrinder/bot/dispatch/handler/message_reply.py +36 -36
  31. telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
  32. telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
  33. telegrinder/bot/dispatch/handler/video_reply.py +44 -44
  34. telegrinder/bot/dispatch/middleware/__init__.py +3 -3
  35. telegrinder/bot/dispatch/middleware/abc.py +97 -22
  36. telegrinder/bot/dispatch/middleware/global_middleware.py +70 -0
  37. telegrinder/bot/dispatch/process.py +151 -157
  38. telegrinder/bot/dispatch/return_manager/__init__.py +15 -13
  39. telegrinder/bot/dispatch/return_manager/abc.py +104 -108
  40. telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
  41. telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
  42. telegrinder/bot/dispatch/return_manager/message.py +36 -36
  43. telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +20 -0
  44. telegrinder/bot/dispatch/view/__init__.py +15 -13
  45. telegrinder/bot/dispatch/view/abc.py +45 -41
  46. telegrinder/bot/dispatch/view/base.py +231 -200
  47. telegrinder/bot/dispatch/view/box.py +140 -129
  48. telegrinder/bot/dispatch/view/callback_query.py +16 -17
  49. telegrinder/bot/dispatch/view/chat_join_request.py +11 -16
  50. telegrinder/bot/dispatch/view/chat_member.py +37 -39
  51. telegrinder/bot/dispatch/view/inline_query.py +16 -17
  52. telegrinder/bot/dispatch/view/message.py +43 -44
  53. telegrinder/bot/dispatch/view/pre_checkout_query.py +16 -0
  54. telegrinder/bot/dispatch/view/raw.py +116 -114
  55. telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
  56. telegrinder/bot/dispatch/waiter_machine/actions.py +14 -13
  57. telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
  58. telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
  59. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +59 -57
  60. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
  61. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +20 -19
  62. telegrinder/bot/dispatch/waiter_machine/machine.py +251 -172
  63. telegrinder/bot/dispatch/waiter_machine/middleware.py +94 -89
  64. telegrinder/bot/dispatch/waiter_machine/short_state.py +57 -68
  65. telegrinder/bot/polling/__init__.py +4 -4
  66. telegrinder/bot/polling/abc.py +25 -25
  67. telegrinder/bot/polling/polling.py +139 -131
  68. telegrinder/bot/rules/__init__.py +85 -62
  69. telegrinder/bot/rules/abc.py +213 -206
  70. telegrinder/bot/rules/callback_data.py +122 -163
  71. telegrinder/bot/rules/chat_join.py +45 -43
  72. telegrinder/bot/rules/command.py +126 -126
  73. telegrinder/bot/rules/enum_text.py +33 -36
  74. telegrinder/bot/rules/func.py +28 -26
  75. telegrinder/bot/rules/fuzzy.py +24 -24
  76. telegrinder/bot/rules/id.py +24 -0
  77. telegrinder/bot/rules/inline.py +58 -56
  78. telegrinder/bot/rules/integer.py +21 -20
  79. telegrinder/bot/rules/is_from.py +127 -127
  80. telegrinder/bot/rules/logic.py +18 -0
  81. telegrinder/bot/rules/markup.py +42 -43
  82. telegrinder/bot/rules/mention.py +14 -14
  83. telegrinder/bot/rules/message.py +15 -17
  84. telegrinder/bot/rules/message_entities.py +33 -35
  85. telegrinder/bot/rules/node.py +33 -27
  86. telegrinder/bot/rules/payload.py +81 -0
  87. telegrinder/bot/rules/payment_invoice.py +29 -0
  88. telegrinder/bot/rules/regex.py +36 -37
  89. telegrinder/bot/rules/rule_enum.py +72 -72
  90. telegrinder/bot/rules/start.py +42 -42
  91. telegrinder/bot/rules/state.py +35 -37
  92. telegrinder/bot/rules/text.py +38 -33
  93. telegrinder/bot/rules/update.py +15 -15
  94. telegrinder/bot/scenario/__init__.py +5 -5
  95. telegrinder/bot/scenario/abc.py +17 -19
  96. telegrinder/bot/scenario/checkbox.py +174 -176
  97. telegrinder/bot/scenario/choice.py +48 -51
  98. telegrinder/client/__init__.py +12 -4
  99. telegrinder/client/abc.py +100 -75
  100. telegrinder/client/aiohttp.py +134 -130
  101. telegrinder/client/form_data.py +31 -0
  102. telegrinder/client/sonic.py +212 -0
  103. telegrinder/model.py +208 -315
  104. telegrinder/modules.py +239 -237
  105. telegrinder/msgspec_json.py +14 -14
  106. telegrinder/msgspec_utils.py +478 -410
  107. telegrinder/node/__init__.py +86 -25
  108. telegrinder/node/attachment.py +163 -87
  109. telegrinder/node/base.py +288 -160
  110. telegrinder/node/callback_query.py +54 -53
  111. telegrinder/node/command.py +34 -33
  112. telegrinder/node/composer.py +163 -198
  113. telegrinder/node/container.py +33 -27
  114. telegrinder/node/either.py +82 -0
  115. telegrinder/node/event.py +54 -65
  116. telegrinder/node/file.py +51 -0
  117. telegrinder/node/me.py +15 -16
  118. telegrinder/node/payload.py +78 -0
  119. telegrinder/node/polymorphic.py +67 -48
  120. telegrinder/node/rule.py +72 -76
  121. telegrinder/node/scope.py +36 -38
  122. telegrinder/node/source.py +87 -71
  123. telegrinder/node/text.py +53 -41
  124. telegrinder/node/tools/__init__.py +3 -3
  125. telegrinder/node/tools/generator.py +36 -40
  126. telegrinder/py.typed +0 -0
  127. telegrinder/rules.py +1 -62
  128. telegrinder/tools/__init__.py +152 -93
  129. telegrinder/tools/adapter/__init__.py +19 -0
  130. telegrinder/tools/adapter/abc.py +49 -0
  131. telegrinder/tools/adapter/dataclass.py +56 -0
  132. telegrinder/{bot/rules → tools}/adapter/errors.py +5 -5
  133. telegrinder/{bot/rules → tools}/adapter/event.py +63 -65
  134. telegrinder/{bot/rules → tools}/adapter/node.py +46 -48
  135. telegrinder/{bot/rules → tools}/adapter/raw_event.py +27 -27
  136. telegrinder/{bot/rules → tools}/adapter/raw_update.py +30 -30
  137. telegrinder/tools/buttons.py +106 -80
  138. telegrinder/tools/callback_data_serilization/__init__.py +5 -0
  139. telegrinder/tools/callback_data_serilization/abc.py +51 -0
  140. telegrinder/tools/callback_data_serilization/json_ser.py +60 -0
  141. telegrinder/tools/callback_data_serilization/msgpack_ser.py +172 -0
  142. telegrinder/tools/error_handler/__init__.py +7 -7
  143. telegrinder/tools/error_handler/abc.py +30 -33
  144. telegrinder/tools/error_handler/error.py +9 -9
  145. telegrinder/tools/error_handler/error_handler.py +179 -193
  146. telegrinder/tools/formatting/__init__.py +83 -63
  147. telegrinder/tools/formatting/deep_links.py +541 -0
  148. telegrinder/tools/formatting/{html.py → html_formatter.py} +266 -294
  149. telegrinder/tools/formatting/spec_html_formats.py +71 -117
  150. telegrinder/tools/functional.py +8 -12
  151. telegrinder/tools/global_context/__init__.py +7 -7
  152. telegrinder/tools/global_context/abc.py +63 -63
  153. telegrinder/tools/global_context/global_context.py +387 -412
  154. telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
  155. telegrinder/tools/i18n/__init__.py +7 -7
  156. telegrinder/tools/i18n/abc.py +30 -30
  157. telegrinder/tools/i18n/middleware/__init__.py +3 -3
  158. telegrinder/tools/i18n/middleware/abc.py +22 -25
  159. telegrinder/tools/i18n/simple.py +43 -43
  160. telegrinder/tools/input_file_directory.py +30 -0
  161. telegrinder/tools/keyboard.py +128 -128
  162. telegrinder/tools/lifespan.py +105 -0
  163. telegrinder/tools/limited_dict.py +32 -37
  164. telegrinder/tools/loop_wrapper/__init__.py +4 -4
  165. telegrinder/tools/loop_wrapper/abc.py +20 -15
  166. telegrinder/tools/loop_wrapper/loop_wrapper.py +169 -224
  167. telegrinder/tools/magic.py +307 -157
  168. telegrinder/tools/parse_mode.py +6 -6
  169. telegrinder/tools/state_storage/__init__.py +4 -4
  170. telegrinder/tools/state_storage/abc.py +31 -35
  171. telegrinder/tools/state_storage/memory.py +25 -25
  172. telegrinder/tools/strings.py +13 -0
  173. telegrinder/types/__init__.py +268 -260
  174. telegrinder/types/enums.py +711 -701
  175. telegrinder/types/input_file.py +51 -0
  176. telegrinder/types/methods.py +5055 -4633
  177. telegrinder/types/objects.py +7058 -6950
  178. telegrinder/verification_utils.py +30 -32
  179. {telegrinder-0.3.4.dist-info → telegrinder-0.4.0.dist-info}/LICENSE +22 -22
  180. telegrinder-0.4.0.dist-info/METADATA +144 -0
  181. telegrinder-0.4.0.dist-info/RECORD +182 -0
  182. {telegrinder-0.3.4.dist-info → telegrinder-0.4.0.dist-info}/WHEEL +1 -1
  183. telegrinder/bot/rules/adapter/__init__.py +0 -17
  184. telegrinder/bot/rules/adapter/abc.py +0 -31
  185. telegrinder/node/message.py +0 -14
  186. telegrinder/node/update.py +0 -15
  187. telegrinder/tools/formatting/links.py +0 -38
  188. telegrinder/tools/kb_set/__init__.py +0 -4
  189. telegrinder/tools/kb_set/base.py +0 -15
  190. telegrinder/tools/kb_set/yaml.py +0 -63
  191. telegrinder-0.3.4.dist-info/METADATA +0 -110
  192. telegrinder-0.3.4.dist-info/RECORD +0 -165
@@ -1,27 +1,27 @@
1
- import re
2
- import typing
3
-
4
- import vbml
5
-
6
- from telegrinder.tools.global_context import GlobalContext, ctx_var
7
-
8
-
9
- class TelegrinderContext(GlobalContext):
10
- """Basic type-hinted telegrinder context with context name `"telegrinder"`.
11
-
12
- You can use this class or GlobalContext:
13
- ```
14
- from telegrinder.tools.global_context import GlobalContext, TelegrinderContext
15
-
16
- ctx1 = TelegrinderContext()
17
- ctx2 = GlobalContext("telegrinder") # same, but without the type-hints
18
- assert ctx1 == ctx2 # ok
19
- ```"""
20
-
21
- __ctx_name__ = "telegrinder"
22
-
23
- vbml_pattern_flags: re.RegexFlag | None = None
24
- vbml_patcher: typing.ClassVar[vbml.Patcher] = ctx_var(vbml.Patcher(), const=True)
25
-
26
-
27
- __all__ = ("TelegrinderContext",)
1
+ import re
2
+
3
+ import vbml
4
+
5
+ from telegrinder.tools.global_context import GlobalContext, ctx_var
6
+
7
+
8
+ class TelegrinderContext(GlobalContext):
9
+ """Basic type-hinted telegrinder context with context name `"telegrinder"`.
10
+
11
+ You can use this class or GlobalContext:
12
+ ```
13
+ from telegrinder.tools.global_context import GlobalContext, TelegrinderContext
14
+
15
+ ctx1 = TelegrinderContext()
16
+ ctx2 = GlobalContext("telegrinder") # same, but without the type-hints
17
+ assert ctx1 == ctx2 # ok
18
+ ```
19
+ """
20
+
21
+ __ctx_name__ = "telegrinder"
22
+
23
+ vbml_pattern_flags: re.RegexFlag | None = None
24
+ vbml_patcher: vbml.Patcher = ctx_var(default=vbml.Patcher(), frozen=True)
25
+
26
+
27
+ __all__ = ("TelegrinderContext",)
@@ -1,12 +1,12 @@
1
- from .abc import ABCI18n, ABCTranslator, I18nEnum
2
- from .middleware import ABCTranslatorMiddleware
3
- from .simple import SimpleI18n, SimpleTranslator
4
-
5
- __all__ = (
1
+ from .abc import ABCI18n, ABCTranslator, I18nEnum
2
+ from .middleware import ABCTranslatorMiddleware
3
+ from .simple import SimpleI18n, SimpleTranslator
4
+
5
+ __all__ = (
6
6
  "ABCI18n",
7
7
  "ABCTranslator",
8
8
  "ABCTranslatorMiddleware",
9
9
  "I18nEnum",
10
10
  "SimpleI18n",
11
- "SimpleTranslator",
12
- )
11
+ "SimpleTranslator",
12
+ )
@@ -1,32 +1,32 @@
1
- import enum
2
- import typing
3
- from abc import ABC, abstractmethod
4
-
5
-
6
- class ABCI18n(ABC):
7
- @abstractmethod
8
- def get_translator_by_locale(self, locale: str) -> "ABCTranslator":
9
- pass
10
-
11
-
12
- class ABCTranslator(ABC):
13
- def __init__(self, locale: str, **kwargs: typing.Any) -> None:
14
- self.locale = locale
15
-
16
- @abstractmethod
17
- def get(self, __key: str, *args: typing.Any, **kwargs: typing.Any) -> str:
18
- """This translates a key to actual human-readable string"""
19
-
20
- def __call__(self, __key: str, *args: typing.Any, **kwargs: typing.Any) -> str:
21
- return self.get(__key, *args, **kwargs)
22
-
23
-
24
- class I18nEnum(enum.Enum):
25
- I18N = "_"
26
-
27
-
28
- __all__ = (
1
+ import enum
2
+ import typing
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+ class ABCI18n(ABC):
7
+ @abstractmethod
8
+ def get_translator_by_locale(self, locale: str) -> "ABCTranslator":
9
+ pass
10
+
11
+
12
+ class ABCTranslator(ABC):
13
+ def __init__(self, locale: str, **kwargs: typing.Any) -> None:
14
+ self.locale = locale
15
+
16
+ @abstractmethod
17
+ def get(self, __key: str, *args: typing.Any, **kwargs: typing.Any) -> str:
18
+ """This translates a key to actual human-readable string"""
19
+
20
+ def __call__(self, __key: str, *args: typing.Any, **kwargs: typing.Any) -> str:
21
+ return self.get(__key, *args, **kwargs)
22
+
23
+
24
+ class I18nEnum(enum.Enum):
25
+ I18N = "_"
26
+
27
+
28
+ __all__ = (
29
29
  "ABCI18n",
30
30
  "ABCTranslator",
31
- "I18nEnum",
32
- )
31
+ "I18nEnum",
32
+ )
@@ -1,3 +1,3 @@
1
- from .abc import ABCTranslatorMiddleware
2
-
3
- __all__ = ("ABCTranslatorMiddleware",)
1
+ from .abc import ABCTranslatorMiddleware
2
+
3
+ __all__ = ("ABCTranslatorMiddleware",)
@@ -1,25 +1,22 @@
1
- import typing
2
- from abc import abstractmethod
3
-
4
- from telegrinder.bot.cute_types.base import BaseCute
5
- from telegrinder.bot.dispatch.context import Context
6
- from telegrinder.bot.dispatch.middleware import ABCMiddleware
7
- from telegrinder.tools.i18n import ABCI18n, I18nEnum
8
-
9
- T = typing.TypeVar("T", bound=BaseCute)
10
-
11
-
12
- class ABCTranslatorMiddleware(ABCMiddleware[T]):
13
- def __init__(self, i18n: ABCI18n) -> None:
14
- self.i18n = i18n
15
-
16
- @abstractmethod
17
- async def get_locale(self, event: T) -> str:
18
- pass
19
-
20
- async def pre(self, event: T, ctx: Context) -> bool:
21
- ctx[I18nEnum.I18N] = self.i18n.get_translator_by_locale(await self.get_locale(event))
22
- return True
23
-
24
-
25
- __all__ = ("ABCTranslatorMiddleware",)
1
+ from abc import abstractmethod
2
+
3
+ from telegrinder.bot.cute_types.base import BaseCute
4
+ from telegrinder.bot.dispatch.context import Context
5
+ from telegrinder.bot.dispatch.middleware import ABCMiddleware
6
+ from telegrinder.tools.i18n import ABCI18n, I18nEnum
7
+
8
+
9
+ class ABCTranslatorMiddleware[Event: BaseCute](ABCMiddleware[Event]):
10
+ def __init__(self, i18n: ABCI18n) -> None:
11
+ self.i18n = i18n
12
+
13
+ @abstractmethod
14
+ async def get_locale(self, event: Event) -> str:
15
+ pass
16
+
17
+ async def pre(self, event: Event, ctx: Context) -> bool:
18
+ ctx[I18nEnum.I18N] = self.i18n.get_translator_by_locale(await self.get_locale(event))
19
+ return True
20
+
21
+
22
+ __all__ = ("ABCTranslatorMiddleware",)
@@ -1,43 +1,43 @@
1
- """This is an implementation of GNU gettext (pyBabel)."""
2
-
3
- import gettext
4
- import os
5
-
6
- from telegrinder.tools.i18n.abc import ABCI18n, ABCTranslator
7
-
8
-
9
- class SimpleTranslator(ABCTranslator):
10
- def __init__(self, locale: str, g: gettext.GNUTranslations) -> None:
11
- self.g = g
12
- super().__init__(locale)
13
-
14
- def get(self, __key: str, *args: object, **kwargs: object) -> str:
15
- return self.g.gettext(__key).format(*args, **kwargs)
16
-
17
-
18
- class SimpleI18n(ABCI18n):
19
- def __init__(self, folder: str, domain: str, default_locale: str) -> None:
20
- self.folder = folder
21
- self.domain = domain
22
- self.default_locale = default_locale
23
- self.translators = self._load_translators()
24
-
25
- def _load_translators(self) -> dict[str, gettext.GNUTranslations]:
26
- result = {}
27
- for name in os.listdir(self.folder):
28
- if not os.path.isdir(os.path.join(self.folder, name)):
29
- continue
30
-
31
- mo_path = os.path.join(self.folder, name, "LC_MESSAGES", f"{self.domain}.mo")
32
- if os.path.exists(mo_path):
33
- with open(mo_path, "rb") as f:
34
- result[name] = gettext.GNUTranslations(f)
35
- elif os.path.exists(mo_path[:-2] + "po"):
36
- raise FileNotFoundError(".po files should be compiled first")
37
- return result
38
-
39
- def get_translator_by_locale(self, locale: str) -> "SimpleTranslator":
40
- return SimpleTranslator(locale, self.translators.get(locale, self.translators[self.default_locale]))
41
-
42
-
43
- __all__ = ("SimpleI18n", "SimpleTranslator")
1
+ """This is an implementation of GNU gettext (pyBabel)."""
2
+
3
+ import gettext
4
+ import os
5
+
6
+ from telegrinder.tools.i18n.abc import ABCI18n, ABCTranslator
7
+
8
+
9
+ class SimpleTranslator(ABCTranslator):
10
+ def __init__(self, locale: str, g: gettext.GNUTranslations) -> None:
11
+ self.g = g
12
+ super().__init__(locale)
13
+
14
+ def get(self, __key: str, *args: object, **kwargs: object) -> str:
15
+ return self.g.gettext(__key).format(*args, **kwargs)
16
+
17
+
18
+ class SimpleI18n(ABCI18n):
19
+ def __init__(self, folder: str, domain: str, default_locale: str) -> None:
20
+ self.folder = folder
21
+ self.domain = domain
22
+ self.default_locale = default_locale
23
+ self.translators = self._load_translators()
24
+
25
+ def _load_translators(self) -> dict[str, gettext.GNUTranslations]:
26
+ result = {}
27
+ for name in os.listdir(self.folder):
28
+ if not os.path.isdir(os.path.join(self.folder, name)):
29
+ continue
30
+
31
+ mo_path = os.path.join(self.folder, name, "LC_MESSAGES", f"{self.domain}.mo")
32
+ if os.path.exists(mo_path):
33
+ with open(mo_path, "rb") as f:
34
+ result[name] = gettext.GNUTranslations(f)
35
+ elif os.path.exists(mo_path[:-2] + "po"):
36
+ raise FileNotFoundError(".po files should be compiled first")
37
+ return result
38
+
39
+ def get_translator_by_locale(self, locale: str) -> "SimpleTranslator":
40
+ return SimpleTranslator(locale, self.translators.get(locale, self.translators[self.default_locale]))
41
+
42
+
43
+ __all__ = ("SimpleI18n", "SimpleTranslator")
@@ -0,0 +1,30 @@
1
+ import dataclasses
2
+ import pathlib
3
+
4
+ from telegrinder.types.objects import InputFile
5
+
6
+
7
+ @dataclasses.dataclass
8
+ class InputFileDirectory:
9
+ directory: pathlib.Path
10
+ storage: dict[str, InputFile] = dataclasses.field(init=False, repr=False)
11
+
12
+ def __post_init__(self) -> None:
13
+ self.storage = self._load_files()
14
+
15
+ def _load_files(self) -> dict[str, InputFile]:
16
+ files = {}
17
+
18
+ for path in self.directory.rglob("*"):
19
+ if path.is_file():
20
+ relative_path = path.relative_to(self.directory)
21
+ files[str(relative_path)] = InputFile(path.name, path.read_bytes())
22
+
23
+ return files
24
+
25
+ def get(self, filename: str, /) -> InputFile:
26
+ assert filename in self.storage, f"File {filename!r} not found."
27
+ return self.storage[filename]
28
+
29
+
30
+ __all__ = ("InputFileDirectory",)
@@ -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
+
5
+ from fntypes.option import Some
6
+
7
+ from telegrinder.model import is_none
8
+ from telegrinder.types.objects import (
9
+ InlineKeyboardMarkup,
10
+ ReplyKeyboardMarkup,
11
+ ReplyKeyboardRemove,
12
+ )
13
+
14
+ from .buttons import BaseButton, Button, InlineButton, RowButtons
15
+
16
+ type DictStrAny = dict[str, typing.Any]
17
+ type AnyMarkup = 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[KeyboardButton: BaseButton](ABC):
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 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 not is_none(v)
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
+ )