pymaxgram 4.0.0__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.
Files changed (150) hide show
  1. pymaxgram-4.0.0/.gitignore +9 -0
  2. pymaxgram-4.0.0/PKG-INFO +61 -0
  3. pymaxgram-4.0.0/README.md +35 -0
  4. pymaxgram-4.0.0/maxgram/__init__.py +30 -0
  5. pymaxgram-4.0.0/maxgram/__meta__.py +2 -0
  6. pymaxgram-4.0.0/maxgram/client/__init__.py +5 -0
  7. pymaxgram-4.0.0/maxgram/client/bot.py +362 -0
  8. pymaxgram-4.0.0/maxgram/client/context_controller.py +35 -0
  9. pymaxgram-4.0.0/maxgram/client/default.py +21 -0
  10. pymaxgram-4.0.0/maxgram/client/max_api.py +22 -0
  11. pymaxgram-4.0.0/maxgram/client/session/__init__.py +0 -0
  12. pymaxgram-4.0.0/maxgram/client/session/aiohttp.py +227 -0
  13. pymaxgram-4.0.0/maxgram/client/session/base.py +180 -0
  14. pymaxgram-4.0.0/maxgram/client/session/middlewares/__init__.py +0 -0
  15. pymaxgram-4.0.0/maxgram/client/session/middlewares/base.py +52 -0
  16. pymaxgram-4.0.0/maxgram/client/session/middlewares/manager.py +61 -0
  17. pymaxgram-4.0.0/maxgram/client/session/middlewares/request_logging.py +37 -0
  18. pymaxgram-4.0.0/maxgram/dispatcher/__init__.py +0 -0
  19. pymaxgram-4.0.0/maxgram/dispatcher/dispatcher.py +472 -0
  20. pymaxgram-4.0.0/maxgram/dispatcher/event/__init__.py +0 -0
  21. pymaxgram-4.0.0/maxgram/dispatcher/event/bases.py +35 -0
  22. pymaxgram-4.0.0/maxgram/dispatcher/event/event.py +54 -0
  23. pymaxgram-4.0.0/maxgram/dispatcher/event/handler.py +123 -0
  24. pymaxgram-4.0.0/maxgram/dispatcher/event/max.py +119 -0
  25. pymaxgram-4.0.0/maxgram/dispatcher/flags.py +132 -0
  26. pymaxgram-4.0.0/maxgram/dispatcher/middlewares/__init__.py +0 -0
  27. pymaxgram-4.0.0/maxgram/dispatcher/middlewares/base.py +20 -0
  28. pymaxgram-4.0.0/maxgram/dispatcher/middlewares/data.py +82 -0
  29. pymaxgram-4.0.0/maxgram/dispatcher/middlewares/error.py +38 -0
  30. pymaxgram-4.0.0/maxgram/dispatcher/middlewares/manager.py +68 -0
  31. pymaxgram-4.0.0/maxgram/dispatcher/middlewares/user_context.py +64 -0
  32. pymaxgram-4.0.0/maxgram/dispatcher/router.py +169 -0
  33. pymaxgram-4.0.0/maxgram/enums/__init__.py +21 -0
  34. pymaxgram-4.0.0/maxgram/enums/attachment_type.py +13 -0
  35. pymaxgram-4.0.0/maxgram/enums/button_type.py +11 -0
  36. pymaxgram-4.0.0/maxgram/enums/chat_action.py +10 -0
  37. pymaxgram-4.0.0/maxgram/enums/chat_admin_permission.py +15 -0
  38. pymaxgram-4.0.0/maxgram/enums/chat_status.py +8 -0
  39. pymaxgram-4.0.0/maxgram/enums/content_type.py +14 -0
  40. pymaxgram-4.0.0/maxgram/enums/parse_mode.py +6 -0
  41. pymaxgram-4.0.0/maxgram/enums/update_type.py +7 -0
  42. pymaxgram-4.0.0/maxgram/enums/upload_type.py +8 -0
  43. pymaxgram-4.0.0/maxgram/exceptions.py +127 -0
  44. pymaxgram-4.0.0/maxgram/filters/__init__.py +26 -0
  45. pymaxgram-4.0.0/maxgram/filters/base.py +54 -0
  46. pymaxgram-4.0.0/maxgram/filters/callback_data.py +149 -0
  47. pymaxgram-4.0.0/maxgram/filters/command.py +210 -0
  48. pymaxgram-4.0.0/maxgram/filters/exception.py +57 -0
  49. pymaxgram-4.0.0/maxgram/filters/logic.py +77 -0
  50. pymaxgram-4.0.0/maxgram/filters/magic_data.py +27 -0
  51. pymaxgram-4.0.0/maxgram/filters/state.py +50 -0
  52. pymaxgram-4.0.0/maxgram/fsm/__init__.py +0 -0
  53. pymaxgram-4.0.0/maxgram/fsm/context.py +44 -0
  54. pymaxgram-4.0.0/maxgram/fsm/middleware.py +104 -0
  55. pymaxgram-4.0.0/maxgram/fsm/scene.py +980 -0
  56. pymaxgram-4.0.0/maxgram/fsm/state.py +175 -0
  57. pymaxgram-4.0.0/maxgram/fsm/storage/__init__.py +0 -0
  58. pymaxgram-4.0.0/maxgram/fsm/storage/base.py +193 -0
  59. pymaxgram-4.0.0/maxgram/fsm/storage/memory.py +95 -0
  60. pymaxgram-4.0.0/maxgram/fsm/strategy.py +36 -0
  61. pymaxgram-4.0.0/maxgram/handlers/__init__.py +15 -0
  62. pymaxgram-4.0.0/maxgram/handlers/base.py +47 -0
  63. pymaxgram-4.0.0/maxgram/handlers/bot_started.py +16 -0
  64. pymaxgram-4.0.0/maxgram/handlers/callback.py +16 -0
  65. pymaxgram-4.0.0/maxgram/handlers/error.py +17 -0
  66. pymaxgram-4.0.0/maxgram/handlers/message.py +26 -0
  67. pymaxgram-4.0.0/maxgram/loggers.py +7 -0
  68. pymaxgram-4.0.0/maxgram/methods/__init__.py +65 -0
  69. pymaxgram-4.0.0/maxgram/methods/add_members.py +16 -0
  70. pymaxgram-4.0.0/maxgram/methods/answer_callback.py +40 -0
  71. pymaxgram-4.0.0/maxgram/methods/assign_admins.py +16 -0
  72. pymaxgram-4.0.0/maxgram/methods/base.py +120 -0
  73. pymaxgram-4.0.0/maxgram/methods/create_subscription.py +17 -0
  74. pymaxgram-4.0.0/maxgram/methods/delete_chat.py +15 -0
  75. pymaxgram-4.0.0/maxgram/methods/delete_message.py +18 -0
  76. pymaxgram-4.0.0/maxgram/methods/delete_subscription.py +15 -0
  77. pymaxgram-4.0.0/maxgram/methods/edit_chat.py +20 -0
  78. pymaxgram-4.0.0/maxgram/methods/edit_message.py +34 -0
  79. pymaxgram-4.0.0/maxgram/methods/get_admins.py +17 -0
  80. pymaxgram-4.0.0/maxgram/methods/get_chat.py +16 -0
  81. pymaxgram-4.0.0/maxgram/methods/get_chats.py +22 -0
  82. pymaxgram-4.0.0/maxgram/methods/get_me.py +14 -0
  83. pymaxgram-4.0.0/maxgram/methods/get_members.py +19 -0
  84. pymaxgram-4.0.0/maxgram/methods/get_message_by_id.py +16 -0
  85. pymaxgram-4.0.0/maxgram/methods/get_messages.py +18 -0
  86. pymaxgram-4.0.0/maxgram/methods/get_my_membership.py +16 -0
  87. pymaxgram-4.0.0/maxgram/methods/get_pinned_message.py +16 -0
  88. pymaxgram-4.0.0/maxgram/methods/get_subscriptions.py +14 -0
  89. pymaxgram-4.0.0/maxgram/methods/get_updates.py +19 -0
  90. pymaxgram-4.0.0/maxgram/methods/get_upload_url.py +16 -0
  91. pymaxgram-4.0.0/maxgram/methods/get_video_info.py +16 -0
  92. pymaxgram-4.0.0/maxgram/methods/leave_chat.py +15 -0
  93. pymaxgram-4.0.0/maxgram/methods/pin_message.py +17 -0
  94. pymaxgram-4.0.0/maxgram/methods/remove_admin.py +16 -0
  95. pymaxgram-4.0.0/maxgram/methods/remove_member.py +17 -0
  96. pymaxgram-4.0.0/maxgram/methods/send_action.py +16 -0
  97. pymaxgram-4.0.0/maxgram/methods/send_message.py +50 -0
  98. pymaxgram-4.0.0/maxgram/methods/unpin_message.py +15 -0
  99. pymaxgram-4.0.0/maxgram/py.typed +0 -0
  100. pymaxgram-4.0.0/maxgram/types/__init__.py +105 -0
  101. pymaxgram-4.0.0/maxgram/types/attachment.py +66 -0
  102. pymaxgram-4.0.0/maxgram/types/attachment_request.py +56 -0
  103. pymaxgram-4.0.0/maxgram/types/base.py +37 -0
  104. pymaxgram-4.0.0/maxgram/types/bot_command.py +8 -0
  105. pymaxgram-4.0.0/maxgram/types/bot_info.py +10 -0
  106. pymaxgram-4.0.0/maxgram/types/button.py +13 -0
  107. pymaxgram-4.0.0/maxgram/types/callback.py +38 -0
  108. pymaxgram-4.0.0/maxgram/types/chat.py +30 -0
  109. pymaxgram-4.0.0/maxgram/types/chat_admin.py +11 -0
  110. pymaxgram-4.0.0/maxgram/types/chat_member.py +14 -0
  111. pymaxgram-4.0.0/maxgram/types/error_event.py +13 -0
  112. pymaxgram-4.0.0/maxgram/types/image.py +12 -0
  113. pymaxgram-4.0.0/maxgram/types/inline_keyboard.py +10 -0
  114. pymaxgram-4.0.0/maxgram/types/input_file.py +150 -0
  115. pymaxgram-4.0.0/maxgram/types/linked_message.py +18 -0
  116. pymaxgram-4.0.0/maxgram/types/message.py +106 -0
  117. pymaxgram-4.0.0/maxgram/types/message_body.py +13 -0
  118. pymaxgram-4.0.0/maxgram/types/message_stat.py +9 -0
  119. pymaxgram-4.0.0/maxgram/types/new_message_body.py +15 -0
  120. pymaxgram-4.0.0/maxgram/types/new_message_link.py +8 -0
  121. pymaxgram-4.0.0/maxgram/types/recipient.py +11 -0
  122. pymaxgram-4.0.0/maxgram/types/subscription.py +12 -0
  123. pymaxgram-4.0.0/maxgram/types/update.py +46 -0
  124. pymaxgram-4.0.0/maxgram/types/upload_info.py +10 -0
  125. pymaxgram-4.0.0/maxgram/types/user.py +15 -0
  126. pymaxgram-4.0.0/maxgram/types/user_with_photo.py +11 -0
  127. pymaxgram-4.0.0/maxgram/types/video_info.py +22 -0
  128. pymaxgram-4.0.0/maxgram/utils/__init__.py +0 -0
  129. pymaxgram-4.0.0/maxgram/utils/backoff.py +85 -0
  130. pymaxgram-4.0.0/maxgram/utils/callback_answer.py +218 -0
  131. pymaxgram-4.0.0/maxgram/utils/chat_action.py +179 -0
  132. pymaxgram-4.0.0/maxgram/utils/chat_member.py +36 -0
  133. pymaxgram-4.0.0/maxgram/utils/class_attrs_resolver.py +87 -0
  134. pymaxgram-4.0.0/maxgram/utils/dataclass.py +63 -0
  135. pymaxgram-4.0.0/maxgram/utils/formatting.py +735 -0
  136. pymaxgram-4.0.0/maxgram/utils/keyboard.py +91 -0
  137. pymaxgram-4.0.0/maxgram/utils/link.py +24 -0
  138. pymaxgram-4.0.0/maxgram/utils/magic_filter.py +23 -0
  139. pymaxgram-4.0.0/maxgram/utils/markdown.py +59 -0
  140. pymaxgram-4.0.0/maxgram/utils/mixins.py +98 -0
  141. pymaxgram-4.0.0/maxgram/utils/mypy_hacks.py +21 -0
  142. pymaxgram-4.0.0/maxgram/utils/payload.py +114 -0
  143. pymaxgram-4.0.0/maxgram/utils/serialization.py +89 -0
  144. pymaxgram-4.0.0/maxgram/utils/text_decorations.py +104 -0
  145. pymaxgram-4.0.0/maxgram/utils/token.py +15 -0
  146. pymaxgram-4.0.0/maxgram/utils/warnings.py +6 -0
  147. pymaxgram-4.0.0/maxgram/webhook/__init__.py +0 -0
  148. pymaxgram-4.0.0/maxgram/webhook/aiohttp_server.py +152 -0
  149. pymaxgram-4.0.0/maxgram/webhook/security.py +33 -0
  150. pymaxgram-4.0.0/pyproject.toml +49 -0
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.4
2
+ Name: pymaxgram
3
+ Version: 4.0.0
4
+ Summary: Async framework for MAX Messenger Bot API
5
+ Project-URL: Repository, https://github.com/daeeros/pymaxgram
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Framework :: AsyncIO
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Communications :: Chat
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: aiofiles<26.0,>=23.2.1
20
+ Requires-Dist: aiohttp<3.14,>=3.9.0
21
+ Requires-Dist: certifi>=2023.7.22
22
+ Requires-Dist: magic-filter<1.1,>=1.0.12
23
+ Requires-Dist: pydantic<2.13,>=2.4.1
24
+ Requires-Dist: typing-extensions<=5.0,>=4.7.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # pymaxgram
28
+
29
+ Async framework for MAX Messenger Bot API.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install pymaxgram
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```python
40
+ import asyncio
41
+ from maxgram import Bot, Dispatcher, Router
42
+
43
+ bot = Bot(token="YOUR_BOT_TOKEN")
44
+ dp = Dispatcher()
45
+ router = Router()
46
+
47
+
48
+ @router.message()
49
+ async def on_message(message, bot):
50
+ await message.answer("Hello!")
51
+
52
+
53
+ dp.include_router(router)
54
+
55
+
56
+ async def main():
57
+ await dp.start_polling(bot)
58
+
59
+
60
+ asyncio.run(main())
61
+ ```
@@ -0,0 +1,35 @@
1
+ # pymaxgram
2
+
3
+ Async framework for MAX Messenger Bot API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install pymaxgram
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ import asyncio
15
+ from maxgram import Bot, Dispatcher, Router
16
+
17
+ bot = Bot(token="YOUR_BOT_TOKEN")
18
+ dp = Dispatcher()
19
+ router = Router()
20
+
21
+
22
+ @router.message()
23
+ async def on_message(message, bot):
24
+ await message.answer("Hello!")
25
+
26
+
27
+ dp.include_router(router)
28
+
29
+
30
+ async def main():
31
+ await dp.start_polling(bot)
32
+
33
+
34
+ asyncio.run(main())
35
+ ```
@@ -0,0 +1,30 @@
1
+ from maxgram.dispatcher.flags import FlagGenerator
2
+
3
+ from . import enums, methods, types
4
+ from .__meta__ import __api_version__, __version__
5
+ from .client.bot import Bot
6
+ from .dispatcher.dispatcher import Dispatcher
7
+ from .dispatcher.middlewares.base import BaseMiddleware
8
+ from .dispatcher.router import Router
9
+ from .utils.magic_filter import MagicFilter
10
+ from .utils.text_decorations import html_decoration as html
11
+ from .utils.text_decorations import markdown_decoration as md
12
+
13
+ F = MagicFilter()
14
+ flags = FlagGenerator()
15
+
16
+ __all__ = (
17
+ "BaseMiddleware",
18
+ "Bot",
19
+ "Dispatcher",
20
+ "F",
21
+ "Router",
22
+ "__api_version__",
23
+ "__version__",
24
+ "enums",
25
+ "flags",
26
+ "html",
27
+ "md",
28
+ "methods",
29
+ "types",
30
+ )
@@ -0,0 +1,2 @@
1
+ __version__ = "4.0.0"
2
+ __api_version__ = "1.0"
@@ -0,0 +1,5 @@
1
+ from .default import DefaultBotProperties
2
+
3
+ __all__ = [
4
+ "DefaultBotProperties",
5
+ ]
@@ -0,0 +1,362 @@
1
+ from __future__ import annotations
2
+
3
+ import io
4
+ import pathlib
5
+ from collections.abc import AsyncGenerator
6
+ from contextlib import asynccontextmanager
7
+ from types import TracebackType
8
+ from typing import (
9
+ Any,
10
+ BinaryIO,
11
+ TypeVar,
12
+ cast,
13
+ )
14
+
15
+ from ..methods import (
16
+ AddMembers,
17
+ AnswerCallback,
18
+ AssignAdmins,
19
+ CreateSubscription,
20
+ DeleteChat,
21
+ DeleteMessage,
22
+ DeleteSubscription,
23
+ EditChat,
24
+ EditMessage,
25
+ GetAdmins,
26
+ GetChat,
27
+ GetChats,
28
+ GetMe,
29
+ GetMembers,
30
+ GetMessageById,
31
+ GetMessages,
32
+ GetMyMembership,
33
+ GetPinnedMessage,
34
+ GetSubscriptions,
35
+ GetUpdates,
36
+ GetUploadUrl,
37
+ GetVideoInfo,
38
+ LeaveChat,
39
+ MaxMethod,
40
+ PinMessage,
41
+ RemoveAdmin,
42
+ RemoveMember,
43
+ SendAction,
44
+ SendMessage,
45
+ UnpinMessage,
46
+ )
47
+ from ..methods.base import MaxType
48
+ from ..types import (
49
+ BotInfo,
50
+ Chat,
51
+ ChatMember,
52
+ Message,
53
+ Subscription,
54
+ Update,
55
+ UploadInfo,
56
+ User,
57
+ VideoInfo,
58
+ )
59
+ from .context_controller import BotContextController
60
+ from .default import DefaultBotProperties
61
+
62
+ T = TypeVar("T")
63
+
64
+
65
+ class Bot:
66
+ """MAX Bot API client."""
67
+
68
+ def __init__(
69
+ self,
70
+ token: str,
71
+ session: Any | None = None,
72
+ default: DefaultBotProperties | None = None,
73
+ ) -> None:
74
+ if not token:
75
+ raise ValueError("Token must not be empty")
76
+
77
+ self.__token = token
78
+ self.session = session or self._create_default_session()
79
+ self.default = default or DefaultBotProperties()
80
+ self._me: BotInfo | None = None
81
+
82
+ @staticmethod
83
+ def _create_default_session() -> Any:
84
+ from .session.aiohttp import AiohttpSession
85
+ return AiohttpSession()
86
+
87
+ @property
88
+ def token(self) -> str:
89
+ return self.__token
90
+
91
+ @property
92
+ def id(self) -> int | None:
93
+ """Bot ID. Available after calling get_me()."""
94
+ if self._me:
95
+ return self._me.user_id
96
+ return None
97
+
98
+ async def me(self) -> BotInfo:
99
+ """Get bot info (cached)."""
100
+ if self._me is None:
101
+ self._me = await self.get_me()
102
+ return self._me
103
+
104
+ async def __call__(
105
+ self,
106
+ method: MaxMethod[MaxType],
107
+ **kwargs: Any,
108
+ ) -> MaxType:
109
+ """Execute an API method."""
110
+ return await self.session(self, method, **kwargs)
111
+
112
+ def __hash__(self) -> int:
113
+ return hash(self.__token)
114
+
115
+ def __eq__(self, other: object) -> bool:
116
+ if not isinstance(other, Bot):
117
+ return NotImplemented
118
+ return self.__token == other.__token
119
+
120
+ async def __aenter__(self) -> Bot:
121
+ return self
122
+
123
+ async def __aexit__(
124
+ self,
125
+ exc_type: type[BaseException] | None,
126
+ exc_val: BaseException | None,
127
+ exc_tb: TracebackType | None,
128
+ ) -> None:
129
+ await self.session.close()
130
+
131
+ # ==================== Bot Info ====================
132
+
133
+ async def get_me(self) -> BotInfo:
134
+ return await self(GetMe())
135
+
136
+ # ==================== Chats ====================
137
+
138
+ async def get_chats(
139
+ self,
140
+ count: int | None = None,
141
+ marker: int | None = None,
142
+ ) -> list[Chat]:
143
+ return await self(GetChats(count=count, marker=marker))
144
+
145
+ async def get_chat(self, chat_id: int) -> Chat:
146
+ return await self(GetChat(chat_id=chat_id))
147
+
148
+ async def edit_chat(
149
+ self,
150
+ chat_id: int,
151
+ title: str | None = None,
152
+ icon: dict[str, Any] | None = None,
153
+ pin: str | None = None,
154
+ notify: bool | None = None,
155
+ ) -> Chat:
156
+ return await self(EditChat(
157
+ chat_id=chat_id, title=title, icon=icon, pin=pin, notify=notify,
158
+ ))
159
+
160
+ async def delete_chat(self, chat_id: int) -> bool:
161
+ return await self(DeleteChat(chat_id=chat_id))
162
+
163
+ # ==================== Chat Actions ====================
164
+
165
+ async def send_action(self, chat_id: int, action: str) -> bool:
166
+ return await self(SendAction(chat_id=chat_id, action=action))
167
+
168
+ # ==================== Pinned Messages ====================
169
+
170
+ async def get_pinned_message(self, chat_id: int) -> Message | None:
171
+ return await self(GetPinnedMessage(chat_id=chat_id))
172
+
173
+ async def pin_message(
174
+ self,
175
+ chat_id: int,
176
+ message_id: str,
177
+ notify: bool | None = None,
178
+ ) -> bool:
179
+ return await self(PinMessage(chat_id=chat_id, message_id=message_id, notify=notify))
180
+
181
+ async def unpin_message(self, chat_id: int) -> bool:
182
+ return await self(UnpinMessage(chat_id=chat_id))
183
+
184
+ # ==================== Members ====================
185
+
186
+ async def get_my_membership(self, chat_id: int) -> ChatMember:
187
+ return await self(GetMyMembership(chat_id=chat_id))
188
+
189
+ async def leave_chat(self, chat_id: int) -> bool:
190
+ return await self(LeaveChat(chat_id=chat_id))
191
+
192
+ async def get_admins(
193
+ self,
194
+ chat_id: int,
195
+ marker: int | None = None,
196
+ ) -> list[ChatMember]:
197
+ return await self(GetAdmins(chat_id=chat_id, marker=marker))
198
+
199
+ async def assign_admins(
200
+ self,
201
+ chat_id: int,
202
+ admins: list[dict[str, Any]],
203
+ ) -> bool:
204
+ return await self(AssignAdmins(chat_id=chat_id, admins=admins))
205
+
206
+ async def remove_admin(self, chat_id: int, user_id: int) -> bool:
207
+ return await self(RemoveAdmin(chat_id=chat_id, user_id=user_id))
208
+
209
+ async def get_members(
210
+ self,
211
+ chat_id: int,
212
+ user_ids: list[int] | None = None,
213
+ marker: int | None = None,
214
+ count: int | None = None,
215
+ ) -> list[ChatMember]:
216
+ return await self(GetMembers(
217
+ chat_id=chat_id, user_ids=user_ids, marker=marker, count=count,
218
+ ))
219
+
220
+ async def add_members(self, chat_id: int, user_ids: list[int]) -> bool:
221
+ return await self(AddMembers(chat_id=chat_id, user_ids=user_ids))
222
+
223
+ async def remove_member(
224
+ self,
225
+ chat_id: int,
226
+ user_id: int,
227
+ block: bool | None = None,
228
+ ) -> bool:
229
+ return await self(RemoveMember(chat_id=chat_id, user_id=user_id, block=block))
230
+
231
+ # ==================== Subscriptions (Webhooks) ====================
232
+
233
+ async def get_subscriptions(self) -> list[Subscription]:
234
+ return await self(GetSubscriptions())
235
+
236
+ async def create_subscription(
237
+ self,
238
+ url: str,
239
+ update_types: list[str] | None = None,
240
+ secret: str | None = None,
241
+ ) -> bool:
242
+ return await self(CreateSubscription(
243
+ url=url, update_types=update_types, secret=secret,
244
+ ))
245
+
246
+ async def delete_subscription(self, url: str) -> bool:
247
+ return await self(DeleteSubscription(url=url))
248
+
249
+ # ==================== Updates ====================
250
+
251
+ async def get_updates(
252
+ self,
253
+ limit: int | None = None,
254
+ timeout: int | None = None,
255
+ marker: int | None = None,
256
+ types: list[str] | None = None,
257
+ ) -> list[Update]:
258
+ return await self(GetUpdates(
259
+ limit=limit, timeout=timeout, marker=marker, types=types,
260
+ ))
261
+
262
+ # ==================== Messages ====================
263
+
264
+ async def send_message(
265
+ self,
266
+ chat_id: int | None = None,
267
+ user_id: int | None = None,
268
+ text: str | None = None,
269
+ attachments: list[Any] | None = None,
270
+ link: Any | None = None,
271
+ notify: bool | None = None,
272
+ format: str | None = None,
273
+ disable_link_preview: bool | None = None,
274
+ ) -> Message:
275
+ return await self(SendMessage(
276
+ chat_id=chat_id,
277
+ user_id=user_id,
278
+ text=text,
279
+ attachments=attachments,
280
+ link=link,
281
+ notify=notify,
282
+ format=format,
283
+ disable_link_preview=disable_link_preview,
284
+ ))
285
+
286
+ async def edit_message(
287
+ self,
288
+ message_id: str,
289
+ text: str | None = None,
290
+ attachments: list[Any] | None = None,
291
+ notify: bool | None = None,
292
+ format: str | None = None,
293
+ ) -> bool:
294
+ return await self(EditMessage(
295
+ message_id=message_id,
296
+ text=text,
297
+ attachments=attachments,
298
+ notify=notify,
299
+ format=format,
300
+ ))
301
+
302
+ async def delete_message(self, message_id: str) -> bool:
303
+ return await self(DeleteMessage(message_id=message_id))
304
+
305
+ async def get_messages(
306
+ self,
307
+ chat_id: int | None = None,
308
+ message_ids: list[str] | None = None,
309
+ count: int | None = None,
310
+ ) -> list[Message]:
311
+ return await self(GetMessages(
312
+ chat_id=chat_id, message_ids=message_ids, count=count,
313
+ ))
314
+
315
+ async def get_message_by_id(self, message_id: str) -> Message:
316
+ return await self(GetMessageById(message_id=message_id))
317
+
318
+ # ==================== Uploads ====================
319
+
320
+ async def get_upload_url(self, type: str) -> UploadInfo:
321
+ return await self(GetUploadUrl(type=type))
322
+
323
+ async def upload_file(
324
+ self,
325
+ file_type: str,
326
+ file_data: bytes,
327
+ filename: str = "file",
328
+ ) -> str:
329
+ """Two-stage file upload. Returns token for use in attachments."""
330
+ upload_info = await self.get_upload_url(type=file_type)
331
+ result = await self.session.upload_file(
332
+ bot=self,
333
+ upload_url=upload_info.url,
334
+ file_data=file_data,
335
+ filename=filename,
336
+ )
337
+ return result.get("token", upload_info.token or "")
338
+
339
+ # ==================== Video ====================
340
+
341
+ async def get_video_info(self, video_token: str) -> VideoInfo:
342
+ return await self(GetVideoInfo(video_token=video_token))
343
+
344
+ # ==================== Callbacks ====================
345
+
346
+ async def answer_callback(
347
+ self,
348
+ callback_id: str,
349
+ text: str | None = None,
350
+ attachments: list[Any] | None = None,
351
+ notification: str | None = None,
352
+ notify: bool | None = None,
353
+ format: str | None = None,
354
+ ) -> bool:
355
+ return await self(AnswerCallback(
356
+ callback_id=callback_id,
357
+ text=text,
358
+ attachments=attachments,
359
+ notification=notification,
360
+ notify=notify,
361
+ format=format,
362
+ ))
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from pydantic import BaseModel, PrivateAttr
6
+ from typing_extensions import Self
7
+
8
+ if TYPE_CHECKING:
9
+ from maxgram.client.bot import Bot
10
+
11
+
12
+ class BotContextController(BaseModel):
13
+ _bot: Bot | None = PrivateAttr()
14
+
15
+ def model_post_init(self, __context: Any) -> None: # noqa: PYI063
16
+ self._bot = __context.get("bot") if __context else None
17
+
18
+ def as_(self, bot: Bot | None) -> Self:
19
+ """
20
+ Bind object to a bot instance.
21
+
22
+ :param bot: Bot instance
23
+ :return: self
24
+ """
25
+ self._bot = bot
26
+ return self
27
+
28
+ @property
29
+ def bot(self) -> Bot | None:
30
+ """
31
+ Get bot instance.
32
+
33
+ :return: Bot instance
34
+ """
35
+ return self._bot
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from maxgram.utils.dataclass import dataclass_kwargs
7
+
8
+
9
+ @dataclass(**dataclass_kwargs(slots=True, kw_only=True))
10
+ class DefaultBotProperties:
11
+ """Default bot properties for MAX API."""
12
+
13
+ parse_mode: str | None = None
14
+ """Default parse mode for messages (markdown or html)."""
15
+ disable_link_preview: bool | None = None
16
+ """Disable link preview in messages."""
17
+ notify: bool | None = None
18
+ """Default notification setting."""
19
+
20
+ def __getitem__(self, item: str) -> Any:
21
+ return getattr(self, item, None)
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class MaxAPIServer:
8
+ """MAX API server configuration."""
9
+
10
+ base: str = "https://platform-api.max.ru"
11
+
12
+ def api_url(self, path: str) -> str:
13
+ """Build full API URL from path."""
14
+ return f"{self.base}{path}"
15
+
16
+ @classmethod
17
+ def from_base(cls, base: str) -> MaxAPIServer:
18
+ base = base.rstrip("/")
19
+ return cls(base=base)
20
+
21
+
22
+ PRODUCTION = MaxAPIServer()
File without changes