Правки по mypy

This commit is contained in:
Денис Семёнов 2025-07-24 18:54:41 +03:00
parent 2cd3d64bb8
commit 7d2826c4b5
51 changed files with 461 additions and 338 deletions

View File

@ -1,7 +1,9 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List, Optional, TYPE_CHECKING from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING
from .client.default import DefaultConnectionProperties
from .types.input_media import InputMedia, InputMediaBuffer from .types.input_media import InputMedia, InputMediaBuffer
@ -82,6 +84,7 @@ class Bot(BaseConnection):
parse_mode: Optional[ParseMode] = None, parse_mode: Optional[ParseMode] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
auto_requests: bool = True, auto_requests: bool = True,
default_connection: Optional[DefaultConnectionProperties] = None
): ):
""" """
@ -91,22 +94,24 @@ class Bot(BaseConnection):
:param parse_mode: Форматирование по умолчанию :param parse_mode: Форматирование по умолчанию
:param notify: Отключение уведомлений при отправке сообщений (по умолчанию игнорируется) (не работает на стороне MAX) :param notify: Отключение уведомлений при отправке сообщений (по умолчанию игнорируется) (не работает на стороне MAX)
:param auto_requests: Автоматическое заполнение полей chat и from_user в Update :param auto_requests: Автоматическое заполнение полей chat и from_user в Update
:param default_connection: Настройки aiohttp
с помощью API запросов если они не заложены как полноценные объекты в Update (по умолчанию True, при False chat и from_user в некоторых событиях будут выдавать None) с помощью API запросов если они не заложены как полноценные объекты в Update (по умолчанию True, при False chat и from_user в некоторых событиях будут выдавать None)
""" """
super().__init__() super().__init__()
self.bot = self self.bot = self
self.default_connection = default_connection or DefaultConnectionProperties()
self.__token = token self.__token = token
self.params = {'access_token': self.__token} self.params: Dict[str, Any] = {'access_token': self.__token}
self.marker_updates = None self.marker_updates = None
self.parse_mode = parse_mode self.parse_mode = parse_mode
self.notify = notify self.notify = notify
self.auto_requests = auto_requests self.auto_requests = auto_requests
self._me: User = None self._me: User | None = None
@property @property
def me(self): def me(self):
@ -120,11 +125,11 @@ class Bot(BaseConnection):
async def send_message( async def send_message(
self, self,
chat_id: int = None, chat_id: Optional[int] = None,
user_id: int = None, user_id: Optional[int] = None,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
) -> SendedMessage: ) -> SendedMessage:
@ -152,11 +157,11 @@ class Bot(BaseConnection):
link=link, link=link,
notify=self._resolve_notify(notify), notify=self._resolve_notify(notify),
parse_mode=self._resolve_parse_mode(parse_mode) parse_mode=self._resolve_parse_mode(parse_mode)
).request() ).fetch()
async def send_action( async def send_action(
self, self,
chat_id: int = None, chat_id: Optional[int] = None,
action: SenderAction = SenderAction.TYPING_ON action: SenderAction = SenderAction.TYPING_ON
) -> SendedAction: ) -> SendedAction:
@ -173,14 +178,14 @@ class Bot(BaseConnection):
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
action=action action=action
).request() ).fetch()
async def edit_message( async def edit_message(
self, self,
message_id: str, message_id: str,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
) -> EditedMessage: ) -> EditedMessage:
@ -206,7 +211,7 @@ class Bot(BaseConnection):
link=link, link=link,
notify=self._resolve_notify(notify), notify=self._resolve_notify(notify),
parse_mode=self._resolve_parse_mode(parse_mode) parse_mode=self._resolve_parse_mode(parse_mode)
).request() ).fetch()
async def delete_message( async def delete_message(
self, self,
@ -224,7 +229,7 @@ class Bot(BaseConnection):
return await DeleteMessage( return await DeleteMessage(
bot=self, bot=self,
message_id=message_id, message_id=message_id,
).request() ).fetch()
async def delete_chat( async def delete_chat(
self, self,
@ -242,14 +247,14 @@ class Bot(BaseConnection):
return await DeleteChat( return await DeleteChat(
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
).request() ).fetch()
async def get_messages( async def get_messages(
self, self,
chat_id: int = None, chat_id: Optional[int] = None,
message_ids: List[str] = None, message_ids: Optional[List[str]] = None,
from_time: datetime | int = None, from_time: Optional[Union[datetime, int]] = None,
to_time: datetime | int = None, to_time: Optional[Union[datetime, int]] = None,
count: int = 50, count: int = 50,
) -> Messages: ) -> Messages:
@ -272,7 +277,7 @@ class Bot(BaseConnection):
from_time=from_time, from_time=from_time,
to_time=to_time, to_time=to_time,
count=count count=count
).request() ).fetch()
async def get_message( async def get_message(
self, self,
@ -299,7 +304,7 @@ class Bot(BaseConnection):
:return: Объект пользователя бота :return: Объект пользователя бота
""" """
return await GetMe(self).request() return await GetMe(self).fetch()
async def get_pin_message( async def get_pin_message(
self, self,
@ -317,14 +322,14 @@ class Bot(BaseConnection):
return await GetPinnedMessage( return await GetPinnedMessage(
bot=self, bot=self,
chat_id=chat_id chat_id=chat_id
).request() ).fetch()
async def change_info( async def change_info(
self, self,
name: str = None, name: Optional[str] = None,
description: str = None, description: Optional[str] = None,
commands: List[BotCommand] = None, commands: Optional[List[BotCommand]] = None,
photo: Dict[str, Any] = None photo: Optional[Dict[str, Any]] = None
) -> User: ) -> User:
""" """
@ -344,12 +349,12 @@ class Bot(BaseConnection):
description=description, description=description,
commands=commands, commands=commands,
photo=photo photo=photo
).request() ).fetch()
async def get_chats( async def get_chats(
self, self,
count: int = 50, count: int = 50,
marker: int = None marker: Optional[int] = None
) -> Chats: ) -> Chats:
""" """
@ -365,7 +370,7 @@ class Bot(BaseConnection):
bot=self, bot=self,
count=count, count=count,
marker=marker marker=marker
).request() ).fetch()
async def get_chat_by_link( async def get_chat_by_link(
self, self,
@ -380,7 +385,7 @@ class Bot(BaseConnection):
:return: Объект чата :return: Объект чата
""" """
return await GetChatByLink(bot=self, link=link).request() return await GetChatByLink(bot=self, link=link).fetch()
async def get_chat_by_id( async def get_chat_by_id(
self, self,
@ -395,14 +400,14 @@ class Bot(BaseConnection):
:return: Объект чата :return: Объект чата
""" """
return await GetChatById(bot=self, id=id).request() return await GetChatById(bot=self, id=id).fetch()
async def edit_chat( async def edit_chat(
self, self,
chat_id: int, chat_id: int,
icon: PhotoAttachmentRequestPayload = None, icon: Optional[PhotoAttachmentRequestPayload] = None,
title: str = None, title: Optional[str] = None,
pin: str = None, pin: Optional[str] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
) -> Chat: ) -> Chat:
@ -425,7 +430,7 @@ class Bot(BaseConnection):
title=title, title=title,
pin=pin, pin=pin,
notify=self._resolve_notify(notify), notify=self._resolve_notify(notify),
).request() ).fetch()
async def get_video( async def get_video(
self, self,
@ -443,13 +448,13 @@ class Bot(BaseConnection):
return await GetVideo( return await GetVideo(
bot=self, bot=self,
video_token=video_token video_token=video_token
).request() ).fetch()
async def send_callback( async def send_callback(
self, self,
callback_id: str, callback_id: str,
message: Message = None, message: Optional[Message] = None,
notification: str = None notification: Optional[str] = None
) -> SendedCallback: ) -> SendedCallback:
""" """
@ -467,7 +472,7 @@ class Bot(BaseConnection):
callback_id=callback_id, callback_id=callback_id,
message=message, message=message,
notification=notification notification=notification
).request() ).fetch()
async def pin_message( async def pin_message(
self, self,
@ -491,7 +496,7 @@ class Bot(BaseConnection):
chat_id=chat_id, chat_id=chat_id,
message_id=message_id, message_id=message_id,
notify=self._resolve_notify(notify), notify=self._resolve_notify(notify),
).request() ).fetch()
async def delete_pin_message( async def delete_pin_message(
self, self,
@ -509,7 +514,7 @@ class Bot(BaseConnection):
return await DeletePinMessage( return await DeletePinMessage(
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
).request() ).fetch()
async def get_me_from_chat( async def get_me_from_chat(
self, self,
@ -527,7 +532,7 @@ class Bot(BaseConnection):
return await GetMeFromChat( return await GetMeFromChat(
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
).request() ).fetch()
async def delete_me_from_chat( async def delete_me_from_chat(
self, self,
@ -545,7 +550,7 @@ class Bot(BaseConnection):
return await DeleteMeFromMessage( return await DeleteMeFromMessage(
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
).request() ).fetch()
async def get_list_admin_chat( async def get_list_admin_chat(
self, self,
@ -563,13 +568,13 @@ class Bot(BaseConnection):
return await GetListAdminChat( return await GetListAdminChat(
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
).request() ).fetch()
async def add_list_admin_chat( async def add_list_admin_chat(
self, self,
chat_id: int, chat_id: int,
admins: List[ChatAdmin], admins: List[ChatAdmin],
marker: int = None marker: Optional[int] = None
) -> AddedListAdminChat: ) -> AddedListAdminChat:
""" """
@ -587,7 +592,7 @@ class Bot(BaseConnection):
chat_id=chat_id, chat_id=chat_id,
admins=admins, admins=admins,
marker=marker, marker=marker,
).request() ).fetch()
async def remove_admin( async def remove_admin(
self, self,
@ -608,14 +613,14 @@ class Bot(BaseConnection):
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
user_id=user_id, user_id=user_id,
).request() ).fetch()
async def get_chat_members( async def get_chat_members(
self, self,
chat_id: int, chat_id: int,
user_ids: List[int] = None, user_ids: Optional[List[int]] = None,
marker: int = None, marker: Optional[int] = None,
count: int = None, count: Optional[int] = None,
) -> GettedMembersChat: ) -> GettedMembersChat:
""" """
@ -635,13 +640,13 @@ class Bot(BaseConnection):
user_ids=user_ids, user_ids=user_ids,
marker=marker, marker=marker,
count=count, count=count,
).request() ).fetch()
async def get_chat_member( async def get_chat_member(
self, self,
chat_id: int, chat_id: int,
user_id: int, user_id: int,
) -> GettedMembersChat: ) -> Optional[ChatMember]:
""" """
Получает участника чата. Получает участника чата.
@ -659,11 +664,13 @@ class Bot(BaseConnection):
if members.members: if members.members:
return members.members[0] return members.members[0]
return None
async def add_chat_members( async def add_chat_members(
self, self,
chat_id: int, chat_id: int,
user_ids: List[str], user_ids: List[int],
) -> AddedMembersChat: ) -> AddedMembersChat:
""" """
@ -679,7 +686,7 @@ class Bot(BaseConnection):
bot=self, bot=self,
chat_id=chat_id, chat_id=chat_id,
user_ids=user_ids, user_ids=user_ids,
).request() ).fetch()
async def kick_chat_member( async def kick_chat_member(
self, self,
@ -703,11 +710,11 @@ class Bot(BaseConnection):
chat_id=chat_id, chat_id=chat_id,
user_id=user_id, user_id=user_id,
block=block, block=block,
).request() ).fetch()
async def get_updates( async def get_updates(
self, self,
) -> UpdateUnion: ) -> Dict:
""" """
Получает обновления для бота. Получает обновления для бота.
@ -717,7 +724,7 @@ class Bot(BaseConnection):
return await GetUpdates( return await GetUpdates(
bot=self, bot=self,
).request() ).fetch()
async def get_upload_url( async def get_upload_url(
self, self,
@ -735,7 +742,7 @@ class Bot(BaseConnection):
return await GetUploadURL( return await GetUploadURL(
bot=self, bot=self,
type=type type=type
).request() ).fetch()
async def set_my_commands( async def set_my_commands(
self, self,
@ -753,7 +760,7 @@ class Bot(BaseConnection):
return await ChangeInfo( return await ChangeInfo(
bot=self, bot=self,
commands=list(commands) commands=list(commands)
).request() ).fetch()
async def download_file( async def download_file(
self, self,
@ -777,4 +784,4 @@ class Bot(BaseConnection):
path=path, path=path,
media_url=url, media_url=url,
media_token=token media_token=token
).request() ).fetch()

10
maxapi/client/default.py Normal file
View File

@ -0,0 +1,10 @@
from aiohttp import ClientTimeout
class DefaultConnectionProperties:
def __init__(self, timeout: int = 5 * 30, sock_connect: int = 30, **kwargs):
self.timeout = ClientTimeout(total=timeout, sock_connect=sock_connect)
self.kwargs = kwargs

View File

@ -1,7 +1,9 @@
from __future__ import annotations
import os import os
import mimetypes import mimetypes
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any, Optional
from uuid import uuid4 from uuid import uuid4
import aiofiles import aiofiles
@ -18,7 +20,7 @@ from ..enums.http_method import HTTPMethod
from ..enums.api_path import ApiPath from ..enums.api_path import ApiPath
from ..enums.upload_type import UploadType from ..enums.upload_type import UploadType
from ..loggers import logger_bot, logger_connection from ..loggers import logger_bot
if TYPE_CHECKING: if TYPE_CHECKING:
from ..bot import Bot from ..bot import Bot
@ -36,15 +38,15 @@ class BaseConnection:
API_URL = 'https://botapi.max.ru' API_URL = 'https://botapi.max.ru'
def __init__(self): def __init__(self) -> None:
self.bot: 'Bot' = None self.bot: Optional[Bot] = None
self.session: ClientSession = None self.session: Optional[ClientSession] = None
async def request( async def request(
self, self,
method: HTTPMethod, method: HTTPMethod,
path: ApiPath, path: ApiPath | str,
model: BaseModel = None, model: BaseModel | Any = None,
is_return_raw: bool = False, is_return_raw: bool = False,
**kwargs **kwargs
): ):
@ -64,8 +66,14 @@ class BaseConnection:
- dict (если is_return_raw=True) - dict (если is_return_raw=True)
""" """
assert self.bot is not None
if not self.bot.session: if not self.bot.session:
self.bot.session = ClientSession(self.bot.API_URL) self.bot.session = ClientSession(
base_url=self.bot.API_URL,
timeout=self.bot.default_connection.timeout,
**self.bot.default_connection.kwargs
)
try: try:
r = await self.bot.session.request( r = await self.bot.session.request(
@ -90,7 +98,7 @@ class BaseConnection:
if is_return_raw: return raw if is_return_raw: return raw
model = model(**raw) model = model(**raw) # type: ignore
if hasattr(model, 'message'): if hasattr(model, 'message'):
attr = getattr(model, 'message') attr = getattr(model, 'message')

View File

@ -1,6 +1,6 @@
import asyncio import asyncio
from typing import Any, Dict from typing import Any, Dict, Optional, Union
from ..context.state_machine import State, StatesGroup from ..context.state_machine import State, StatesGroup
@ -19,7 +19,7 @@ class MemoryContext:
self.chat_id = chat_id self.chat_id = chat_id
self.user_id = user_id self.user_id = user_id
self._context: Dict[str, Any] = {} self._context: Dict[str, Any] = {}
self._state: State | None = None self._state: State | str | None = None
self._lock = asyncio.Lock() self._lock = asyncio.Lock()
async def get_data(self) -> dict[str, Any]: async def get_data(self) -> dict[str, Any]:
@ -58,7 +58,7 @@ class MemoryContext:
async with self._lock: async with self._lock:
self._context.update(kwargs) self._context.update(kwargs)
async def set_state(self, state: State | str = None): async def set_state(self, state: Optional[Union[State, str]] = None):
""" """
Устанавливает новое состояние. Устанавливает новое состояние.

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import asyncio import asyncio
from typing import Any, Callable, Dict, List, TYPE_CHECKING from typing import Any, Callable, Dict, List, TYPE_CHECKING, Optional, cast
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
@ -45,7 +45,7 @@ class Dispatcher:
применение middleware, фильтров и вызов соответствующих обработчиков. применение middleware, фильтров и вызов соответствующих обработчиков.
""" """
def __init__(self): def __init__(self) -> None:
""" """
Инициализация диспетчера. Инициализация диспетчера.
@ -53,12 +53,12 @@ class Dispatcher:
self.event_handlers: List[Handler] = [] self.event_handlers: List[Handler] = []
self.contexts: List[MemoryContext] = [] self.contexts: List[MemoryContext] = []
self.routers: List[Router] = [] self.routers: List[Router | Dispatcher] = []
self.filters: List[MagicFilter] = [] self.filters: List[MagicFilter] = []
self.middlewares: List[BaseMiddleware] = [] self.middlewares: List[BaseMiddleware] = []
self.bot: Bot = None self.bot: Optional[Bot] = None
self.on_started_func: Callable = None self.on_started_func: Optional[Callable] = None
self.message_created = Event(update_type=UpdateType.MESSAGE_CREATED, router=self) self.message_created = Event(update_type=UpdateType.MESSAGE_CREATED, router=self)
self.bot_added = Event(update_type=UpdateType.BOT_ADDED, router=self) self.bot_added = Event(update_type=UpdateType.BOT_ADDED, router=self)
@ -249,18 +249,18 @@ class Dispatcher:
while True: while True:
try: try:
events = await self.bot.get_updates() events: Dict = await self.bot.get_updates() # type: ignore
if isinstance(events, Error): if isinstance(events, Error):
logger_dp.info(f'Ошибка при получении обновлений: {events}, жду {GET_UPDATES_RETRY_DELAY} секунд') logger_dp.info(f'Ошибка при получении обновлений: {events}, жду {GET_UPDATES_RETRY_DELAY} секунд')
await asyncio.sleep(GET_UPDATES_RETRY_DELAY) await asyncio.sleep(GET_UPDATES_RETRY_DELAY)
continue continue
self.bot.marker_updates = events.get('marker') self.bot.marker_updates = events.get('marker') # type: ignore
processed_events = await process_update_request( processed_events = await process_update_request(
events=events, events=events,
bot=self.bot bot=self.bot # type: ignore
) )
for event in processed_events: for event in processed_events:
@ -270,7 +270,7 @@ class Dispatcher:
logger_dp.error(f'Ошибка подключения, жду {CONNECTION_RETRY_DELAY} секунд') logger_dp.error(f'Ошибка подключения, жду {CONNECTION_RETRY_DELAY} секунд')
await asyncio.sleep(CONNECTION_RETRY_DELAY) await asyncio.sleep(CONNECTION_RETRY_DELAY)
except Exception as e: except Exception as e:
logger_dp.error(f'Общая ошибка при обработке событий: {e}') logger_dp.error(f'Общая ошибка при обработке событий: {e.__class__} - {e}')
async def handle_webhook(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080): async def handle_webhook(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080):
@ -289,7 +289,7 @@ class Dispatcher:
event_object = await process_update_webhook( event_object = await process_update_webhook(
event_json=event_json, event_json=event_json,
bot=self.bot bot=self.bot # type: ignore
) )
await self.handle(event_object) await self.handle(event_object)

View File

@ -16,4 +16,5 @@ class AttachmentType(str, Enum):
STICKER = 'sticker' STICKER = 'sticker'
CONTACT = 'contact' CONTACT = 'contact'
INLINE_KEYBOARD = 'inline_keyboard' INLINE_KEYBOARD = 'inline_keyboard'
LOCATION = 'location' LOCATION = 'location'
SHARE = 'share'

View File

@ -1,3 +1,11 @@
class MaxConnection(BaseException): class MaxConnection(BaseException):
...
class MaxUploadFileFailed(BaseException):
...
class MaxIconParamsException(BaseException):
... ...

View File

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, List from typing import TYPE_CHECKING, Any, Dict, List, Optional
from .types.added_admin_chat import AddedListAdminChat from .types.added_admin_chat import AddedListAdminChat
from ..types.users import ChatAdmin from ..types.users import ChatAdmin
@ -30,14 +30,14 @@ class AddAdminChat(BaseConnection):
bot: 'Bot', bot: 'Bot',
chat_id: int, chat_id: int,
admins: List[ChatAdmin], admins: List[ChatAdmin],
marker: int = None marker: Optional[int] = None
): ):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
self.admins = admins self.admins = admins
self.marker = marker self.marker = marker
async def request(self) -> AddedListAdminChat: async def fetch(self) -> AddedListAdminChat:
""" """
Выполняет HTTP POST запрос для добавления администраторов в чат. Выполняет HTTP POST запрос для добавления администраторов в чат.
@ -48,7 +48,9 @@ class AddAdminChat(BaseConnection):
AddedListAdminChat: Результат операции с информацией об успешности. AddedListAdminChat: Результат операции с информацией об успешности.
""" """
json = {} assert self.bot is not None
json: Dict[str, Any] = {}
json['admins'] = [admin.model_dump() for admin in self.admins] json['admins'] = [admin.model_dump() for admin in self.admins]
json['marker'] = self.marker json['marker'] = self.marker

View File

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, List from typing import TYPE_CHECKING, Any, Dict, List
from ..methods.types.added_members_chat import AddedMembersChat from ..methods.types.added_members_chat import AddedMembersChat
@ -34,7 +34,7 @@ class AddMembersChat(BaseConnection):
self.chat_id = chat_id self.chat_id = chat_id
self.user_ids = user_ids self.user_ids = user_ids
async def request(self) -> AddedMembersChat: async def fetch(self) -> AddedMembersChat:
""" """
Отправляет POST-запрос на добавление пользователей в чат. Отправляет POST-запрос на добавление пользователей в чат.
@ -45,7 +45,9 @@ class AddMembersChat(BaseConnection):
AddedMembersChat: Результат операции с информацией об успешности добавления. AddedMembersChat: Результат операции с информацией об успешности добавления.
""" """
json = {} assert self.bot is not None
json: Dict[str, Any] = {}
json['user_ids'] = self.user_ids json['user_ids'] = self.user_ids

View File

@ -1,4 +1,4 @@
from typing import Any, Dict, List, TYPE_CHECKING from typing import Any, Dict, List, TYPE_CHECKING, Optional
from ..types.users import User from ..types.users import User
from ..types.command import BotCommand from ..types.command import BotCommand
@ -29,10 +29,10 @@ class ChangeInfo(BaseConnection):
def __init__( def __init__(
self, self,
bot: 'Bot', bot: 'Bot',
name: str = None, name: Optional[str] = None,
description: str = None, description: Optional[str] = None,
commands: List[BotCommand] = None, commands: Optional[List[BotCommand]] = None,
photo: Dict[str, Any] = None photo: Optional[Dict[str, Any]] = None
): ):
self.bot = bot self.bot = bot
self.name = name self.name = name
@ -40,7 +40,7 @@ class ChangeInfo(BaseConnection):
self.commands = commands self.commands = commands
self.photo = photo self.photo = photo
async def request(self) -> User: async def fetch(self) -> User:
"""Отправляет запрос на изменение информации о боте. """Отправляет запрос на изменение информации о боте.
@ -48,7 +48,9 @@ class ChangeInfo(BaseConnection):
User: Объект с обновленными данными бота User: Объект с обновленными данными бота
""" """
json = {} assert self.bot is not None
json: Dict[str, Any] = {}
if self.name: json['name'] = self.name if self.name: json['name'] = self.name
if self.description: json['description'] = self.description if self.description: json['description'] = self.description

View File

@ -30,7 +30,7 @@ class DeleteMeFromMessage(BaseConnection):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def request(self) -> DeletedBotFromChat: async def fetch(self) -> DeletedBotFromChat:
""" """
Отправляет DELETE-запрос для удаления бота из чата. Отправляет DELETE-запрос для удаления бота из чата.
@ -39,6 +39,7 @@ class DeleteMeFromMessage(BaseConnection):
DeletedBotFromChat: Результат операции удаления. DeletedBotFromChat: Результат операции удаления.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.DELETE, method=HTTPMethod.DELETE,
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME, path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,

View File

@ -29,7 +29,7 @@ class DeleteChat(BaseConnection):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def request(self) -> DeletedChat: async def fetch(self) -> DeletedChat:
""" """
Отправляет DELETE-запрос для удаления указанного чата. Отправляет DELETE-запрос для удаления указанного чата.
@ -38,6 +38,7 @@ class DeleteChat(BaseConnection):
DeletedChat: Результат операции удаления чата. DeletedChat: Результат операции удаления чата.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.DELETE, method=HTTPMethod.DELETE,
path=ApiPath.CHATS.value + '/' + str(self.chat_id), path=ApiPath.CHATS.value + '/' + str(self.chat_id),

View File

@ -29,7 +29,7 @@ class DeleteMessage(BaseConnection):
self.bot = bot self.bot = bot
self.message_id = message_id self.message_id = message_id
async def request(self) -> DeletedMessage: async def fetch(self) -> DeletedMessage:
""" """
Выполняет DELETE-запрос для удаления сообщения. Выполняет DELETE-запрос для удаления сообщения.
@ -40,6 +40,7 @@ class DeleteMessage(BaseConnection):
DeletedMessage: Результат операции удаления сообщения. DeletedMessage: Результат операции удаления сообщения.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
params['message_id'] = self.message_id params['message_id'] = self.message_id

View File

@ -19,18 +19,18 @@ class DeletePinMessage(BaseConnection):
Args: Args:
bot (Bot): Экземпляр бота для выполнения запроса. bot (Bot): Экземпляр бота для выполнения запроса.
chat_id (str): Идентификатор чата, из которого нужно удалить закреплённое сообщение. chat_id (int): Идентификатор чата, из которого нужно удалить закреплённое сообщение.
""" """
def __init__( def __init__(
self, self,
bot: 'Bot', bot: 'Bot',
chat_id: str, chat_id: int,
): ):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def request(self) -> DeletedPinMessage: async def fetch(self) -> DeletedPinMessage:
""" """
Выполняет DELETE-запрос для удаления закреплённого сообщения. Выполняет DELETE-запрос для удаления закреплённого сообщения.
@ -38,7 +38,7 @@ class DeletePinMessage(BaseConnection):
Returns: Returns:
DeletedPinMessage: Результат операции удаления закреплённого сообщения. DeletedPinMessage: Результат операции удаления закреплённого сообщения.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.DELETE, method=HTTPMethod.DELETE,
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN, path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,

View File

@ -36,7 +36,7 @@ class DownloadMedia(BaseConnection):
self.media_url = media_url self.media_url = media_url
self.media_token = media_token self.media_token = media_token
async def request(self) -> int: async def fetch(self) -> int:
""" """
Выполняет GET-запрос для скачивания медиафайла Выполняет GET-запрос для скачивания медиафайла

View File

@ -1,9 +1,11 @@
from logging import getLogger from logging import getLogger
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any, Dict, Optional
from collections import Counter from collections import Counter
from ..exceptions.max import MaxIconParamsException
from ..types.attachments.image import PhotoAttachmentRequestPayload from ..types.attachments.image import PhotoAttachmentRequestPayload
from ..types.chats import Chat from ..types.chats import Chat
@ -37,10 +39,10 @@ class EditChat(BaseConnection):
self, self,
bot: 'Bot', bot: 'Bot',
chat_id: int, chat_id: int,
icon: PhotoAttachmentRequestPayload = None, icon: Optional[PhotoAttachmentRequestPayload] = None,
title: str = None, title: Optional[str] = None,
pin: str = None, pin: Optional[str] = None,
notify: bool = True, notify: Optional[bool] = None,
): ):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
@ -49,7 +51,7 @@ class EditChat(BaseConnection):
self.pin = pin self.pin = pin
self.notify = notify self.notify = notify
async def request(self) -> Chat: async def fetch(self) -> Chat:
""" """
Выполняет PATCH-запрос для обновления параметров чата. Выполняет PATCH-запрос для обновления параметров чата.
@ -62,7 +64,8 @@ class EditChat(BaseConnection):
Chat: Обновлённый объект чата. Chat: Обновлённый объект чата.
""" """
json = {} assert self.bot is not None
json: Dict[str, Any] = {}
if self.icon: if self.icon:
dump = self.icon.model_dump() dump = self.icon.model_dump()
@ -70,7 +73,8 @@ class EditChat(BaseConnection):
if not None in counter or \ if not None in counter or \
not counter[None] == 2: not counter[None] == 2:
return logger.error(
raise MaxIconParamsException(
'Все атрибуты модели Icon являются взаимоисключающими | ' 'Все атрибуты модели Icon являются взаимоисключающими | '
'https://dev.max.ru/docs-api/methods/PATCH/chats/-chatId-' 'https://dev.max.ru/docs-api/methods/PATCH/chats/-chatId-'
) )

View File

@ -1,6 +1,8 @@
from __future__ import annotations from __future__ import annotations
from typing import List, TYPE_CHECKING, Optional from typing import Any, Dict, List, TYPE_CHECKING, Optional
from ..utils.message import process_input_media
from .types.edited_message import EditedMessage from .types.edited_message import EditedMessage
from ..types.message import NewMessageLink from ..types.message import NewMessageLink
@ -37,10 +39,10 @@ class EditMessage(BaseConnection):
self, self,
bot: Bot, bot: Bot,
message_id: str, message_id: str,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: bool = True, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
): ):
self.bot = bot self.bot = bot
@ -51,7 +53,7 @@ class EditMessage(BaseConnection):
self.notify = notify self.notify = notify
self.parse_mode = parse_mode self.parse_mode = parse_mode
async def request(self) -> EditedMessage: async def fetch(self) -> EditedMessage:
""" """
Выполняет PUT-запрос для обновления сообщения. Выполняет PUT-запрос для обновления сообщения.
@ -62,15 +64,31 @@ class EditMessage(BaseConnection):
EditedMessage: Обновлённое сообщение. EditedMessage: Обновлённое сообщение.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
json = {} json: Dict[str, Any] = {}
params['message_id'] = self.message_id params['message_id'] = self.message_id
if not self.text is None: json['text'] = self.text if not self.text is None: json['text'] = self.text
if self.attachments: json['attachments'] = \
[att.model_dump() for att in self.attachments] if self.attachments:
for att in self.attachments:
if isinstance(att, InputMedia) or isinstance(att, InputMediaBuffer):
input_media = await process_input_media(
base_connection=self,
bot=self.bot,
att=att
)
json['attachments'].append(
input_media.model_dump()
)
else:
json['attachments'].append(att.model_dump())
if not self.link is None: json['link'] = self.link.model_dump() if not self.link is None: json['link'] = self.link.model_dump()
if not self.notify is None: json['notify'] = self.notify if not self.notify is None: json['notify'] = self.notify
if not self.parse_mode is None: json['format'] = self.parse_mode.value if not self.parse_mode is None: json['format'] = self.parse_mode.value

View File

@ -30,7 +30,7 @@ class GetChatById(BaseConnection):
self.bot = bot self.bot = bot
self.id = id self.id = id
async def request(self) -> Chat: async def fetch(self) -> Chat:
""" """
Выполняет GET-запрос для получения данных чата. Выполняет GET-запрос для получения данных чата.
@ -39,6 +39,7 @@ class GetChatById(BaseConnection):
Chat: Объект чата с полной информацией. Chat: Объект чата с полной информацией.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.CHATS.value + '/' + str(self.id), path=ApiPath.CHATS.value + '/' + str(self.id),

View File

@ -40,7 +40,7 @@ class GetChatByLink(BaseConnection):
if not self.link: if not self.link:
return return
async def request(self) -> Chat: async def fetch(self) -> Chat:
""" """
Выполняет GET-запрос для получения данных чата по ссылке. Выполняет GET-запрос для получения данных чата по ссылке.
@ -49,6 +49,7 @@ class GetChatByLink(BaseConnection):
Chat: Объект с информацией о чате. Chat: Объект с информацией о чате.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.CHATS.value + '/' + self.link[-1], path=ApiPath.CHATS.value + '/' + self.link[-1],

View File

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Optional
from ..types.chats import Chats from ..types.chats import Chats
@ -32,13 +32,13 @@ class GetChats(BaseConnection):
self, self,
bot: 'Bot', bot: 'Bot',
count: int = 50, count: int = 50,
marker: int = None marker: Optional[int] = None
): ):
self.bot = bot self.bot = bot
self.count = count self.count = count
self.marker = marker self.marker = marker
async def request(self) -> Chats: async def fetch(self) -> Chats:
""" """
Выполняет GET-запрос для получения списка чатов. Выполняет GET-запрос для получения списка чатов.
@ -46,7 +46,7 @@ class GetChats(BaseConnection):
Returns: Returns:
Chats: Объект с данными по списку чатов. Chats: Объект с данными по списку чатов.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
params['count'] = self.count params['count'] = self.count

View File

@ -34,7 +34,7 @@ class GetListAdminChat(BaseConnection):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def request(self) -> GettedListAdminChat: async def fetch(self) -> GettedListAdminChat:
""" """
Выполняет GET-запрос для получения списка администраторов указанного чата. Выполняет GET-запрос для получения списка администраторов указанного чата.
@ -42,7 +42,7 @@ class GetListAdminChat(BaseConnection):
Returns: Returns:
GettedListAdminChat: Объект с информацией о администраторах чата. GettedListAdminChat: Объект с информацией о администраторах чата.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ADMINS, path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ADMINS,

View File

@ -24,7 +24,7 @@ class GetMe(BaseConnection):
def __init__(self, bot: 'Bot'): def __init__(self, bot: 'Bot'):
self.bot = bot self.bot = bot
async def request(self) -> User: async def fetch(self) -> User:
""" """
Выполняет GET-запрос для получения данных о боте. Выполняет GET-запрос для получения данных о боте.
@ -32,7 +32,7 @@ class GetMe(BaseConnection):
Returns: Returns:
User: Объект пользователя с полной информацией. User: Объект пользователя с полной информацией.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.ME, path=ApiPath.ME,

View File

@ -34,7 +34,7 @@ class GetMeFromChat(BaseConnection):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def request(self) -> ChatMember: async def fetch(self) -> ChatMember:
""" """
Выполняет GET-запрос для получения информации о боте в указанном чате. Выполняет GET-запрос для получения информации о боте в указанном чате.
@ -42,7 +42,7 @@ class GetMeFromChat(BaseConnection):
Returns: Returns:
ChatMember: Информация о боте как участнике чата. ChatMember: Информация о боте как участнике чата.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME, path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,

View File

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, List from typing import TYPE_CHECKING, List, Optional
from ..methods.types.getted_members_chat import GettedMembersChat from ..methods.types.getted_members_chat import GettedMembersChat
@ -27,7 +27,7 @@ class GetMembersChat(BaseConnection):
Attributes: Attributes:
bot (Bot): Экземпляр бота. bot (Bot): Экземпляр бота.
chat_id (int): Идентификатор чата. chat_id (int): Идентификатор чата.
user_ids (List[str] | None): Список ID пользователей для фильтра. user_ids (List[int] | None): Список ID пользователей для фильтра.
marker (int | None): Позиция для пагинации. marker (int | None): Позиция для пагинации.
count (int | None): Максимальное количество участников. count (int | None): Максимальное количество участников.
""" """
@ -36,9 +36,9 @@ class GetMembersChat(BaseConnection):
self, self,
bot: 'Bot', bot: 'Bot',
chat_id: int, chat_id: int,
user_ids: List[str] = None, user_ids: Optional[List[int]] = None,
marker: int = None, marker: Optional[int] = None,
count: int = None, count: Optional[int] = None,
): ):
self.bot = bot self.bot = bot
@ -47,7 +47,7 @@ class GetMembersChat(BaseConnection):
self.marker = marker self.marker = marker
self.count = count self.count = count
async def request(self) -> GettedMembersChat: async def fetch(self) -> GettedMembersChat:
""" """
Выполняет GET-запрос для получения участников чата с опциональной фильтрацией. Выполняет GET-запрос для получения участников чата с опциональной фильтрацией.
@ -57,12 +57,12 @@ class GetMembersChat(BaseConnection):
Returns: Returns:
GettedMembersChat: Объект с данными по участникам чата. GettedMembersChat: Объект с данными по участникам чата.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
if self.user_ids: if self.user_ids:
self.user_ids = [str(user_id) for user_id in self.user_ids] params['user_ids'] = ','.join([str(user_id) for user_id in self.user_ids])
params['user_ids'] = ','.join(self.user_ids)
if self.marker: params['marker'] = self.marker if self.marker: params['marker'] = self.marker
if self.count: params['marker'] = self.count if self.count: params['marker'] = self.count

View File

@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING, List from typing import TYPE_CHECKING, List, Optional, Union
from ..types.message import Messages from ..types.message import Messages
from ..enums.http_method import HTTPMethod from ..enums.http_method import HTTPMethod
@ -36,10 +36,10 @@ class GetMessages(BaseConnection):
def __init__( def __init__(
self, self,
bot: 'Bot', bot: 'Bot',
chat_id: int, chat_id: Optional[int] = None,
message_ids: List[str] = None, message_ids: Optional[List[str]] = None,
from_time: datetime | int = None, from_time: Optional[Union[datetime, int]] = None,
to_time: datetime | int = None, to_time: Optional[Union[datetime, int]] = None,
count: int = 50, count: int = 50,
): ):
self.bot = bot self.bot = bot
@ -49,7 +49,7 @@ class GetMessages(BaseConnection):
self.to_time = to_time self.to_time = to_time
self.count = count self.count = count
async def request(self) -> Messages: async def fetch(self) -> Messages:
""" """
Выполняет GET-запрос для получения сообщений с учётом параметров фильтрации. Выполняет GET-запрос для получения сообщений с учётом параметров фильтрации.
@ -59,7 +59,7 @@ class GetMessages(BaseConnection):
Returns: Returns:
Messages: Объект с полученными сообщениями. Messages: Объект с полученными сообщениями.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
if self.chat_id: params['chat_id'] = self.chat_id if self.chat_id: params['chat_id'] = self.chat_id

View File

@ -29,7 +29,7 @@ class GetPinnedMessage(BaseConnection):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def request(self) -> GettedPin: async def fetch(self) -> GettedPin:
""" """
Выполняет GET-запрос для получения закреплённого сообщения. Выполняет GET-запрос для получения закреплённого сообщения.
@ -37,7 +37,7 @@ class GetPinnedMessage(BaseConnection):
Returns: Returns:
GettedPin: Объект с информацией о закреплённом сообщении. GettedPin: Объект с информацией о закреплённом сообщении.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN, path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,

View File

@ -1,4 +1,5 @@
from typing import TYPE_CHECKING from __future__ import annotations
from typing import TYPE_CHECKING, Dict
from ..types.updates import UpdateUnion from ..types.updates import UpdateUnion
@ -28,13 +29,13 @@ class GetUpdates(BaseConnection):
def __init__( def __init__(
self, self,
bot: 'Bot', bot: Bot,
limit: int = 100, limit: int = 100,
): ):
self.bot = bot self.bot = bot
self.limit = limit self.limit = limit
async def request(self) -> UpdateUnion: async def fetch(self) -> Dict:
""" """
Выполняет GET-запрос для получения обновлений с указанным лимитом. Выполняет GET-запрос для получения обновлений с указанным лимитом.
@ -44,7 +45,7 @@ class GetUpdates(BaseConnection):
Returns: Returns:
UpdateUnion: Объединённый тип данных обновлений. UpdateUnion: Объединённый тип данных обновлений.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
params['limit'] = self.limit params['limit'] = self.limit

View File

@ -33,7 +33,7 @@ class GetUploadURL(BaseConnection):
self.bot = bot self.bot = bot
self.type = type self.type = type
async def request(self) -> GettedUploadUrl: async def fetch(self) -> GettedUploadUrl:
""" """
Выполняет POST-запрос для получения URL загрузки файла. Выполняет POST-запрос для получения URL загрузки файла.
@ -43,7 +43,7 @@ class GetUploadURL(BaseConnection):
Returns: Returns:
GettedUploadUrl: Результат с URL для загрузки. GettedUploadUrl: Результат с URL для загрузки.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
params['type'] = self.type.value params['type'] = self.type.value

View File

@ -30,7 +30,7 @@ class GetVideo(BaseConnection):
self.bot = bot self.bot = bot
self.video_token = video_token self.video_token = video_token
async def request(self) -> Video: async def fetch(self) -> Video:
""" """
Выполняет GET-запрос для получения данных видео по токену. Выполняет GET-запрос для получения данных видео по токену.
@ -38,7 +38,7 @@ class GetVideo(BaseConnection):
Returns: Returns:
Video: Объект с информацией о видео. Video: Объект с информацией о видео.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.GET, method=HTTPMethod.GET,
path=ApiPath.VIDEOS.value + '/' + self.video_token, path=ApiPath.VIDEOS.value + '/' + self.video_token,

View File

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any, Dict, Optional
from .types.pinned_message import PinnedMessage from .types.pinned_message import PinnedMessage
@ -35,14 +35,14 @@ class PinMessage(BaseConnection):
bot: 'Bot', bot: 'Bot',
chat_id: int, chat_id: int,
message_id: str, message_id: str,
notify: bool = True notify: Optional[bool] = None
): ):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
self.message_id = message_id self.message_id = message_id
self.notify = notify self.notify = notify
async def request(self) -> PinnedMessage: async def fetch(self) -> PinnedMessage:
""" """
Выполняет PUT-запрос для закрепления сообщения в чате. Выполняет PUT-запрос для закрепления сообщения в чате.
@ -52,8 +52,8 @@ class PinMessage(BaseConnection):
Returns: Returns:
PinnedMessage: Объект с информацией о закреплённом сообщении. PinnedMessage: Объект с информацией о закреплённом сообщении.
""" """
assert self.bot is not None
json = {} json: Dict[str, Any] = {}
json['message_id'] = self.message_id json['message_id'] = self.message_id
json['notify'] = self.notify json['notify'] = self.notify

View File

@ -38,7 +38,7 @@ class RemoveAdmin(BaseConnection):
self.chat_id = chat_id self.chat_id = chat_id
self.user_id = user_id self.user_id = user_id
async def request(self) -> RemovedAdmin: async def fetch(self) -> RemovedAdmin:
""" """
Выполняет DELETE-запрос для отмены прав администратора в чате. Выполняет DELETE-запрос для отмены прав администратора в чате.
@ -46,11 +46,11 @@ class RemoveAdmin(BaseConnection):
Returns: Returns:
RemovedAdmin: Объект с результатом отмены прав администратора. RemovedAdmin: Объект с результатом отмены прав администратора.
""" """
assert self.bot is not None
return await super().request( return await super().request(
method=HTTPMethod.DELETE, method=HTTPMethod.DELETE,
path=ApiPath.CHATS + '/' + str(self.chat_id) + \ path=ApiPath.CHATS + '/' + str(self.chat_id) + \
ApiPath.MEMBERS + ApiPath.ADMINS + '/' + str(self.user_id), ApiPath.MEMBERS + ApiPath.ADMINS + '/' + str(self.user_id),
model=RemovedAdmin, model=RemovedAdmin,
params=self.bot.params, params=self.bot.params,
) )

View File

@ -43,7 +43,7 @@ class RemoveMemberChat(BaseConnection):
self.user_id = user_id self.user_id = user_id
self.block = block self.block = block
async def request(self) -> RemovedMemberChat: async def fetch(self) -> RemovedMemberChat:
""" """
Выполняет DELETE-запрос для удаления пользователя из чата. Выполняет DELETE-запрос для удаления пользователя из чата.
@ -54,6 +54,7 @@ class RemoveMemberChat(BaseConnection):
RemovedMemberChat: Результат удаления участника. RemovedMemberChat: Результат удаления участника.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
params['chat_id'] = self.chat_id params['chat_id'] = self.chat_id

View File

@ -1,6 +1,6 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any, Dict, Optional
from ..methods.types.sended_action import SendedAction from ..methods.types.sended_action import SendedAction
@ -34,14 +34,14 @@ class SendAction(BaseConnection):
def __init__( def __init__(
self, self,
bot: 'Bot', bot: 'Bot',
chat_id: int = None, chat_id: Optional[int] = None,
action: SenderAction = SenderAction.TYPING_ON action: SenderAction = SenderAction.TYPING_ON
): ):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
self.action = action self.action = action
async def request(self) -> SendedAction: async def fetch(self) -> SendedAction:
""" """
Выполняет POST-запрос для отправки действия в указанный чат. Выполняет POST-запрос для отправки действия в указанный чат.
@ -49,8 +49,9 @@ class SendAction(BaseConnection):
Returns: Returns:
SendedAction: Результат выполнения запроса. SendedAction: Результат выполнения запроса.
""" """
assert self.bot is not None
json = {} json: Dict[str, Any] = {}
json['action'] = self.action.value json['action'] = self.action.value

View File

@ -1,5 +1,5 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any, Dict, Optional
from ..methods.types.sended_callback import SendedCallback from ..methods.types.sended_callback import SendedCallback
@ -36,15 +36,15 @@ class SendCallback(BaseConnection):
self, self,
bot: 'Bot', bot: 'Bot',
callback_id: str, callback_id: str,
message: Message = None, message: Optional[Message] = None,
notification: str = None notification: Optional[str] = None
): ):
self.bot = bot self.bot = bot
self.callback_id = callback_id self.callback_id = callback_id
self.message = message self.message = message
self.notification = notification self.notification = notification
async def request(self) -> SendedCallback: async def fetch(self) -> SendedCallback:
""" """
Выполняет POST-запрос для отправки callback-ответа. Выполняет POST-запрос для отправки callback-ответа.
@ -55,11 +55,12 @@ class SendCallback(BaseConnection):
SendedCallback: Объект с результатом отправки callback. SendedCallback: Объект с результатом отправки callback.
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
params['callback_id'] = self.callback_id params['callback_id'] = self.callback_id
json = {} json: Dict[str, Any] = {}
if self.message: json['message'] = self.message.model_dump() if self.message: json['message'] = self.message.model_dump()
if self.notification: json['notification'] = self.notification if self.notification: json['notification'] = self.notification

View File

@ -1,10 +1,14 @@
import asyncio import asyncio
from typing import List, TYPE_CHECKING, Optional from typing import Any, Dict, List, TYPE_CHECKING, Optional
from json import loads as json_loads from json import loads as json_loads
from ..utils.message import process_input_media
from ..exceptions.max import MaxUploadFileFailed
from .types.sended_message import SendedMessage from .types.sended_message import SendedMessage
from ..types.attachments.upload import AttachmentPayload, AttachmentUpload from ..types.attachments.upload import AttachmentPayload, AttachmentUpload
from ..types.errors import Error from ..types.errors import Error
@ -39,7 +43,7 @@ class SendMessage(BaseConnection):
chat_id (int, optional): Идентификатор чата, куда отправлять сообщение. chat_id (int, optional): Идентификатор чата, куда отправлять сообщение.
user_id (int, optional): Идентификатор пользователя, если нужно отправить личное сообщение. user_id (int, optional): Идентификатор пользователя, если нужно отправить личное сообщение.
text (str, optional): Текст сообщения. text (str, optional): Текст сообщения.
attachments (List[Attachment | InputMedia], optional): Список вложений к сообщению. attachments (List[Attachment | InputMedia | InputMediaBuffer], optional): Список вложений к сообщению.
link (NewMessageLink, optional): Связь с другим сообщением (например, ответ или пересылка). link (NewMessageLink, optional): Связь с другим сообщением (например, ответ или пересылка).
notify (bool, optional): Отправлять ли уведомление о сообщении. По умолчанию True. notify (bool, optional): Отправлять ли уведомление о сообщении. По умолчанию True.
parse_mode (ParseMode, optional): Режим разбора текста (например, Markdown, HTML). parse_mode (ParseMode, optional): Режим разбора текста (например, Markdown, HTML).
@ -48,12 +52,12 @@ class SendMessage(BaseConnection):
def __init__( def __init__(
self, self,
bot: 'Bot', bot: 'Bot',
chat_id: int = None, chat_id: Optional[int] = None,
user_id: int = None, user_id: Optional[int] = None,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: bool = True, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
): ):
self.bot = bot self.bot = bot
@ -65,59 +69,7 @@ class SendMessage(BaseConnection):
self.notify = notify self.notify = notify
self.parse_mode = parse_mode self.parse_mode = parse_mode
async def __process_input_media( async def fetch(self) -> Optional[SendedMessage | Error]:
self,
att: InputMedia | InputMediaBuffer
):
# очень нестабильный метод независящий от модуля
# ждем обновлений MAX API
"""
Загружает файл вложения и формирует объект AttachmentUpload.
Args:
att (InputMedia): Объект вложения для загрузки.
Returns:
AttachmentUpload: Загруженное вложение с токеном.
"""
upload = await self.bot.get_upload_url(att.type)
if isinstance(att, InputMedia):
upload_file_response = await self.upload_file(
url=upload.url,
path=att.path,
type=att.type,
)
elif isinstance(att, InputMediaBuffer):
upload_file_response = await self.upload_file_buffer(
url=upload.url,
buffer=att.buffer,
type=att.type,
)
if att.type in (UploadType.VIDEO, UploadType.AUDIO):
token = upload.token
elif att.type == UploadType.FILE:
json_r = json_loads(upload_file_response)
token = json_r['token']
elif att.type == UploadType.IMAGE:
json_r = json_loads(upload_file_response)
json_r_keys = list(json_r['photos'].keys())
token = json_r['photos'][json_r_keys[0]]['token']
return AttachmentUpload(
type=att.type,
payload=AttachmentPayload(
token=token
)
)
async def request(self) -> SendedMessage:
""" """
Отправляет сообщение с вложениями (если есть), с обработкой задержки готовности вложений. Отправляет сообщение с вложениями (если есть), с обработкой задержки готовности вложений.
@ -128,9 +80,10 @@ class SendMessage(BaseConnection):
SendedMessage или Error SendedMessage или Error
""" """
assert self.bot is not None
params = self.bot.params.copy() params = self.bot.params.copy()
json = {'attachments': []} json: Dict[str, Any] = {'attachments': []}
if self.chat_id: params['chat_id'] = self.chat_id if self.chat_id: params['chat_id'] = self.chat_id
elif self.user_id: params['user_id'] = self.user_id elif self.user_id: params['user_id'] = self.user_id
@ -142,7 +95,11 @@ class SendMessage(BaseConnection):
for att in self.attachments: for att in self.attachments:
if isinstance(att, InputMedia) or isinstance(att, InputMediaBuffer): if isinstance(att, InputMedia) or isinstance(att, InputMediaBuffer):
input_media = await self.__process_input_media(att) input_media = await process_input_media(
base_connection=self,
bot=self.bot,
att=att
)
json['attachments'].append( json['attachments'].append(
input_media.model_dump() input_media.model_dump()
) )

View File

@ -3,5 +3,5 @@ from pydantic import BaseModel
class GettedUploadUrl(BaseModel): class GettedUploadUrl(BaseModel):
url: Optional[str] = None url: str
token: Optional[str] = None token: Optional[str] = None

View File

@ -32,35 +32,35 @@ from .input_media import InputMedia
from .input_media import InputMediaBuffer from .input_media import InputMediaBuffer
__all__ = [ __all__ = [
CommandStart, 'CommandStart',
OpenAppButton, 'OpenAppButton',
Message, 'Message',
Attachment, 'Attachment',
InputMediaBuffer, 'InputMediaBuffer',
MessageButton, 'MessageButton',
UpdateUnion, 'UpdateUnion',
InputMedia, 'InputMedia',
BotCommand, 'BotCommand',
CallbackButton, 'CallbackButton',
ChatButton, 'ChatButton',
LinkButton, 'LinkButton',
RequestContactButton, 'RequestContactButton',
RequestGeoLocationButton, 'RequestGeoLocationButton',
Command, 'Command',
PhotoAttachmentPayload, 'PhotoAttachmentPayload',
OtherAttachmentPayload, 'OtherAttachmentPayload',
ContactAttachmentPayload, 'ContactAttachmentPayload',
ButtonsPayload, 'ButtonsPayload',
StickerAttachmentPayload, 'StickerAttachmentPayload',
BotAdded, 'BotAdded',
BotRemoved, 'BotRemoved',
BotStarted, 'BotStarted',
ChatTitleChanged, 'ChatTitleChanged',
MessageCallback, 'MessageCallback',
MessageChatCreated, 'MessageChatCreated',
MessageCreated, 'MessageCreated',
MessageEdited, 'MessageEdited',
MessageRemoved, 'MessageRemoved',
UserAdded, 'UserAdded',
UserRemoved 'UserRemoved',
] ]

View File

@ -112,33 +112,33 @@ class Attachment(BaseModel):
bot: Optional[Any] = Field(default=None, exclude=True) bot: Optional[Any] = Field(default=None, exclude=True)
if TYPE_CHECKING: if TYPE_CHECKING:
bot: Optional[Bot] bot: Optional[Bot] # type: ignore
class Config: class Config:
use_enum_values = True use_enum_values = True
async def download( # async def download(
self, # self,
path: str # path: str
): # ):
""" # """
Скачивает медиа, сохраняя по определенному пути # Скачивает медиа, сохраняя по определенному пути
:param path: Путь сохранения медиа # :param path: Путь сохранения медиа
:return: Числовой статус # :return: Числовой статус
""" # """
if not hasattr(self.payload, 'token') or \ # if not hasattr(self.payload, 'token') or \
not hasattr(self.payload, 'url'): # not hasattr(self.payload, 'url'):
raise NotAvailableForDownload() # raise NotAvailableForDownload()
elif not self.payload.token or not self.payload.url: # elif not self.payload.token or not self.payload.url:
raise NotAvailableForDownload(f'Медиа типа `{self.type}` недоступно для скачивания') # raise NotAvailableForDownload(f'Медиа типа `{self.type}` недоступно для скачивания')
return await self.bot.download_file( # return await self.bot.download_file(
path=path, # path=path,
url=self.payload.url, # url=self.payload.url,
token=self.payload.token, # token=self.payload.token,
) # )

View File

@ -1,4 +1,6 @@
from typing import Literal, Optional from typing import Optional
from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
@ -13,5 +15,5 @@ class Audio(Attachment):
transcription (Optional[str]): Транскрипция аудио (если есть). transcription (Optional[str]): Транскрипция аудио (если есть).
""" """
type: Literal['audio'] = 'audio' type: AttachmentType = AttachmentType.AUDIO
transcription: Optional[str] = None transcription: Optional[str] = None

View File

@ -1,4 +1,4 @@
from typing import Literal from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
@ -12,4 +12,4 @@ class Contact(Attachment):
type (Literal['contact']): Тип вложения, всегда 'contact'. type (Literal['contact']): Тип вложения, всегда 'contact'.
""" """
type: Literal['contact'] = 'contact' type: AttachmentType = AttachmentType.CONTACT

View File

@ -1,4 +1,6 @@
from typing import Literal, Optional from typing import Optional
from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
@ -14,6 +16,6 @@ class File(Attachment):
size (Optional[int]): Размер файла в байтах. size (Optional[int]): Размер файла в байтах.
""" """
type: Literal['file'] = 'file' type: AttachmentType = AttachmentType.FILE
filename: Optional[str] = None filename: Optional[str] = None
size: Optional[int] = None size: Optional[int] = None

View File

@ -1,7 +1,9 @@
from typing import Literal, Optional from typing import Optional
from pydantic import BaseModel from pydantic import BaseModel
from .attachment import Attachment from .attachment import Attachment
from ...enums.attachment import AttachmentType
class PhotoAttachmentRequestPayload(BaseModel): class PhotoAttachmentRequestPayload(BaseModel):
@ -29,4 +31,4 @@ class Image(Attachment):
type (Literal['image']): Тип вложения, всегда 'image'. type (Literal['image']): Тип вложения, всегда 'image'.
""" """
type: Literal['image'] = 'image' type: AttachmentType = AttachmentType.IMAGE

View File

@ -1,4 +1,6 @@
from typing import Literal, Optional from typing import Optional
from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
@ -14,6 +16,6 @@ class Location(Attachment):
longitude (Optional[float]): Долгота. longitude (Optional[float]): Долгота.
""" """
type: Literal['location'] = 'location' type: AttachmentType = AttachmentType.LOCATION
latitude: Optional[float] = None latitude: Optional[float] = None
longitude: Optional[float] = None longitude: Optional[float] = None

View File

@ -1,4 +1,6 @@
from typing import Literal, Optional from typing import Optional
from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
@ -15,7 +17,7 @@ class Share(Attachment):
image_url (Optional[str]): URL изображения для предпросмотра. image_url (Optional[str]): URL изображения для предпросмотра.
""" """
type: Literal['share'] = 'share' type: AttachmentType = AttachmentType.SHARE
title: Optional[str] = None title: Optional[str] = None
description: Optional[str] = None description: Optional[str] = None
image_url: Optional[str] = None image_url: Optional[str] = None

View File

@ -1,4 +1,6 @@
from typing import Literal, Optional from typing import Optional
from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
@ -14,6 +16,6 @@ class Sticker(Attachment):
height (Optional[int]): Высота стикера в пикселях. height (Optional[int]): Высота стикера в пикселях.
""" """
type: Literal['sticker'] = 'sticker' type: AttachmentType = AttachmentType.STICKER
width: Optional[int] = None width: Optional[int] = None
height: Optional[int] = None height: Optional[int] = None

View File

@ -1,6 +1,8 @@
from typing import TYPE_CHECKING, Any, Literal, Optional from typing import TYPE_CHECKING, Any, Literal, Optional
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from ...enums.attachment import AttachmentType
from .attachment import Attachment from .attachment import Attachment
if TYPE_CHECKING: if TYPE_CHECKING:
@ -59,7 +61,7 @@ class Video(Attachment):
bot (Optional[Any]): Ссылка на экземпляр бота, не сериализуется. bot (Optional[Any]): Ссылка на экземпляр бота, не сериализуется.
""" """
type: Optional[Literal['video']] = 'video' type: AttachmentType = AttachmentType.VIDEO
token: Optional[str] = None token: Optional[str] = None
urls: Optional[VideoUrl] = None urls: Optional[VideoUrl] = None
thumbnail: VideoThumbnail thumbnail: VideoThumbnail
@ -69,4 +71,4 @@ class Video(Attachment):
bot: Optional[Any] = Field(default=None, exclude=True) bot: Optional[Any] = Field(default=None, exclude=True)
if TYPE_CHECKING: if TYPE_CHECKING:
bot: Optional['Bot'] bot: Optional['Bot'] # type: ignore

View File

@ -70,11 +70,11 @@ class InputMediaBuffer:
Класс для представления медиафайла из буфера. Класс для представления медиафайла из буфера.
Attributes: Attributes:
buffer (BytesIO): Буфер с содержимым файла. buffer (bytes): Буфер с содержимым файла.
type (UploadType): Тип файла, определенный по содержимому. type (UploadType): Тип файла, определенный по содержимому.
""" """
def __init__(self, buffer: BytesIO): def __init__(self, buffer: bytes):
""" """
Инициализирует объект медиафайла из буфера. Инициализирует объект медиафайла из буфера.
@ -84,7 +84,7 @@ class InputMediaBuffer:
self.buffer = buffer self.buffer = buffer
self.type = self.__detect_file_type(buffer) self.type = self.__detect_file_type(buffer)
def __detect_file_type(self, buffer: BytesIO) -> UploadType: def __detect_file_type(self, buffer: bytes) -> UploadType:
try: try:
matches = puremagic.magic_string(buffer) matches = puremagic.magic_string(buffer)
if matches: if matches:

View File

@ -89,7 +89,7 @@ class MessageBody(BaseModel):
mid: str mid: str
seq: int seq: int
text: str = None text: Optional[str] = None
attachments: Optional[ attachments: Optional[
List[ List[
Union[ Union[
@ -103,7 +103,7 @@ class MessageBody(BaseModel):
Location Location
] ]
] ]
] = Field(default_factory=list) ] = Field(default_factory=list) # type: ignore
markup: Optional[ markup: Optional[
List[ List[
@ -111,7 +111,7 @@ class MessageBody(BaseModel):
MarkupLink, MarkupElement MarkupLink, MarkupElement
] ]
] ]
] = Field(default_factory=list) ] = Field(default_factory=list) # type: ignore
class MessageStat(BaseModel): class MessageStat(BaseModel):
@ -164,19 +164,19 @@ class Message(BaseModel):
recipient: Recipient recipient: Recipient
timestamp: int timestamp: int
link: Optional[LinkedMessage] = None link: Optional[LinkedMessage] = None
body: Optional[MessageBody] = None body: MessageBody
stat: Optional[MessageStat] = None stat: Optional[MessageStat] = None
url: Optional[str] = None url: Optional[str] = None
bot: Optional[Any] = Field(default=None, exclude=True) bot: Optional[Any] = Field(default=None, exclude=True)
if TYPE_CHECKING: if TYPE_CHECKING:
bot: Optional[Bot] bot: Optional[Bot] # type: ignore
async def answer( async def answer(
self, self,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
): ):
@ -195,6 +195,7 @@ class Message(BaseModel):
Any: Результат выполнения метода send_message бота. Any: Результат выполнения метода send_message бота.
""" """
assert self.bot is not None
return await self.bot.send_message( return await self.bot.send_message(
chat_id=self.recipient.chat_id, chat_id=self.recipient.chat_id,
user_id=self.recipient.user_id, user_id=self.recipient.user_id,
@ -207,8 +208,8 @@ class Message(BaseModel):
async def reply( async def reply(
self, self,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
): ):
@ -226,6 +227,7 @@ class Message(BaseModel):
Any: Результат выполнения метода send_message бота. Any: Результат выполнения метода send_message бота.
""" """
assert self.bot is not None
return await self.bot.send_message( return await self.bot.send_message(
chat_id=self.recipient.chat_id, chat_id=self.recipient.chat_id,
user_id=self.recipient.user_id, user_id=self.recipient.user_id,
@ -242,8 +244,8 @@ class Message(BaseModel):
async def forward( async def forward(
self, self,
chat_id, chat_id,
user_id: int = None, user_id: Optional[int] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
notify: Optional[bool] = None, notify: Optional[bool] = None,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
): ):
@ -262,6 +264,7 @@ class Message(BaseModel):
Any: Результат выполнения метода send_message бота. Any: Результат выполнения метода send_message бота.
""" """
assert self.bot is not None
return await self.bot.send_message( return await self.bot.send_message(
chat_id=chat_id, chat_id=chat_id,
user_id=user_id, user_id=user_id,
@ -276,9 +279,9 @@ class Message(BaseModel):
async def edit( async def edit(
self, self,
text: str = None, text: Optional[str] = None,
attachments: List[Attachment | InputMedia | InputMediaBuffer] = None, attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: bool = True, notify: bool = True,
parse_mode: Optional[ParseMode] = None parse_mode: Optional[ParseMode] = None
): ):
@ -297,6 +300,7 @@ class Message(BaseModel):
Any: Результат выполнения метода edit_message бота. Any: Результат выполнения метода edit_message бота.
""" """
assert self.bot is not None
return await self.bot.edit_message( return await self.bot.edit_message(
message_id=self.body.mid, message_id=self.body.mid,
text=text, text=text,
@ -331,6 +335,7 @@ class Message(BaseModel):
Any: Результат выполнения метода pin_message бота. Any: Результат выполнения метода pin_message бота.
""" """
assert self.bot is not None
return await self.bot.pin_message( return await self.bot.pin_message(
chat_id=self.recipient.chat_id, chat_id=self.recipient.chat_id,
message_id=self.body.mid, message_id=self.body.mid,
@ -352,7 +357,7 @@ class Messages(BaseModel):
bot: Optional[Any] = Field(default=None, exclude=True) bot: Optional[Any] = Field(default=None, exclude=True)
if TYPE_CHECKING: if TYPE_CHECKING:
bot: Optional[Bot] bot: Optional[Bot] # type: ignore
class NewMessageLink(BaseModel): class NewMessageLink(BaseModel):

View File

@ -2,6 +2,8 @@ from typing import List, Optional, TYPE_CHECKING, Union
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from ...types.attachments.location import Location
from .update import Update from .update import Update
from ...enums.parse_mode import ParseMode from ...enums.parse_mode import ParseMode
@ -49,10 +51,11 @@ class MessageForCallback(BaseModel):
File, File,
Image, Image,
Sticker, Sticker,
Share Share,
Location
] ]
] ]
] = Field(default_factory=list) ] = Field(default_factory=list) # type: ignore
link: Optional[NewMessageLink] = None link: Optional[NewMessageLink] = None
notify: Optional[bool] = True notify: Optional[bool] = True
format: Optional[ParseMode] = None format: Optional[ParseMode] = None
@ -86,9 +89,9 @@ class MessageCallback(Update):
async def answer( async def answer(
self, self,
notification: str = None, notification: Optional[str] = None,
new_text: str = None, new_text: Optional[str] = None,
link: NewMessageLink = None, link: Optional[NewMessageLink] = None,
notify: bool = True, notify: bool = True,
format: Optional[ParseMode] = None, format: Optional[ParseMode] = None,
): ):
@ -115,6 +118,7 @@ class MessageCallback(Update):
message.notify = notify message.notify = notify
message.format = format message.format = format
assert self.bot is not None
return await self.bot.send_callback( return await self.bot.send_callback(
callback_id=self.callback.callback_id, callback_id=self.callback.callback_id,
message=message, message=message,

72
maxapi/utils/message.py Normal file
View File

@ -0,0 +1,72 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from json import loads
from ..types.input_media import InputMedia, InputMediaBuffer
from ..enums.upload_type import UploadType
from ..exceptions.max import MaxUploadFileFailed
from ..types.attachments.upload import AttachmentPayload, AttachmentUpload
if TYPE_CHECKING:
from ..bot import Bot
from ..connection.base import BaseConnection
async def process_input_media(
base_connection: BaseConnection,
bot: Bot,
att: InputMedia | InputMediaBuffer
):
# очень нестабильный метод независящий от модуля
# ждем обновлений MAX API
"""
Загружает файл вложения и формирует объект AttachmentUpload.
Args:
att (InputMedia): Объект вложения для загрузки.
Returns:
AttachmentUpload: Загруженное вложение с токеном.
"""
upload = await bot.get_upload_url(att.type)
if isinstance(att, InputMedia):
upload_file_response = await base_connection.upload_file(
url=upload.url,
path=att.path,
type=att.type,
)
elif isinstance(att, InputMediaBuffer):
upload_file_response = await base_connection.upload_file_buffer(
url=upload.url,
buffer=att.buffer,
type=att.type,
)
if att.type in (UploadType.VIDEO, UploadType.AUDIO):
if upload.token is None:
assert bot.session is not None
await bot.session.close()
raise MaxUploadFileFailed('По неизвестной причине token не был получен')
token = upload.token
elif att.type == UploadType.FILE:
json_r = loads(upload_file_response)
token = json_r['token']
elif att.type == UploadType.IMAGE:
json_r = loads(upload_file_response)
json_r_keys = list(json_r['photos'].keys())
token = json_r['photos'][json_r_keys[0]]['token']
return AttachmentUpload(
type=att.type,
payload=AttachmentPayload(
token=token
)
)

View File

@ -46,7 +46,7 @@ MemoryContext(chat_id: int, user_id: int)
--- ---
### `async def set_state(state: State | str = None)` ### `async def set_state(state: Optional[Union[State, str]] = None)`
Устанавливает новое состояние пользователя или сбрасывает его. Устанавливает новое состояние пользователя или сбрасывает его.