telegrinder 0.3.1__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.

Files changed (164) 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 +11 -11
  10. telegrinder/bot/cute_types/base.py +258 -234
  11. telegrinder/bot/cute_types/callback_query.py +382 -382
  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 +53 -53
  15. telegrinder/bot/cute_types/message.py +2631 -2631
  16. telegrinder/bot/cute_types/update.py +75 -75
  17. telegrinder/bot/cute_types/utils.py +92 -92
  18. telegrinder/bot/dispatch/__init__.py +55 -55
  19. telegrinder/bot/dispatch/abc.py +77 -77
  20. telegrinder/bot/dispatch/context.py +92 -92
  21. telegrinder/bot/dispatch/dispatch.py +202 -201
  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 +128 -123
  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 +16 -16
  35. telegrinder/bot/dispatch/process.py +132 -132
  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 -211
  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 -118
  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 +57 -57
  55. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
  56. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +53 -53
  57. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
  58. telegrinder/bot/dispatch/waiter_machine/machine.py +168 -170
  59. telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
  60. telegrinder/bot/dispatch/waiter_machine/short_state.py +65 -65
  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 +238 -238
  66. telegrinder/bot/rules/adapter/__init__.py +9 -9
  67. telegrinder/bot/rules/adapter/abc.py +29 -29
  68. telegrinder/bot/rules/adapter/errors.py +5 -5
  69. telegrinder/bot/rules/adapter/event.py +76 -76
  70. telegrinder/bot/rules/adapter/node.py +48 -48
  71. telegrinder/bot/rules/adapter/raw_update.py +30 -30
  72. telegrinder/bot/rules/callback_data.py +171 -171
  73. telegrinder/bot/rules/chat_join.py +48 -48
  74. telegrinder/bot/rules/command.py +126 -126
  75. telegrinder/bot/rules/enum_text.py +36 -36
  76. telegrinder/bot/rules/func.py +26 -26
  77. telegrinder/bot/rules/fuzzy.py +24 -24
  78. telegrinder/bot/rules/inline.py +60 -60
  79. telegrinder/bot/rules/integer.py +20 -20
  80. telegrinder/bot/rules/is_from.py +146 -146
  81. telegrinder/bot/rules/markup.py +43 -43
  82. telegrinder/bot/rules/mention.py +14 -14
  83. telegrinder/bot/rules/message.py +17 -17
  84. telegrinder/bot/rules/message_entities.py +35 -35
  85. telegrinder/bot/rules/node.py +27 -27
  86. telegrinder/bot/rules/regex.py +37 -37
  87. telegrinder/bot/rules/rule_enum.py +72 -72
  88. telegrinder/bot/rules/start.py +42 -42
  89. telegrinder/bot/rules/state.py +37 -37
  90. telegrinder/bot/rules/text.py +33 -33
  91. telegrinder/bot/rules/update.py +15 -15
  92. telegrinder/bot/scenario/__init__.py +5 -5
  93. telegrinder/bot/scenario/abc.py +19 -19
  94. telegrinder/bot/scenario/checkbox.py +167 -147
  95. telegrinder/bot/scenario/choice.py +46 -44
  96. telegrinder/client/__init__.py +4 -4
  97. telegrinder/client/abc.py +75 -75
  98. telegrinder/client/aiohttp.py +130 -130
  99. telegrinder/model.py +244 -244
  100. telegrinder/modules.py +237 -237
  101. telegrinder/msgspec_json.py +14 -14
  102. telegrinder/msgspec_utils.py +410 -410
  103. telegrinder/node/__init__.py +20 -20
  104. telegrinder/node/attachment.py +92 -92
  105. telegrinder/node/base.py +143 -144
  106. telegrinder/node/callback_query.py +14 -14
  107. telegrinder/node/command.py +33 -33
  108. telegrinder/node/composer.py +196 -184
  109. telegrinder/node/container.py +27 -27
  110. telegrinder/node/event.py +71 -73
  111. telegrinder/node/me.py +16 -16
  112. telegrinder/node/message.py +14 -14
  113. telegrinder/node/polymorphic.py +48 -52
  114. telegrinder/node/rule.py +76 -76
  115. telegrinder/node/scope.py +38 -38
  116. telegrinder/node/source.py +71 -71
  117. telegrinder/node/text.py +21 -21
  118. telegrinder/node/tools/__init__.py +3 -3
  119. telegrinder/node/tools/generator.py +40 -40
  120. telegrinder/node/update.py +15 -15
  121. telegrinder/rules.py +0 -0
  122. telegrinder/tools/__init__.py +74 -74
  123. telegrinder/tools/buttons.py +79 -79
  124. telegrinder/tools/error_handler/__init__.py +7 -7
  125. telegrinder/tools/error_handler/abc.py +33 -33
  126. telegrinder/tools/error_handler/error.py +9 -9
  127. telegrinder/tools/error_handler/error_handler.py +193 -193
  128. telegrinder/tools/formatting/__init__.py +46 -46
  129. telegrinder/tools/formatting/html.py +308 -308
  130. telegrinder/tools/formatting/links.py +33 -33
  131. telegrinder/tools/formatting/spec_html_formats.py +111 -111
  132. telegrinder/tools/functional.py +12 -12
  133. telegrinder/tools/global_context/__init__.py +7 -7
  134. telegrinder/tools/global_context/abc.py +63 -63
  135. telegrinder/tools/global_context/global_context.py +412 -412
  136. telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
  137. telegrinder/tools/i18n/__init__.py +12 -12
  138. telegrinder/tools/i18n/abc.py +32 -32
  139. telegrinder/tools/i18n/middleware/__init__.py +3 -3
  140. telegrinder/tools/i18n/middleware/abc.py +25 -25
  141. telegrinder/tools/i18n/simple.py +43 -43
  142. telegrinder/tools/kb_set/__init__.py +4 -4
  143. telegrinder/tools/kb_set/base.py +15 -15
  144. telegrinder/tools/kb_set/yaml.py +63 -63
  145. telegrinder/tools/keyboard.py +128 -128
  146. telegrinder/tools/limited_dict.py +37 -37
  147. telegrinder/tools/loop_wrapper/__init__.py +4 -4
  148. telegrinder/tools/loop_wrapper/abc.py +15 -15
  149. telegrinder/tools/loop_wrapper/loop_wrapper.py +216 -216
  150. telegrinder/tools/magic.py +168 -168
  151. telegrinder/tools/parse_mode.py +6 -6
  152. telegrinder/tools/state_storage/__init__.py +4 -4
  153. telegrinder/tools/state_storage/abc.py +35 -35
  154. telegrinder/tools/state_storage/memory.py +25 -25
  155. telegrinder/types/__init__.py +6 -6
  156. telegrinder/types/enums.py +672 -672
  157. telegrinder/types/methods.py +4633 -4633
  158. telegrinder/types/objects.py +6317 -6317
  159. telegrinder/verification_utils.py +32 -32
  160. {telegrinder-0.3.1.dist-info → telegrinder-0.3.2.dist-info}/LICENSE +22 -22
  161. {telegrinder-0.3.1.dist-info → telegrinder-0.3.2.dist-info}/METADATA +1 -1
  162. telegrinder-0.3.2.dist-info/RECORD +164 -0
  163. telegrinder-0.3.1.dist-info/RECORD +0 -164
  164. {telegrinder-0.3.1.dist-info → telegrinder-0.3.2.dist-info}/WHEEL +0 -0
@@ -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
+ 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,12 +1,12 @@
1
- from .abc import ABCI18n, ABCTranslator, I18nEnum
2
- from .middleware import ABCTranslatorMiddleware
3
- from .simple import SimpleI18n, SimpleTranslator
4
-
5
- __all__ = (
6
- "ABCI18n",
7
- "ABCTranslator",
8
- "ABCTranslatorMiddleware",
9
- "I18nEnum",
10
- "SimpleI18n",
11
- "SimpleTranslator",
12
- )
1
+ from .abc import ABCI18n, ABCTranslator, I18nEnum
2
+ from .middleware import ABCTranslatorMiddleware
3
+ from .simple import SimpleI18n, SimpleTranslator
4
+
5
+ __all__ = (
6
+ "ABCI18n",
7
+ "ABCTranslator",
8
+ "ABCTranslatorMiddleware",
9
+ "I18nEnum",
10
+ "SimpleI18n",
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__ = (
29
- "ABCI18n",
30
- "ABCTranslator",
31
- "I18nEnum",
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__ = (
29
+ "ABCI18n",
30
+ "ABCTranslator",
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,25 @@
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
+ 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,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")
@@ -1,4 +1,4 @@
1
- from .base import KeyboardSetBase, KeyboardSetError
2
- from .yaml import KeyboardSetYAML
3
-
4
- __all__ = ("KeyboardSetBase", "KeyboardSetError", "KeyboardSetYAML")
1
+ from .base import KeyboardSetBase, KeyboardSetError
2
+ from .yaml import KeyboardSetYAML
3
+
4
+ __all__ = ("KeyboardSetBase", "KeyboardSetError", "KeyboardSetYAML")
@@ -1,15 +1,15 @@
1
- from abc import ABC, abstractmethod
2
-
3
-
4
- class KeyboardSetError(LookupError):
5
- pass
6
-
7
-
8
- class KeyboardSetBase(ABC):
9
- @classmethod
10
- @abstractmethod
11
- def load(cls) -> None:
12
- pass
13
-
14
-
15
- __all__ = ("KeyboardSetBase", "KeyboardSetError")
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class KeyboardSetError(LookupError):
5
+ pass
6
+
7
+
8
+ class KeyboardSetBase(ABC):
9
+ @classmethod
10
+ @abstractmethod
11
+ def load(cls) -> None:
12
+ pass
13
+
14
+
15
+ __all__ = ("KeyboardSetBase", "KeyboardSetError")
@@ -1,63 +1,63 @@
1
- import os
2
- import re
3
- import typing
4
-
5
- import yaml
6
-
7
- from telegrinder.tools.keyboard import InlineKeyboard, Keyboard
8
-
9
- from .base import KeyboardSetBase, KeyboardSetError
10
-
11
- PathLike: typing.TypeAlias = str | os.PathLike[str]
12
-
13
-
14
- class KeyboardSetYAML(KeyboardSetBase):
15
- __config__: PathLike
16
-
17
- @classmethod
18
- def load(cls) -> None:
19
- config_path = getattr(cls, "__config__", "keyboards.yaml")
20
- if not os.path.exists(config_path):
21
- raise FileNotFoundError(f"Config file for {cls.__name__!r} is undefined.")
22
-
23
- config = yaml.load(
24
- open( # noqa: SIM115
25
- str(config_path),
26
- mode="r",
27
- encoding="UTF-8",
28
- ),
29
- yaml.Loader,
30
- )
31
- for name, hint in typing.get_type_hints(cls).items():
32
- g = re.match(r"(?:kb_|keyboard_)(.+)", name.lower())
33
- if not g:
34
- continue
35
-
36
- short_name = g.group(1)
37
- if short_name not in config:
38
- raise KeyboardSetError(f"Keyboard {short_name!r} is undefined in config.")
39
-
40
- kb_config = config[short_name]
41
- if (
42
- not isinstance(kb_config, dict)
43
- or "buttons" not in kb_config
44
- or not isinstance(kb_config["buttons"], list)
45
- ):
46
- raise KeyboardSetError(
47
- "Keyboard should be dict with field buttons which must be a list, " "check documentation."
48
- )
49
-
50
- buttons = kb_config.pop("buttons")
51
- new_keyboard: Keyboard | InlineKeyboard = hint(**kb_config)
52
- for button in buttons:
53
- if not button:
54
- new_keyboard.row()
55
- continue
56
- if "text" not in button:
57
- raise KeyboardSetError("Text is required in button.")
58
- new_keyboard.add(new_keyboard.BUTTON(**button)) # type: ignore
59
-
60
- setattr(cls, name, new_keyboard)
61
-
62
-
63
- __all__ = ("KeyboardSetYAML",)
1
+ import os
2
+ import re
3
+ import typing
4
+
5
+ import yaml
6
+
7
+ from telegrinder.tools.keyboard import InlineKeyboard, Keyboard
8
+
9
+ from .base import KeyboardSetBase, KeyboardSetError
10
+
11
+ PathLike: typing.TypeAlias = str | os.PathLike[str]
12
+
13
+
14
+ class KeyboardSetYAML(KeyboardSetBase):
15
+ __config__: PathLike
16
+
17
+ @classmethod
18
+ def load(cls) -> None:
19
+ config_path = getattr(cls, "__config__", "keyboards.yaml")
20
+ if not os.path.exists(config_path):
21
+ raise FileNotFoundError(f"Config file for {cls.__name__!r} is undefined.")
22
+
23
+ config = yaml.load(
24
+ open( # noqa: SIM115
25
+ str(config_path),
26
+ mode="r",
27
+ encoding="UTF-8",
28
+ ),
29
+ yaml.Loader,
30
+ )
31
+ for name, hint in typing.get_type_hints(cls).items():
32
+ g = re.match(r"(?:kb_|keyboard_)(.+)", name.lower())
33
+ if not g:
34
+ continue
35
+
36
+ short_name = g.group(1)
37
+ if short_name not in config:
38
+ raise KeyboardSetError(f"Keyboard {short_name!r} is undefined in config.")
39
+
40
+ kb_config = config[short_name]
41
+ if (
42
+ not isinstance(kb_config, dict)
43
+ or "buttons" not in kb_config
44
+ or not isinstance(kb_config["buttons"], list)
45
+ ):
46
+ raise KeyboardSetError(
47
+ "Keyboard should be dict with field buttons which must be a list, " "check documentation."
48
+ )
49
+
50
+ buttons = kb_config.pop("buttons")
51
+ new_keyboard: Keyboard | InlineKeyboard = hint(**kb_config)
52
+ for button in buttons:
53
+ if not button:
54
+ new_keyboard.row()
55
+ continue
56
+ if "text" not in button:
57
+ raise KeyboardSetError("Text is required in button.")
58
+ new_keyboard.add(new_keyboard.BUTTON(**button)) # type: ignore
59
+
60
+ setattr(cls, name, new_keyboard)
61
+
62
+
63
+ __all__ = ("KeyboardSetYAML",)