maxbot-api-client-python 1.1.2__py3-none-any.whl → 2.0.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.
@@ -1,10 +1,12 @@
1
- import aiofiles, asyncio, httpx, logging, mimetypes, os, time
1
+ import aiofiles, asyncio, httpx, logging, mimetypes, os, time, re
2
+ from aiofiles import tempfile
2
3
  from typing import Any, List, Optional
3
4
  from urllib.parse import urlparse
4
5
  from pathlib import Path
5
6
 
7
+ from maxbot_api_client_python.exceptions import MaxBotError
6
8
  from maxbot_api_client_python.tools.uploads import Uploads
7
- from maxbot_api_client_python.client import Client, decode, adecode
9
+ from maxbot_api_client_python.client import Client
8
10
  from maxbot_api_client_python.types.constants import AttachmentType, Paths, UploadType
9
11
  from maxbot_api_client_python.types.models import Message, SendFileReq, SendMessageReq, UploadFileReq, Attachment
10
12
 
@@ -15,66 +17,74 @@ class Helpers:
15
17
  self.client = client
16
18
  self.uploads = Uploads(client)
17
19
 
18
- def SendFile(self, **kwargs) -> Optional[Message]:
20
+ def send_file(self, **kwargs: Any) -> Optional[Message]:
19
21
  """
20
22
  A helper that simplifies sending files to a chat.
21
23
  It automatically determines whether the provided file_source is a direct URL or a local file path.
22
24
 
23
25
  Example:
24
26
  # Sending a file via URL:
25
- response = api.helpers.SendFile(
27
+ response = bot.helpers.send_file(
26
28
  chat_id=123456789,
27
29
  text="Check out this image!",
28
30
  file_source="https://example.com/image.png"
29
31
  )
30
32
 
31
33
  # Sending a local file:
32
- response = api.helpers.SendFile(
34
+ response = bot.helpers.send_file(
33
35
  chat_id=123456789,
34
36
  text="Here is the report.",
35
37
  file_source="/local/path/to/report.pdf"
36
38
  )
37
39
  """
38
40
  req = SendFileReq(**kwargs)
39
- if self._is_url(req.file_source):
40
- return self.sendFileByUrl(req)
41
- return self.sendFileByUpload(req)
41
+ is_url = urlparse(req.file_source).scheme in ("http", "https")
42
+ if not is_url and not os.path.exists(req.file_source):
43
+ raise ValueError("Invalid file path or URL.")
44
+
45
+ if urlparse(req.file_source).scheme in ("http", "https"):
46
+ return self._send_file_by_url(req)
47
+
48
+ return self._send_file_by_upload(req)
42
49
 
43
- def sendFileByUrl(self, req: SendFileReq) -> Optional[Message]:
50
+ def _send_file_by_url(self, req: SendFileReq) -> Optional[Message]:
44
51
  ext = self._get_extension(req.file_source)
45
52
  upload_type = self._determine_upload_type(ext)
46
53
 
47
54
  if upload_type == UploadType.IMAGE:
48
55
  attachment = Attachment(type=AttachmentType.IMAGE, payload={"url": req.file_source})
49
- return self.sendFileInternal(req, attachment)
56
+ return self._send_file_internal(req, attachment)
50
57
 
51
58
  temp_path = None
52
59
  try:
53
60
  temp_path = self._download_temp_file(req.file_source)
54
61
  req.file_source = temp_path
55
- return self.sendFileByUpload(req)
62
+ return self._send_file_by_upload(req)
56
63
  except Exception as e:
57
64
  logger.error(f"File processing/upload error: {e}")
58
- return None
65
+ raise
59
66
  finally:
60
- if temp_path and os.path.exists(temp_path):
61
- os.remove(temp_path)
67
+ if temp_path:
68
+ try:
69
+ os.remove(temp_path)
70
+ except FileNotFoundError:
71
+ pass
62
72
 
63
- def sendFileByUpload(self, req: SendFileReq) -> Optional[Message]:
73
+ def _send_file_by_upload(self, req: SendFileReq) -> Optional[Message]:
64
74
  ext = self._get_extension(req.file_source)
65
75
  upload_type = self._determine_upload_type(ext)
66
76
 
67
77
  upload_req = UploadFileReq(type=upload_type, file_path=req.file_source)
68
- upload_resp = self.uploads.UploadFile(**upload_req.model_dump_json(indent=4))
78
+ upload_resp = self.uploads.upload_file(**upload_req.model_dump(exclude_none=True))
69
79
 
70
80
  if not upload_resp or not upload_resp.token:
71
81
  logger.error("Upload failed: No token returned.")
72
82
  return None
73
83
 
74
84
  attachment = self._build_attachment_from_token(upload_type, upload_resp.token, Path(req.file_source).name)
75
- return self.sendFileInternal(req, attachment)
85
+ return self._send_file_internal(req, attachment)
76
86
 
77
- def sendFileInternal(self, req: SendFileReq, attachment: Attachment) -> Message:
87
+ def _send_file_internal(self, req: SendFileReq, attachment: Attachment) -> Message:
78
88
  attachments: List[Attachment] = req.attachments or []
79
89
  attachments.append(attachment)
80
90
 
@@ -89,13 +99,15 @@ class Helpers:
89
99
  disable_link_preview=req.disable_link_preview
90
100
  )
91
101
 
102
+ query, payload = self.client.split_request(request_data)
92
103
  last_err: Optional[Exception] = None
104
+
93
105
  for _ in range(self.client.max_retries):
94
106
  try:
95
- return decode(self.client, "POST", Paths.MESSAGES, Message, query=request_data.model_dump(exclude_none=True), payload=request_data)
96
- except Exception as e:
107
+ return self.client.decode("POST", Paths.MESSAGES, Message, query=query, payload=payload)
108
+ except MaxBotError as e:
97
109
  last_err = e
98
- if "not.ready" in str(e).lower():
110
+ if e.status_code == 422 or "not.ready" in str(e.response).lower():
99
111
  time.sleep(self.client.retry_delay_sec)
100
112
  continue
101
113
  break
@@ -104,73 +116,81 @@ class Helpers:
104
116
  raise last_err
105
117
  raise Exception("Unknown error in sendFileInternal")
106
118
 
107
- async def SendFileAsync(self, **kwargs) -> Optional[Message]:
119
+ async def send_file_async(self, **kwargs: Any) -> Optional[Message]:
108
120
  """
109
- Async version of SendFile.
121
+ Async version of send_file.
110
122
 
111
123
  Example:
112
124
  # Sending a local file asynchronously:
113
- response = await api.helpers.SendFileAsync(
125
+ response = await bot.helpers.send_file_async(
114
126
  chat_id=123456789,
115
127
  text="Here is the report.",
116
128
  file_source="/local/path/to/report.pdf"
117
129
  )
118
130
  """
119
131
  req = SendFileReq(**kwargs)
120
- if self._is_url(req.file_source):
121
- return await self.sendFileByUrlAsync(req)
122
- return await self.sendFileByUploadAsync(req)
132
+ if urlparse(req.file_source).scheme in ("http", "https"):
133
+ return await self._send_file_by_url_async(req)
134
+
135
+ return await self._send_file_by_upload_async(req)
123
136
 
124
- async def sendFileByUrlAsync(self, req: SendFileReq) -> Optional[Message]:
137
+ async def _send_file_by_url_async(self, req: SendFileReq) -> Optional[Message]:
125
138
  ext = self._get_extension(req.file_source)
126
139
  upload_type = self._determine_upload_type(ext)
127
140
 
128
141
  if upload_type == UploadType.IMAGE:
129
142
  attachment = Attachment(type=AttachmentType.IMAGE, payload={"url": req.file_source})
130
- return await self.sendFileInternalAsync(req, attachment)
143
+ return await self._send_file_internal_async(req, attachment)
131
144
 
132
145
  temp_path = None
133
146
  try:
134
147
  temp_path = await self._download_temp_file_async(req.file_source)
135
148
  req.file_source = temp_path
136
- return await self.sendFileByUploadAsync(req)
149
+ return await self._send_file_by_upload_async(req)
137
150
  except Exception as e:
138
151
  logger.error(f"Async file processing/upload error: {e}")
139
- return None
152
+ raise
140
153
  finally:
141
154
  if temp_path and os.path.exists(temp_path):
142
- await asyncio.to_thread(os.remove, temp_path)
155
+ try:
156
+ await aiofiles.os.remove(temp_path)
157
+ except OSError as e:
158
+ logger.error(f"Failed to cleanup temp file: {e}")
143
159
 
144
- async def sendFileByUploadAsync(self, req: SendFileReq) -> Optional[Message]:
160
+ async def _send_file_by_upload_async(self, req: SendFileReq) -> Optional[Message]:
145
161
  ext = self._get_extension(req.file_source)
146
162
  u_type = self._determine_upload_type(ext)
147
163
 
148
164
  upload_req = UploadFileReq(type=u_type, file_path=req.file_source)
149
- upload_resp = await self.uploads.UploadFileAsync(**upload_req.model_dump())
165
+ upload_resp = await self.uploads.upload_file_async(**upload_req.model_dump(exclude_none=True))
150
166
 
151
167
  if not upload_resp or not upload_resp.token:
152
168
  return None
153
169
 
154
170
  attachment = self._build_attachment_from_token(u_type, upload_resp.token, Path(req.file_source).name)
155
- return await self.sendFileInternalAsync(req, attachment)
171
+ return await self._send_file_internal_async(req, attachment)
156
172
 
157
- async def sendFileInternalAsync(self, req: SendFileReq, attachment: Attachment) -> Message:
173
+ async def _send_file_internal_async(self, req: SendFileReq, attachment: Attachment) -> Message:
158
174
  attachments: List[Attachment] = req.attachments or []
159
175
  attachments.append(attachment)
160
176
 
161
177
  request_data = SendMessageReq(
162
- **req.model_dump(exclude={"file_source", "attachments"}),
163
- attachments=attachments
178
+ user_id=req.user_id,
179
+ chat_id=req.chat_id,
180
+ text=req.text,
181
+ format=req.format,
182
+ attachments=attachments,
183
+ notify=req.notify,
184
+ link=req.link,
185
+ disable_link_preview=req.disable_link_preview
164
186
  )
165
187
 
188
+ query, payload = self.client.split_request(request_data)
166
189
  last_err: Optional[Exception] = None
190
+
167
191
  for _ in range(self.client.max_retries):
168
192
  try:
169
- return await adecode(
170
- self.client, "POST", Paths.MESSAGES, Message,
171
- query=request_data.model_dump(exclude_none=True),
172
- payload=request_data
173
- )
193
+ return await self.client.adecode("POST", Paths.MESSAGES, Message, query=query, payload=payload)
174
194
  except Exception as e:
175
195
  last_err = e
176
196
  if "not.ready" in str(e).lower():
@@ -181,13 +201,6 @@ class Helpers:
181
201
  if last_err:
182
202
  raise last_err
183
203
  raise Exception("Unknown error in sendFileInternalAsync")
184
-
185
- def _is_url(self, source: str) -> bool:
186
- try:
187
- result = urlparse(source)
188
- return all([result.scheme, result.netloc])
189
- except ValueError:
190
- return False
191
204
 
192
205
  def _get_extension(self, source: str) -> str:
193
206
  parsed = urlparse(source)
@@ -202,6 +215,10 @@ class Helpers:
202
215
  if ext in {".mp3", ".ogg", ".wav"}:
203
216
  return UploadType.AUDIO
204
217
  return UploadType.FILE
218
+
219
+ def _sanitize_filename(self, filename: str) -> str:
220
+ base = os.path.basename(filename)
221
+ return re.sub(r'[^a-zA-Z0-9.\-_]', '_', base)
205
222
 
206
223
  def _build_attachment_from_token(self, u_type: UploadType, token: str, filename: str) -> Attachment:
207
224
  payload: dict[str, Any] = {"token": token}
@@ -211,14 +228,17 @@ class Helpers:
211
228
 
212
229
  def _download_temp_file(self, url_str: str) -> str:
213
230
  headers = {"User-Agent": "maxbot-client/1.0"}
214
- with httpx.Client() as client:
231
+ with httpx.Client(follow_redirects=True, max_redirects=3) as client:
232
+
215
233
  with client.stream("GET", url_str, headers=headers, follow_redirects=True) as resp:
216
234
  resp.raise_for_status()
217
235
 
218
236
  content_disp = resp.headers.get("Content-Disposition", "")
219
237
  filename = None
220
238
  if "filename=" in content_disp:
221
- filename = content_disp.split("filename=")[1].strip('"')
239
+ raw_part = content_disp.split("filename=")[1].split(";")[0]
240
+ raw_filename = raw_part.strip('"').strip("'")
241
+ filename = self._sanitize_filename(raw_filename)
222
242
 
223
243
  if not filename:
224
244
  content_type = resp.headers.get("Content-Type", "")
@@ -227,14 +247,17 @@ class Helpers:
227
247
  filename = f"file{ext}"
228
248
 
229
249
  if not filename:
230
- filename = Path(urlparse(url_str).path).name or "temp_file.bin"
231
-
232
- temp_path = f"temp_{int(time.time())}_{filename}"
233
-
234
- with open(temp_path, "wb") as f:
235
- for chunk in resp.iter_bytes(chunk_size=8192):
236
- f.write(chunk)
237
- return temp_path
250
+ filename = os.path.basename(Path(urlparse(url_str).path).name) or "temp_file.bin"
251
+
252
+ fd, temp_path = tempfile.mkstemp(prefix="temp_", suffix=f"_{os.path.basename(filename)}")
253
+ try:
254
+ with os.fdopen(fd, "wb") as f:
255
+ for chunk in resp.iter_bytes(chunk_size=8192):
256
+ f.write(chunk)
257
+ return temp_path
258
+ except Exception:
259
+ os.remove(temp_path)
260
+ raise
238
261
 
239
262
  async def _download_temp_file_async(self, url_str: str) -> str:
240
263
  headers = {"User-Agent": "maxbot-client/1.0"}
@@ -245,13 +268,15 @@ class Helpers:
245
268
  content_type = resp.headers.get("Content-Type", "").split(";")[0]
246
269
  extension = mimetypes.guess_extension(content_type) or ".bin"
247
270
 
248
- url_path_name = Path(urlparse(url_str).path).name
271
+ url_path_name = os.path.basename(Path(urlparse(url_str).path).name)
249
272
  if url_path_name == "uc" or not url_path_name:
250
273
  filename = f"file{extension}"
251
274
  else:
252
275
  filename = url_path_name if "." in url_path_name else f"{url_path_name}{extension}"
253
276
 
254
- temp_path = f"temp_{int(time.time())}_{filename}"
277
+ temp_file = tempfile.NamedTemporaryFile(prefix="temp_", suffix=f"_{os.path.basename(filename)}", delete=False)
278
+ temp_path = temp_file.name
279
+ temp_file.close()
255
280
 
256
281
  async with aiofiles.open(temp_path, "wb") as f:
257
282
  async for chunk in resp.aiter_bytes(chunk_size=8192):
@@ -1,194 +1,210 @@
1
- from maxbot_api_client_python.client import Client, decode, adecode
1
+ from typing import Any
2
+
3
+ from maxbot_api_client_python.client import Client
2
4
  from maxbot_api_client_python.types.constants import Paths
3
- from maxbot_api_client_python.types import models
5
+ from maxbot_api_client_python.types.models import AnswerCallbackReq, DeleteMessageReq, EditMessageReq, GetMessageReq, GetMessagesReq, GetVideoInfoReq, GetVideoInfoResp, Message, MessagesList, SendMessageReq, SendMessageResp, SimpleQueryResult
4
6
 
5
7
  class Messages:
6
8
  def __init__(self, client: Client):
7
9
  self.client = client
8
10
 
9
- def GetMessages(self, **kwargs) -> models.MessagesList:
11
+ def get_messages(self, **kwargs: Any) -> MessagesList:
10
12
  """
11
13
  Retrieves a list of messages.
12
14
  It can fetch messages belonging to a specific ChatID or by an exact list of MessageIDs.
13
15
 
14
16
  Example:
15
17
  # Fetch messages by Chat ID
16
- response = api.messages.GetMessages(chat_id=123456)
18
+ response = bot.messages.get_messages(chat_id=123456)
17
19
 
18
20
  # Fetch specific messages:
19
- response = api.messages.GetMessages(message_ids=["mid:1", "mid:2"])
21
+ response = bot.messages.get_messages(message_ids=["mid:1", "mid:2"])
20
22
  """
21
- req = models.GetMessagesReq(**kwargs)
22
- return decode(self.client, "GET", Paths.MESSAGES, models.MessagesList, query=req.model_dump(exclude_none=True))
23
+ req = GetMessagesReq(**kwargs)
24
+ query, payload = self.client.split_request(req)
25
+ return self.client.decode("GET", Paths.MESSAGES, MessagesList, query=query, payload=payload)
23
26
 
24
- def SendMessage(self, **kwargs) -> models.SendMessageResp:
27
+ def send_message(self, **kwargs: Any) -> SendMessageResp:
25
28
  """
26
29
  Sends a text message or attachment to a specific user or chat.
27
30
  If Notify is False, no push notification will be sent to the user.
28
31
 
29
32
  Example:
30
- response = api.messages.SendMessage(
33
+ response = bot.messages.send_message(
31
34
  chat_id=123456,
32
35
  text="Hello, world!",
33
36
  notify=True
34
37
  )
35
38
  """
36
- req = models.SendMessageReq(**kwargs)
37
- return decode(self.client, "POST", Paths.MESSAGES, models.SendMessageResp, query=req.model_dump(exclude_none=True), payload=req)
39
+ req = SendMessageReq(**kwargs)
40
+ query, payload = self.client.split_request(req)
41
+ return self.client.decode("POST", Paths.MESSAGES, SendMessageResp, query=query, payload=payload)
38
42
 
39
- def EditMessage(self, **kwargs) -> models.SimpleQueryResult:
43
+ def edit_message(self, **kwargs: Any) -> SimpleQueryResult:
40
44
  """
41
45
  Modifies the content of a previously sent message.
42
46
 
43
47
  Example:
44
- response = api.messages.EditMessage(
48
+ response = bot.messages.edit_message(
45
49
  message_id="mid:987654321...",
46
50
  text="Updated message text!",
47
51
  format="HTML"
48
52
  )
49
53
  """
50
- req = models.EditMessageReq(**kwargs)
51
- return decode(self.client, "PUT", Paths.MESSAGES, models.SimpleQueryResult, query=req.model_dump(exclude_none=True), payload=req)
54
+ req = EditMessageReq(**kwargs)
55
+ query, payload = self.client.split_request(req)
56
+ return self.client.decode("PUT", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
52
57
 
53
- def DeleteMessage(self, **kwargs) -> models.SimpleQueryResult:
58
+ def delete_message(self, **kwargs: Any) -> SimpleQueryResult:
54
59
  """
55
60
  Removes a previously sent message by its ID.
56
61
 
57
62
  Example:
58
- response = api.messages.DeleteMessage(
63
+ response = bot.messages.delete_message(
59
64
  message_id="mid:987654321..."
60
65
  )
61
66
  """
62
- req = models.DeleteMessageReq(**kwargs)
63
- return decode(self.client, "DELETE", Paths.MESSAGES, models.SimpleQueryResult, query=req.model_dump(exclude_none=True))
67
+ req = DeleteMessageReq(**kwargs)
68
+ query, payload = self.client.split_request(req)
69
+ return self.client.decode("DELETE", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
64
70
 
65
- def GetMessage(self, **kwargs) -> models.Message:
71
+ def get_message(self, **kwargs: Any) -> Message:
66
72
  """
67
73
  Retrieves full information about a message by its ID.
68
74
 
69
75
  Example:
70
- response = api.messages.GetMessage(
76
+ response = bot.messages.get_message(
71
77
  message_id="mid:987654321..."
72
78
  )
73
79
  """
74
- req = models.GetMessageReq(**kwargs)
80
+ req = GetMessageReq(**kwargs)
75
81
  path = f"{Paths.MESSAGES}/{req.message_id}"
76
- return decode(self.client, "GET", path, models.Message)
82
+ query, payload = self.client.split_request(req)
83
+ return self.client.decode("GET", path, Message, query=query, payload=payload)
77
84
 
78
- def GetVideoInfo(self, **kwargs) -> models.GetVideoInfoResp:
85
+ def get_video_info(self, **kwargs: Any) -> GetVideoInfoResp:
79
86
  """
80
87
  Retrieves metadata and the processing status for an uploaded video.
81
88
 
82
89
  Example:
83
- response = api.messages.GetVideoInfo(
90
+ response = bot.messages.get_video_info(
84
91
  video_token="vtok_abc123xyz..."
85
92
  )
86
93
  """
87
- req = models.GetVideoInfoReq(**kwargs)
94
+ req = GetVideoInfoReq(**kwargs)
88
95
  path = f"{Paths.VIDEOS}/{req.video_token}"
89
- return decode(self.client, "GET", path, models.GetVideoInfoResp)
96
+ query, payload = self.client.split_request(req)
97
+ return self.client.decode("GET", path, GetVideoInfoResp, query=query, payload=payload)
90
98
 
91
- def AnswerCallback(self, **kwargs) -> models.SimpleQueryResult:
99
+ def answer_callback(self, **kwargs: Any) -> SimpleQueryResult:
92
100
  """
93
101
  Acknowledges and responds to a user clicking an inline button.
94
102
 
95
103
  Example:
96
- response = api.messages.AnswerCallback(
104
+ response = bot.messages.answer_callback(
97
105
  callback_id="cbk_12345...",
98
106
  message=NewMessageBody(text="Action confirmed!")
99
107
  )
100
108
  """
101
- req = models.AnswerCallbackReq(**kwargs)
102
- return decode(self.client, "POST", Paths.ANSWERS, models.SimpleQueryResult, query=req.model_dump(exclude_none=True), payload=req)
109
+ req = AnswerCallbackReq(**kwargs)
110
+ query, payload = self.client.split_request(req)
111
+ return self.client.decode("POST", Paths.ANSWERS, SimpleQueryResult, query=query, payload=payload)
103
112
 
104
- async def GetMessagesAsync(self, **kwargs) -> models.MessagesList:
105
- """Async version of GetMessages.
113
+ async def get_messages_async(self, **kwargs: Any) -> MessagesList:
114
+ """Async version of get_messages.
106
115
 
107
116
  Example:
108
117
  # Fetch messages by Chat ID
109
- response = await api.messages.GetMessagesAsync(chat_id=123456)
118
+ response = await bot.messages.get_messages_async(chat_id=123456)
110
119
 
111
120
  # Fetch specific messages:
112
- response = await api.messages.GetMessagesAsync(message_ids=["mid:1", "mid:2"])
121
+ response = await bot.messages.get_messages_async(message_ids=["mid:1", "mid:2"])
113
122
  """
114
- req = models.GetMessagesReq(**kwargs)
115
- return await adecode(self.client, "GET", Paths.MESSAGES, models.MessagesList, query=req.model_dump(exclude_none=True))
123
+ req = GetMessagesReq(**kwargs)
124
+ query, payload = self.client.split_request(req)
125
+ return await self.client.adecode("GET", Paths.MESSAGES, MessagesList, query=query, payload=payload)
116
126
 
117
- async def SendMessageAsync(self, **kwargs) -> models.SendMessageResp:
127
+ async def send_message_async(self, **kwargs: Any) -> SendMessageResp:
118
128
  """
119
- Async version of SendMessage.
129
+ Async version of send_message.
120
130
 
121
131
  Example:
122
- response = await api.messages.SendMessageAsync(
132
+ response = await bot.messages.send_message_async(
123
133
  chat_id=123456,
124
134
  text="Hello, world!",
125
135
  notify=True
126
136
  )
127
137
  """
128
- req = models.SendMessageReq(**kwargs)
129
- return await adecode(self.client, "POST", Paths.MESSAGES, models.SendMessageResp, query=req.model_dump(exclude_none=True), payload=req)
138
+ req = SendMessageReq(**kwargs)
139
+ query, payload = self.client.split_request(req)
140
+ return await self.client.adecode("POST", Paths.MESSAGES, SendMessageResp, query=query, payload=payload)
130
141
 
131
- async def EditMessageAsync(self, **kwargs) -> models.SimpleQueryResult:
142
+ async def edit_message_async(self, **kwargs: Any) -> SimpleQueryResult:
132
143
  """
133
- Async version of EditMessage.
144
+ Async version of edit_message.
134
145
 
135
146
  Example:
136
- response = await api.messages.EditMessageAsync(
147
+ response = await bot.messages.edit_message_async(
137
148
  message_id="mid:987654321...",
138
149
  text="Updated message text!",
139
150
  format="HTML"
140
151
  )
141
152
  """
142
- req = models.EditMessageReq(**kwargs)
143
- return await adecode(self.client, "PUT", Paths.MESSAGES, models.SimpleQueryResult, query=req.model_dump(exclude_none=True), payload=req)
153
+ req = EditMessageReq(**kwargs)
154
+ query, payload = self.client.split_request(req)
155
+ return await self.client.adecode("PUT", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
144
156
 
145
- async def DeleteMessageAsync(self, **kwargs) -> models.SimpleQueryResult:
157
+ async def delete_message_async(self, **kwargs: Any) -> SimpleQueryResult:
146
158
  """
147
- Async version of DeleteMessage.
159
+ Async version of delete_message.
148
160
 
149
161
  Example:
150
- response = await api.messages.DeleteMessageAsync(
162
+ response = await bot.messages.delete_message_async(
151
163
  message_id="mid:987654321..."
152
164
  )
153
165
  """
154
- req = models.DeleteMessageReq(**kwargs)
155
- return await adecode(self.client, "DELETE", Paths.MESSAGES, models.SimpleQueryResult, query=req.model_dump(exclude_none=True))
166
+ req = DeleteMessageReq(**kwargs)
167
+ query, payload = self.client.split_request(req)
168
+ return await self.client.adecode("DELETE", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
156
169
 
157
- async def GetMessageAsync(self, **kwargs) -> models.Message:
170
+ async def get_message_async(self, **kwargs: Any) -> Message:
158
171
  """
159
- Async version of GetMessage.
172
+ Async version of get_message.
160
173
 
161
174
  Example:
162
- response = await api.messages.GetMessageAsync(
175
+ response = await bot.messages.get_message_async(
163
176
  message_id="mid:987654321..."
164
177
  )
165
178
  """
166
- req = models.GetMessageReq(**kwargs)
179
+ req = GetMessageReq(**kwargs)
167
180
  path = f"{Paths.MESSAGES}/{req.message_id}"
168
- return await adecode(self.client, "GET", path, models.Message)
181
+ query, payload = self.client.split_request(req)
182
+ return await self.client.adecode("GET", path, Message, query=query, payload=payload)
169
183
 
170
- async def GetVideoInfoAsync(self, **kwargs) -> models.GetVideoInfoResp:
184
+ async def get_video_info_async(self, **kwargs: Any) -> GetVideoInfoResp:
171
185
  """
172
- Async version of GetVideoInfo.
186
+ Async version of get_video.
173
187
 
174
188
  Example:
175
- response = await api.messages.GetVideoInfoAsync(
189
+ response = await bot.messages.get_video_info_async(
176
190
  video_token="vtok_abc123xyz..."
177
191
  )
178
192
  """
179
- req = models.GetVideoInfoReq(**kwargs)
193
+ req = GetVideoInfoReq(**kwargs)
180
194
  path = f"{Paths.VIDEOS}/{req.video_token}"
181
- return await adecode(self.client, "GET", path, models.GetVideoInfoResp)
195
+ query, payload = self.client.split_request(req)
196
+ return await self.client.adecode("GET", path, GetVideoInfoResp, query=query, payload=payload)
182
197
 
183
- async def AnswerCallbackAsync(self, **kwargs) -> models.SimpleQueryResult:
198
+ async def answer_callback_async(self, **kwargs: Any) -> SimpleQueryResult:
184
199
  """
185
- Async version of AnswerCallback.
200
+ Async version of answer_callback.
186
201
 
187
202
  Example:
188
- response = await api.messages.AnswerCallbackAsync(
203
+ response = await bot.messages.answer_callback_async(
189
204
  callback_id="cbk_12345...",
190
205
  message=NewMessageBody(text="Action confirmed!")
191
206
  )
192
207
  """
193
- req = models.AnswerCallbackReq(**kwargs)
194
- return await adecode(self.client, "POST", Paths.ANSWERS, models.SimpleQueryResult, query=req.model_dump(exclude_none=True), payload=req)
208
+ req = AnswerCallbackReq(**kwargs)
209
+ query, payload = self.client.split_request(req)
210
+ return await self.client.adecode("POST", Paths.ANSWERS, SimpleQueryResult, query=query, payload=payload)