telegrinder 0.1.dev158__tar.gz → 0.1.dev160__tar.gz

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 (137) hide show
  1. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/LICENSE +0 -0
  2. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/PKG-INFO +9 -7
  3. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/pyproject.toml +18 -11
  4. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/readme.md +1 -1
  5. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/__init__.py +4 -2
  6. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/api/__init__.py +0 -0
  7. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/api/abc.py +6 -4
  8. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/api/api.py +25 -11
  9. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/api/error.py +0 -0
  10. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/api/response.py +0 -0
  11. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/__init__.py +0 -0
  12. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/bot.py +0 -0
  13. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/cute_types/__init__.py +0 -0
  14. telegrinder-0.1.dev160/telegrinder/bot/cute_types/base.py +138 -0
  15. telegrinder-0.1.dev160/telegrinder/bot/cute_types/callback_query.py +467 -0
  16. telegrinder-0.1.dev160/telegrinder/bot/cute_types/inline_query.py +68 -0
  17. telegrinder-0.1.dev160/telegrinder/bot/cute_types/message.py +2961 -0
  18. telegrinder-0.1.dev160/telegrinder/bot/cute_types/update.py +30 -0
  19. telegrinder-0.1.dev160/telegrinder/bot/cute_types/utils.py +542 -0
  20. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/__init__.py +0 -0
  21. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/abc.py +0 -0
  22. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/composition.py +0 -0
  23. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/context.py +0 -0
  24. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/dispatch.py +0 -0
  25. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/handler/__init__.py +0 -0
  26. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/handler/abc.py +0 -0
  27. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/handler/func.py +1 -1
  28. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/handler/message_reply.py +0 -0
  29. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/middleware/__init__.py +0 -0
  30. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/middleware/abc.py +0 -0
  31. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/process.py +0 -0
  32. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/return_manager/__init__.py +0 -0
  33. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/return_manager/abc.py +0 -0
  34. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/return_manager/callback_query.py +0 -0
  35. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/return_manager/inline_query.py +0 -0
  36. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/return_manager/message.py +0 -0
  37. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/view/__init__.py +0 -0
  38. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/view/abc.py +40 -29
  39. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/view/box.py +0 -0
  40. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/view/callback_query.py +0 -0
  41. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/view/inline_query.py +0 -0
  42. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/view/message.py +0 -0
  43. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/waiter_machine/__init__.py +0 -0
  44. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/waiter_machine/machine.py +0 -0
  45. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/waiter_machine/middleware.py +0 -0
  46. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/dispatch/waiter_machine/short_state.py +0 -0
  47. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/polling/__init__.py +0 -0
  48. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/polling/abc.py +0 -0
  49. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/polling/polling.py +7 -11
  50. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/__init__.py +0 -0
  51. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/abc.py +1 -1
  52. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/adapter/__init__.py +0 -0
  53. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/adapter/abc.py +0 -0
  54. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/adapter/errors.py +0 -0
  55. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/adapter/event.py +12 -6
  56. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/adapter/raw_update.py +0 -0
  57. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/callback_data.py +3 -11
  58. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/command.py +0 -0
  59. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/enum_text.py +0 -0
  60. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/func.py +0 -0
  61. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/fuzzy.py +0 -0
  62. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/inline.py +2 -1
  63. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/integer.py +0 -0
  64. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/is_from.py +0 -0
  65. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/markup.py +3 -1
  66. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/mention.py +0 -0
  67. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/message_entities.py +3 -1
  68. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/regex.py +1 -1
  69. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/rule_enum.py +0 -0
  70. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/start.py +0 -0
  71. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/rules/text.py +0 -0
  72. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/scenario/__init__.py +0 -0
  73. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/scenario/abc.py +0 -0
  74. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/scenario/checkbox.py +0 -0
  75. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/bot/scenario/choice.py +0 -0
  76. telegrinder-0.1.dev160/telegrinder/client/__init__.py +4 -0
  77. telegrinder-0.1.dev160/telegrinder/client/abc.py +75 -0
  78. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/client/aiohttp.py +35 -22
  79. telegrinder-0.1.dev160/telegrinder/model.py +143 -0
  80. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/modules.py +22 -12
  81. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/msgspec_json.py +0 -0
  82. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/msgspec_utils.py +30 -10
  83. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/__init__.py +0 -0
  84. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/attachment.py +0 -0
  85. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/base.py +0 -0
  86. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/composer.py +0 -0
  87. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/container.py +0 -0
  88. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/message.py +0 -0
  89. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/rule.py +0 -0
  90. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/source.py +0 -0
  91. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/text.py +0 -0
  92. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/tools/__init__.py +0 -0
  93. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/tools/generator.py +0 -0
  94. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/node/update.py +0 -0
  95. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/rules.py +0 -0
  96. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/__init__.py +2 -30
  97. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/buttons.py +19 -5
  98. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/error_handler/__init__.py +2 -0
  99. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/error_handler/abc.py +5 -1
  100. telegrinder-0.1.dev160/telegrinder/tools/error_handler/error.py +10 -0
  101. telegrinder-0.1.dev160/telegrinder/tools/error_handler/error_handler.py +175 -0
  102. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/formatting/__init__.py +0 -0
  103. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/formatting/html.py +0 -0
  104. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/formatting/links.py +0 -0
  105. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/formatting/spec_html_formats.py +0 -0
  106. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/global_context/__init__.py +0 -0
  107. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/global_context/abc.py +0 -0
  108. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/global_context/global_context.py +65 -67
  109. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/global_context/telegrinder_ctx.py +0 -0
  110. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/i18n/__init__.py +0 -0
  111. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/i18n/base.py +0 -0
  112. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/i18n/middleware/__init__.py +0 -0
  113. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/i18n/middleware/base.py +0 -0
  114. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/i18n/simple.py +0 -0
  115. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/kb_set/__init__.py +0 -0
  116. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/kb_set/base.py +0 -0
  117. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/kb_set/yaml.py +3 -3
  118. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/keyboard.py +17 -26
  119. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/loop_wrapper/__init__.py +0 -0
  120. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/loop_wrapper/abc.py +0 -0
  121. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/loop_wrapper/loop_wrapper.py +0 -0
  122. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/magic.py +1 -1
  123. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/tools/parse_mode.py +0 -0
  124. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/types/__init__.py +0 -0
  125. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/types/enums.py +13 -9
  126. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/types/methods.py +783 -673
  127. {telegrinder-0.1.dev158 → telegrinder-0.1.dev160}/telegrinder/types/objects.py +317 -163
  128. telegrinder-0.1.dev158/telegrinder/bot/cute_types/base.py +0 -47
  129. telegrinder-0.1.dev158/telegrinder/bot/cute_types/callback_query.py +0 -78
  130. telegrinder-0.1.dev158/telegrinder/bot/cute_types/inline_query.py +0 -41
  131. telegrinder-0.1.dev158/telegrinder/bot/cute_types/message.py +0 -193
  132. telegrinder-0.1.dev158/telegrinder/bot/cute_types/update.py +0 -23
  133. telegrinder-0.1.dev158/telegrinder/client/__init__.py +0 -4
  134. telegrinder-0.1.dev158/telegrinder/client/abc.py +0 -52
  135. telegrinder-0.1.dev158/telegrinder/model.py +0 -96
  136. telegrinder-0.1.dev158/telegrinder/tools/error_handler/error_handler.py +0 -156
  137. telegrinder-0.1.dev158/telegrinder/tools/inline_query.py +0 -684
@@ -1,32 +1,34 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: telegrinder
3
- Version: 0.1.dev158
3
+ Version: 0.1.dev160
4
4
  Summary: Framework for effective and reliable async telegram bot building.
5
5
  Home-page: https://github.com/timoniq/telegrinder
6
6
  License: MIT
7
- Keywords: telegram,telegram bot api framework,telegrinder,asyncio,middleware,composition,bot api,async
7
+ Keywords: asyncio,api schema,async,bot building,bot api,custom rules,telegram,telegram bot api framework,telegrinder,middleware,composition
8
8
  Author: timoniq
9
9
  Author-email: tesseradecades@mail.ru
10
10
  Maintainer: luwqz1
11
+ Maintainer-email: howluwqz1@gmail.com
11
12
  Requires-Python: >=3.11,<4.0
12
13
  Classifier: Environment :: Console
13
14
  Classifier: Intended Audience :: Developers
14
15
  Classifier: License :: OSI Approved :: MIT License
15
16
  Classifier: Programming Language :: Python :: 3
16
17
  Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
17
19
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
20
  Classifier: Topic :: Software Development :: Quality Assurance
19
21
  Classifier: Typing :: Typed
20
22
  Requires-Dist: PyYAML (>=6.0,<7.0)
21
23
  Requires-Dist: aiohttp (>=3.8.1,<4.0.0)
22
- Requires-Dist: certifi (>=2022.6.15,<2023.0.0)
24
+ Requires-Dist: certifi (>=2024.2.2,<2025.0.0)
23
25
  Requires-Dist: choicelib (>=0.1.5,<0.2.0)
24
26
  Requires-Dist: colorama (>=0.4.0,<0.5.0)
25
27
  Requires-Dist: envparse (>=0.2.0,<0.3.0)
26
- Requires-Dist: fntypes (>=0.1.1,<0.2.0)
27
- Requires-Dist: msgspec (>=0.18.4,<0.19.0)
28
+ Requires-Dist: fntypes (>=0.1.2.post1,<0.2.0)
29
+ Requires-Dist: msgspec (>=0.18.6,<0.19.0)
28
30
  Requires-Dist: requests (>=2.28.1,<3.0.0)
29
- Requires-Dist: typing-extensions (>=4.8.0,<5.0.0)
31
+ Requires-Dist: typing-extensions (>=4.10.0,<5.0.0)
30
32
  Requires-Dist: vbml (>=1.1.post1,<2.0)
31
33
  Project-URL: Repository, https://github.com/timoniq/telegrinder
32
34
  Description-Content-Type: text/markdown
@@ -74,9 +76,9 @@ from telegrinder import API, Message, Telegrinder, Token
74
76
  from telegrinder.modules import logger
75
77
  from telegrinder.rules import Text
76
78
 
77
- logger.set_level("INFO")
78
79
  api = API(token=Token("123:token"))
79
80
  bot = Telegrinder(api)
81
+ logger.set_level("INFO")
80
82
 
81
83
 
82
84
  @bot.on.message(Text("/start"))
@@ -1,22 +1,25 @@
1
1
  [tool.poetry]
2
2
  name = "telegrinder"
3
- version = "0.1.dev158"
3
+ version = "0.1.dev160"
4
4
  description = "Framework for effective and reliable async telegram bot building."
5
5
  authors = ["timoniq <tesseradecades@mail.ru>"]
6
- maintainers = ["luwqz1"]
6
+ maintainers = ["luwqz1 <howluwqz1@gmail.com>"]
7
7
  license = "MIT"
8
8
  readme = "readme.md"
9
9
  homepage = "https://github.com/timoniq/telegrinder"
10
10
  repository = "https://github.com/timoniq/telegrinder"
11
11
  keywords = [
12
+ "asyncio",
13
+ "api schema",
14
+ "async",
15
+ "bot building",
16
+ "bot api",
17
+ "custom rules",
12
18
  "telegram",
13
19
  "telegram bot api framework",
14
20
  "telegrinder",
15
- "asyncio",
16
21
  "middleware",
17
22
  "composition",
18
- "bot api",
19
- "async",
20
23
  ]
21
24
  classifiers = [
22
25
  "Environment :: Console",
@@ -36,11 +39,11 @@ vbml = "^1.1.post1"
36
39
  choicelib = "^0.1.5"
37
40
  envparse = "^0.2.0"
38
41
  PyYAML = "^6.0"
39
- certifi = "^2022.6.15"
40
- msgspec = "^0.18.4"
42
+ certifi = "^2024.2.2"
43
+ msgspec = "^0.18.6"
41
44
  requests = "^2.28.1"
42
- typing-extensions = "^4.8.0"
43
- fntypes = "^0.1.1"
45
+ typing-extensions = "^4.10.0"
46
+ fntypes = "^0.1.2.post1"
44
47
 
45
48
  [tool.poetry.group.dev.dependencies]
46
49
  pytest = "^8.0.0"
@@ -59,10 +62,14 @@ line-length = 100
59
62
  target-version = "py311"
60
63
  select = ["I", "N", "ANN", "COM", "YTT", "TCH", "SIM"]
61
64
  ignore = [
62
- "ANN001", "ANN002", "ANN003", "ANN101", "ANN102", "ANN201", "ANN202",
63
- "ANN204", "ANN206", "ANN401", "COM812", "N818", "TCH001", "TCH004"
65
+ "ANN001", "ANN002", "ANN003", "ANN101", "ANN102", "ANN201", "ANN202",
66
+ "ANN204", "ANN206", "ANN401", "COM812", "N818", "TCH001", "TCH004"
64
67
  ]
65
68
 
69
+ [tool.black]
70
+ line-length = 90
71
+ target-version = ["py311"]
72
+
66
73
  [tool.pytest.ini_options]
67
74
  asyncio_mode = "auto"
68
75
 
@@ -41,9 +41,9 @@ from telegrinder import API, Message, Telegrinder, Token
41
41
  from telegrinder.modules import logger
42
42
  from telegrinder.rules import Text
43
43
 
44
- logger.set_level("INFO")
45
44
  api = API(token=Token("123:token"))
46
45
  bot = Telegrinder(api)
46
+ logger.set_level("INFO")
47
47
 
48
48
 
49
49
  @bot.on.message(Text("/start"))
@@ -39,6 +39,7 @@ from .client import ABCClient, AiohttpClient
39
39
  from .model import Model
40
40
  from .modules import logger
41
41
  from .tools import (
42
+ ABCErrorHandler,
42
43
  ABCGlobalContext,
43
44
  ABCLoopWrapper,
44
45
  ABCTranslator,
@@ -47,6 +48,7 @@ from .tools import (
47
48
  Button,
48
49
  CtxVar,
49
50
  DelayedTask,
51
+ ErrorHandler,
50
52
  FormatString,
51
53
  GlobalContext,
52
54
  HTMLFormatter,
@@ -62,7 +64,6 @@ from .tools import (
62
64
  SimpleI18n,
63
65
  SimpleTranslator,
64
66
  ctx_var,
65
- keyboard_remove,
66
67
  magic_bundle,
67
68
  )
68
69
 
@@ -76,6 +77,7 @@ __all__ = (
76
77
  "ABCAPI",
77
78
  "ABCClient",
78
79
  "ABCDispatch",
80
+ "ABCErrorHandler",
79
81
  "ABCGlobalContext",
80
82
  "ABCHandler",
81
83
  "ABCLoopWrapper",
@@ -107,6 +109,7 @@ __all__ = (
107
109
  "CtxVar",
108
110
  "DelayedTask",
109
111
  "Dispatch",
112
+ "ErrorHandler",
110
113
  "FormatString",
111
114
  "FuncHandler",
112
115
  "GlobalContext",
@@ -139,7 +142,6 @@ __all__ = (
139
142
  "ViewBox",
140
143
  "WaiterMachine",
141
144
  "ctx_var",
142
- "keyboard_remove",
143
145
  "logger",
144
146
  "magic_bundle",
145
147
  "register_manager",
@@ -15,7 +15,7 @@ from .error import InvalidTokenError
15
15
  class Token(str):
16
16
  def __new__(cls, token: str) -> typing.Self:
17
17
  if token.count(":") != 1 or not token.split(":")[0].isdigit():
18
- raise InvalidTokenError("Invalid token, it should look like this '123:token'.")
18
+ raise InvalidTokenError("Invalid token, it should look like this '123:ABC'.")
19
19
  return super().__new__(cls, token)
20
20
 
21
21
  @classmethod
@@ -42,15 +42,17 @@ class ABCAPI(ABC):
42
42
  async def request(
43
43
  self,
44
44
  method: str,
45
- data: dict | None = None,
46
- ) -> Result[list | dict | bool, APIError]:
45
+ data: dict[str, typing.Any] | None = None,
46
+ files: dict[str, tuple[str, bytes]] | None = None,
47
+ ) -> Result[list[typing.Any] | dict[str, typing.Any] | bool, APIError]:
47
48
  pass
48
49
 
49
50
  @abstractmethod
50
51
  async def request_raw(
51
52
  self,
52
53
  method: str,
53
- data: dict | None = None,
54
+ data: dict[str, typing.Any] | None = None,
55
+ files: dict[str, tuple[str, bytes]] | None = None,
54
56
  ) -> Result[msgspec.Raw, APIError]:
55
57
  pass
56
58
 
@@ -5,26 +5,38 @@ from fntypes.result import Error, Ok, Result
5
5
 
6
6
  from telegrinder.api.response import APIResponse
7
7
  from telegrinder.client import ABCClient, AiohttpClient
8
- from telegrinder.model import convert, decoder
8
+ from telegrinder.model import DataConverter, decoder
9
9
  from telegrinder.types.methods import APIMethods
10
10
 
11
11
  from .abc import ABCAPI, APIError, Token
12
12
 
13
13
 
14
- def compose_data(client: ABCClient, data: dict[str, typing.Any]) -> typing.Any:
15
- data = {k: convert(v) for k, v in data.items()}
16
- if any(isinstance(v, tuple) for v in data.values()):
17
- data = client.get_form(data)
18
- return data
14
+ def compose_data(
15
+ client: ABCClient,
16
+ data: dict[str, typing.Any],
17
+ files: dict[str, tuple[str, bytes]],
18
+ ) -> typing.Any:
19
+ converter = DataConverter(files=files)
20
+ return client.get_form(
21
+ data={k: converter(v) for k, v in data.items()},
22
+ files=converter.files,
23
+ )
19
24
 
20
25
 
21
26
  class API(ABCAPI, APIMethods):
22
27
  API_URL: typing.ClassVar[str] = "https://api.telegram.org/"
23
28
 
24
- def __init__(self, token: Token, *, http: ABCClient | None = None):
29
+ def __init__(self, token: Token, *, http: ABCClient | None = None) -> None:
25
30
  self.token = token
26
31
  self.http = http or AiohttpClient()
27
32
  super().__init__(self)
33
+
34
+ def __repr__(self) -> str:
35
+ return "<{}: id={}, http={!r}>".format(
36
+ self.__class__.__name__,
37
+ self.id,
38
+ self.http,
39
+ )
28
40
 
29
41
  @property
30
42
  def id(self) -> int:
@@ -37,11 +49,12 @@ class API(ABCAPI, APIMethods):
37
49
  async def request(
38
50
  self,
39
51
  method: str,
40
- data: dict | None = None,
41
- ) -> Result[dict | list | bool, APIError]:
52
+ data: dict[str, typing.Any] | None = None,
53
+ files: dict[str, tuple[str, bytes]] | None = None,
54
+ ) -> Result[dict[str, typing.Any] | list[typing.Any] | bool, APIError]:
42
55
  response = await self.http.request_json(
43
56
  url=self.request_url + method,
44
- data=compose_data(self.http, data or {})
57
+ data=compose_data(self.http, data or {}, files or {})
45
58
  )
46
59
  if response.get("ok"):
47
60
  assert "result" in response
@@ -55,10 +68,11 @@ class API(ABCAPI, APIMethods):
55
68
  self,
56
69
  method: str,
57
70
  data: dict[str, typing.Any] | None = None,
71
+ files: dict[str, tuple[str, bytes]] | None = None,
58
72
  ) -> Result[msgspec.Raw, APIError]:
59
73
  response_bytes = await self.http.request_bytes(
60
74
  url=self.request_url + method,
61
- data=compose_data(self.http, data or {}),
75
+ data=compose_data(self.http, data or {}, files or {}),
62
76
  )
63
77
  return decoder.decode(response_bytes, type=APIResponse).to_result()
64
78
 
@@ -0,0 +1,138 @@
1
+ import dataclasses
2
+ import inspect
3
+ import typing
4
+ from functools import wraps
5
+
6
+ from fntypes.result import Result
7
+
8
+ from telegrinder.api import ABCAPI, API
9
+ from telegrinder.model import Model, get_params
10
+
11
+ F = typing.TypeVar("F", bound=typing.Callable[..., typing.Any])
12
+ CuteT = typing.TypeVar("CuteT", bound="BaseCute")
13
+ UpdateT = typing.TypeVar("UpdateT", bound=Model)
14
+
15
+ Executor: typing.TypeAlias = typing.Callable[
16
+ [CuteT, str, dict[str, typing.Any]],
17
+ typing.Awaitable[Result[typing.Any, typing.Any]],
18
+ ]
19
+
20
+ if typing.TYPE_CHECKING:
21
+
22
+ class BaseCute(Model, typing.Generic[UpdateT]):
23
+ api: ABCAPI
24
+
25
+ @classmethod
26
+ def from_update(cls, update: UpdateT, bound_api: ABCAPI) -> typing.Self:
27
+ ...
28
+
29
+ @property
30
+ def ctx_api(self) -> API:
31
+ ...
32
+
33
+ else:
34
+
35
+ class BaseCute(typing.Generic[UpdateT]):
36
+ api: ABCAPI
37
+
38
+ @classmethod
39
+ def from_update(cls, update, bound_api):
40
+ return cls(**update.to_dict(), api=bound_api)
41
+
42
+ @property
43
+ def ctx_api(self):
44
+ assert isinstance(self.api, API)
45
+ return self.api
46
+
47
+ def to_dict(self, *, exclude_fields=None):
48
+ exclude_fields = exclude_fields or set()
49
+ return super().to_dict(exclude_fields={"api"} | exclude_fields)
50
+
51
+
52
+ def compose_method_params(
53
+ params: dict[str, typing.Any],
54
+ update: CuteT,
55
+ *,
56
+ default_params: set[str | tuple[str, str]] | None = None,
57
+ validators: dict[str, typing.Callable[[CuteT], bool]] | None = None,
58
+ ) -> dict[str, typing.Any]:
59
+ """Compose method `params` from `update` by `default_params` and `validators`.
60
+
61
+ :param params: Method params.
62
+ :param update: Update object.
63
+ :param default_params: Default params. \
64
+ type (`str`) - Attribute name to be taken from `update` if param undefined. \
65
+ type (`tuple[str, str]`) - tuple[0] Parameter name to be set in `params`, \
66
+ tuple[1] attribute name to be taken from `update`.
67
+ :param validators: Validators mapping (`str, Callable`), key - `Parameter name` \
68
+ for which the validator will be applied, value - `Validator`, if returned `True` \
69
+ parameter will be set, otherwise will not be set.
70
+ :return: Composed params.
71
+ """
72
+
73
+ default_params = default_params or set()
74
+ validators = validators or {}
75
+
76
+ for param in default_params:
77
+ param_name = param if isinstance(param, str) else param[0]
78
+ if param_name not in params:
79
+ if param_name in validators and not validators[param_name](update):
80
+ continue
81
+ params[param_name] = getattr(update, param if isinstance(param, str) else param[1])
82
+
83
+ return params
84
+
85
+
86
+ # NOTE: implement parser on ast for methods decorated this decorator
87
+ # to support updates to the schema Bot API.
88
+ def shortcut(
89
+ method_name: str,
90
+ *,
91
+ executor: Executor[CuteT] | None = None,
92
+ custom_params: set[str] | None = None,
93
+ ):
94
+ def wrapper(func: F) -> F:
95
+ @wraps(func)
96
+ async def inner(self: CuteT, *args: typing.Any, **kwargs: typing.Any) -> typing.Any:
97
+ if executor is None:
98
+ return await func(self, *args, **kwargs)
99
+ signature_params = {
100
+ k: p
101
+ for k, p in inspect.signature(func).parameters.items()
102
+ if k != "self"
103
+ }
104
+ params: dict[str, typing.Any] = {}
105
+ index = 0
106
+
107
+ for k, p in signature_params.items():
108
+ if p.kind in (p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY) and len(args) > index:
109
+ params[k] = args[index]
110
+ index += 1
111
+ continue
112
+ if p.kind in (p.VAR_KEYWORD, p.VAR_POSITIONAL):
113
+ params[k] = kwargs.copy() if p.kind is p.VAR_KEYWORD else args[index:]
114
+ continue
115
+ params[k] = kwargs.pop(k, p.default) if p.default is not p.empty else kwargs.pop(k)
116
+
117
+ return await executor(self, method_name, get_params(params))
118
+
119
+ func.__repr__ = lambda _: f"<Shortcut {method_name!r}@{func!r}>"
120
+ inner.__shortcut__ = Shortcut( # type: ignore
121
+ method_name=method_name,
122
+ executor=executor,
123
+ custom_params=custom_params or set(),
124
+ )
125
+ return inner # type: ignore
126
+
127
+ return wrapper
128
+
129
+
130
+ @dataclasses.dataclass
131
+ class Shortcut:
132
+ method_name: str
133
+ _: dataclasses.KW_ONLY
134
+ executor: Executor | None = dataclasses.field(default=None)
135
+ custom_params: set[str] = dataclasses.field(default_factory=lambda: set())
136
+
137
+
138
+ __all__ = ("BaseCute", "Shortcut", "compose_method_params", "shortcut")