diff --git a/maxapi/bot.py b/maxapi/bot.py index 71f0f62..c25419f 100644 --- a/maxapi/bot.py +++ b/maxapi/bot.py @@ -23,7 +23,6 @@ from .methods.delete_bot_from_chat import DeleteMeFromMessage from .methods.delete_chat import DeleteChat from .methods.delete_message import DeleteMessage from .methods.delete_pin_message import DeletePinMessage -# from .methods.download_media import DownloadMedia from .methods.edit_chat import EditChat from .methods.edit_message import EditMessage from .methods.get_chat_by_id import GetChatById @@ -81,38 +80,40 @@ if TYPE_CHECKING: class Bot(BaseConnection): - - """Основной класс для работы с API бота. + + """ + Основной класс для работы с API бота. Предоставляет методы для взаимодействия с чатами, сообщениями, пользователями и другими функциями бота. """ def __init__( - self, - token: str, - parse_mode: Optional[ParseMode] = None, - notify: Optional[bool] = None, - auto_requests: bool = True, - default_connection: Optional[DefaultConnectionProperties] = None, - after_input_media_delay: Optional[float] = None, - auto_check_subscriptions: bool = True - ): - - """ - Инициализирует экземпляр бота с указанным токеном. + self, + token: str, + parse_mode: Optional[ParseMode] = None, + notify: Optional[bool] = None, + auto_requests: bool = True, + default_connection: Optional[DefaultConnectionProperties] = None, + after_input_media_delay: Optional[float] = None, + auto_check_subscriptions: bool = True + ): - :param token: Токен доступа к API бота - :param parse_mode: Форматирование по умолчанию - :param notify: Отключение уведомлений при отправке сообщений (по умолчанию игнорируется) (не работает на стороне MAX) - :param auto_requests: Автоматическое заполнение полей chat и from_user в Update с помощью API запросов если они не заложены как полноценные объекты в Update (по умолчанию True, при False chat и from_user в некоторых событиях будут выдавать None) - :param default_connection: Настройки aiohttp - :param after_input_media_delay: Задержка в секундах после загрузки файла на сервера MAX (без этого чаще всего MAX не успевает обработать вложение и выдает ошибку `errors.process.attachment.file.not.processed`) - :param auto_check_subscriptions: Проверка на установленные подписки для метода start_polling (бот не работает в поллинге при установленных подписках) """ - + Инициализирует экземпляр бота. + + Args: + token (str): Токен доступа к API бота. + parse_mode (Optional[ParseMode]): Форматирование по умолчанию. + notify (Optional[bool]): Отключение уведомлений при отправке сообщений. + auto_requests (bool): Автоматическое заполнение chat/from_user через API (по умолчанию True). + default_connection (Optional[DefaultConnectionProperties]): Настройки соединения. + after_input_media_delay (Optional[float]): Задержка после загрузки файла. + auto_check_subscriptions (bool): Проверка подписок для метода start_polling. + + """ + super().__init__() - self.bot = self self.default_connection = default_connection or DefaultConnectionProperties() self.after_input_media_delay = after_input_media_delay or 2.0 @@ -121,52 +122,92 @@ class Bot(BaseConnection): self.__token = token self.params: Dict[str, Any] = {'access_token': self.__token} self.marker_updates = None - + self.parse_mode = parse_mode self.notify = notify self.auto_requests = auto_requests - + self._me: User | None = None - + @property def me(self): + + """ + Возвращает объект пользователя (бота). + + Returns: + User | None: Объект пользователя или None. + """ + return self._me - + def _resolve_notify(self, notify: Optional[bool]) -> Optional[bool]: + + """ + Определяет флаг уведомления. + + Args: + notify (Optional[bool]): Локальный флаг. + + Returns: + Optional[bool]: Итоговый флаг. + """ + return notify if notify is not None else self.notify def _resolve_parse_mode(self, mode: Optional[ParseMode]) -> Optional[ParseMode]: + + """ + Определяет режим форматирования. + + Args: + mode (Optional[ParseMode]): Локальный режим. + + Returns: + Optional[ParseMode]: Итоговый режим. + """ + return mode if mode is not None else self.parse_mode - + async def close_session(self) -> None: + + """ + Закрывает текущую сессию aiohttp. + + Returns: + None + """ + if self.session is not None: await self.session.close() - + async def send_message( - self, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - text: Optional[str] = None, - attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None, - link: Optional[NewMessageLink] = None, - notify: Optional[bool] = None, - parse_mode: Optional[ParseMode] = None - ) -> Optional[SendedMessage | Error]: - + self, + chat_id: Optional[int] = None, + user_id: Optional[int] = None, + text: Optional[str] = None, + attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None, + link: Optional[NewMessageLink] = None, + notify: Optional[bool] = None, + parse_mode: Optional[ParseMode] = None + ) -> Optional[SendedMessage | Error]: + """ Отправляет сообщение в чат или пользователю. - :param chat_id: ID чата для отправки (обязателен, если не указан user_id) - :param user_id: ID пользователя для отправки (обязателен, если не указан chat_id) - :param text: Текст сообщения - :param attachments: Список вложений к сообщению - :param link: Данные ссылки сообщения - :param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота) - :param parse_mode: Режим форматирования текста + Args: + chat_id (Optional[int]): ID чата для отправки (если не user_id). + user_id (Optional[int]): ID пользователя (если не chat_id). + text (Optional[str]): Текст сообщения. + attachments (Optional[List[Attachment | InputMedia | InputMediaBuffer]]): Вложения. + link (Optional[NewMessageLink]): Данные ссылки сообщения. + notify (Optional[bool]): Флаг уведомления. + parse_mode (Optional[ParseMode]): Режим форматирования текста. - :return: Объект отправленного сообщения + Returns: + Optional[SendedMessage | Error]: Отправленное сообщение или ошибка. """ - + return await SendMessage( bot=self, chat_id=chat_id, @@ -177,51 +218,55 @@ class Bot(BaseConnection): notify=self._resolve_notify(notify), parse_mode=self._resolve_parse_mode(parse_mode) ).fetch() - + async def send_action( - self, - chat_id: Optional[int] = None, - action: SenderAction = SenderAction.TYPING_ON - ) -> SendedAction: - + self, + chat_id: Optional[int] = None, + action: SenderAction = SenderAction.TYPING_ON + ) -> SendedAction: + """ Отправляет действие в чат (например, "печатает"). - :param chat_id: ID чата для отправки действия - :param action: Тип действия (по умолчанию SenderAction.TYPING_ON) + Args: + chat_id (Optional[int]): ID чата. + action (SenderAction): Тип действия. - :return: Результат отправки действия + Returns: + SendedAction: Результат отправки действия. """ - + return await SendAction( bot=self, chat_id=chat_id, action=action ).fetch() - + async def edit_message( - self, - message_id: str, - text: Optional[str] = None, - attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None, - link: Optional[NewMessageLink] = None, - notify: Optional[bool] = None, - parse_mode: Optional[ParseMode] = None - ) -> Optional[EditedMessage | Error]: - + self, + message_id: str, + text: Optional[str] = None, + attachments: Optional[List[Attachment | InputMedia | InputMediaBuffer]] = None, + link: Optional[NewMessageLink] = None, + notify: Optional[bool] = None, + parse_mode: Optional[ParseMode] = None + ) -> Optional[EditedMessage | Error]: + """ Редактирует существующее сообщение. - :param message_id: ID сообщения для редактирования - :param text: Новый текст сообщения - :param attachments: Новые вложения - :param link: Новая ссылка сообщения - :param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота) - :param parse_mode: Режим форматирования текста + Args: + message_id (str): ID сообщения. + text (Optional[str]): Новый текст. + attachments (Optional[List[Attachment | InputMedia | InputMediaBuffer]]): Новые вложения. + link (Optional[NewMessageLink]): Новая ссылка. + notify (Optional[bool]): Флаг уведомления. + parse_mode (Optional[ParseMode]): Режим форматирования текста. - :return: Объект отредактированного сообщения + Returns: + Optional[EditedMessage | Error]: Отредактированное сообщение или ошибка. """ - + return await EditMessage( bot=self, message_id=message_id, @@ -231,64 +276,70 @@ class Bot(BaseConnection): notify=self._resolve_notify(notify), parse_mode=self._resolve_parse_mode(parse_mode) ).fetch() - + async def delete_message( - self, - message_id: str - ) -> DeletedMessage: - + self, + message_id: str + ) -> DeletedMessage: + """ Удаляет сообщение. - :param message_id: ID сообщения для удаления + Args: + message_id (str): ID сообщения. - :return: Результат удаления сообщения + Returns: + DeletedMessage: Результат удаления. """ - + return await DeleteMessage( bot=self, message_id=message_id, ).fetch() - + async def delete_chat( - self, - chat_id: int - ) -> DeletedChat: - + self, + chat_id: int + ) -> DeletedChat: + """ Удаляет чат. - :param chat_id: ID чата для удаления + Args: + chat_id (int): ID чата. - :return: Результат удаления чата + Returns: + DeletedChat: Результат удаления чата. """ - + return await DeleteChat( bot=self, chat_id=chat_id, ).fetch() async def get_messages( - self, - chat_id: Optional[int] = None, - message_ids: Optional[List[str]] = None, - from_time: Optional[Union[datetime, int]] = None, - to_time: Optional[Union[datetime, int]] = None, - count: int = 50, - ) -> Messages: - + self, + chat_id: Optional[int] = None, + message_ids: Optional[List[str]] = None, + from_time: Optional[Union[datetime, int]] = None, + to_time: Optional[Union[datetime, int]] = None, + count: int = 50, + ) -> Messages: + """ Получает сообщения из чата. - :param chat_id: ID чата (обязателен, если не указаны message_ids) - :param message_ids: Список ID сообщений для получения - :param from_time: Время начала периода (datetime или timestamp) - :param to_time: Время конца периода (datetime или timestamp) - :param count: Количество сообщений (по умолчанию 50) + Args: + chat_id (Optional[int]): ID чата. + message_ids (Optional[List[str]]): ID сообщений. + from_time (Optional[datetime | int]): Начало периода. + to_time (Optional[datetime | int]): Конец периода. + count (int): Количество сообщений. - :return: Список сообщений + Returns: + Messages: Список сообщений. """ - + return await GetMessages( bot=self, chat_id=chat_id, @@ -297,71 +348,77 @@ class Bot(BaseConnection): to_time=to_time, count=count ).fetch() - + async def get_message( - self, - message_id: str - ) -> Message: - + self, + message_id: str + ) -> Message: + """ Получает одно сообщение по ID. - :param message_id: ID сообщения + Args: + message_id (str): ID сообщения. - :return: Объект сообщения + Returns: + Message: Объект сообщения. """ - + return await GetMessage( bot=self, message_id=message_id ).fetch() async def get_me(self) -> User: - + """ - https://dev.max.ru/docs-api/methods/GET/me\n Получает информацию о текущем боте. - :return: Объект пользователя бота + Returns: + User: Объект пользователя бота. """ - + return await GetMe(self).fetch() - + async def get_pin_message( - self, - chat_id: int - ) -> GettedPin: - + self, + chat_id: int + ) -> GettedPin: + """ Получает закрепленное сообщение в чате. - :param chat_id: ID чата + Args: + chat_id (int): ID чата. - :return: Закрепленное сообщение + Returns: + GettedPin: Закрепленное сообщение. """ - + return await GetPinnedMessage( bot=self, chat_id=chat_id ).fetch() - + async def change_info( - self, - name: Optional[str] = None, - description: Optional[str] = None, - commands: Optional[List[BotCommand]] = None, - photo: Optional[PhotoAttachmentRequestPayload] = None - ) -> User: - + self, + name: Optional[str] = None, + description: Optional[str] = None, + commands: Optional[List[BotCommand]] = None, + photo: Optional[PhotoAttachmentRequestPayload] = None + ) -> User: + """ Изменяет информацию о боте. - :param name: Новое имя бота - :param description: Новое описание бота - :param commands: Список команд бота - :param photo: Данные фотографии бота + Args: + name (Optional[str]): Новое имя бота. + description (Optional[str]): Новое описание. + commands (Optional[List[BotCommand]]): Команды бота. + photo (Optional[PhotoAttachmentRequestPayload]): Фото бота. - :return: Обновленная информация о боте + Returns: + User: Обновленная информация о боте. """ return await ChangeInfo( @@ -371,79 +428,87 @@ class Bot(BaseConnection): commands=commands, photo=photo ).fetch() - + async def get_chats( - self, - count: int = 50, - marker: Optional[int] = None - ) -> Chats: - + self, + count: int = 50, + marker: Optional[int] = None + ) -> Chats: + """ Получает список чатов бота. - :param count: Количество чатов (по умолчанию 50) - :param marker: Маркер для пагинации + Args: + count (int): Количество чатов (по умолчанию 50). + marker (Optional[int]): Маркер для пагинации. - :return: Список чатов + Returns: + Chats: Список чатов. """ - + return await GetChats( bot=self, count=count, marker=marker ).fetch() - + async def get_chat_by_link( - self, - link: str - ) -> Chat: - + self, + link: str + ) -> Chat: + """ Получает чат по ссылке. - :param link: Ссылка на чат + Args: + link (str): Ссылка на чат. - :return: Объект чата + Returns: + Chat: Объект чата. """ - + return await GetChatByLink(bot=self, link=link).fetch() - + async def get_chat_by_id( - self, - id: int - ) -> Chat: - + self, + id: int + ) -> Chat: + """ Получает чат по ID. - :param id: ID чата + Args: + id (int): ID чата. - :return: Объект чата + Returns: + Chat: Объект чата. """ - + return await GetChatById(bot=self, id=id).fetch() - + async def edit_chat( - self, - chat_id: int, - icon: Optional[PhotoAttachmentRequestPayload] = None, - title: Optional[str] = None, - pin: Optional[str] = None, - notify: Optional[bool] = None, - ) -> Chat: - + self, + chat_id: int, + icon: Optional[PhotoAttachmentRequestPayload] = None, + title: Optional[str] = None, + pin: Optional[str] = None, + notify: Optional[bool] = None, + ) -> Chat: + """ Редактирует параметры чата. - :param chat_id: ID чата - :param icon: Данные иконки чата - :param title: Новый заголовок чата - :param pin: ID сообщения для закрепления - :param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота) + Args: + chat_id (int): ID чата. + icon (Optional[PhotoAttachmentRequestPayload]): Иконка. + title (Optional[str]): Новый заголовок. + pin (Optional[str]): ID сообщения для закрепления. + notify (Optional[bool]): Флаг уведомления. - :return: Обновленный объект чата + Returns: + Chat: Обновленный объект чата. """ - + return await EditChat( bot=self, chat_id=chat_id, @@ -452,209 +517,229 @@ class Bot(BaseConnection): pin=pin, notify=self._resolve_notify(notify), ).fetch() - + async def get_video( - self, - video_token: str - ) -> Video: - + self, + video_token: str + ) -> Video: + """ Получает видео по токену. - :param video_token: Токен видео + Args: + video_token (str): Токен видео. - :return: Объект видео + Returns: + Video: Объект видео. """ - + return await GetVideo( bot=self, video_token=video_token ).fetch() async def send_callback( - self, - callback_id: str, - message: Optional[Message] = None, - notification: Optional[str] = None - ) -> SendedCallback: - + self, + callback_id: str, + message: Optional[Message] = None, + notification: Optional[str] = None + ) -> SendedCallback: + """ Отправляет callback ответ. - :param callback_id: ID callback - :param message: Сообщение для отправки - :param notification: Текст уведомления + Args: + callback_id (str): ID callback. + message (Optional[Message]): Сообщение для отправки. + notification (Optional[str]): Текст уведомления. - :return: Результат отправки callback + Returns: + SendedCallback: Результат отправки callback. """ - + return await SendCallback( bot=self, callback_id=callback_id, message=message, notification=notification ).fetch() - + async def pin_message( - self, - chat_id: int, - message_id: str, - notify: Optional[bool] = None - ) -> PinnedMessage: - + self, + chat_id: int, + message_id: str, + notify: Optional[bool] = None + ) -> PinnedMessage: + """ Закрепляет сообщение в чате. - :param chat_id: ID чата - :param message_id: ID сообщения - :param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота) + Args: + chat_id (int): ID чата. + message_id (str): ID сообщения. + notify (Optional[bool]): Флаг уведомления. - :return: Закрепленное сообщение + Returns: + PinnedMessage: Закрепленное сообщение. """ - + return await PinMessage( bot=self, chat_id=chat_id, message_id=message_id, notify=self._resolve_notify(notify), ).fetch() - + async def delete_pin_message( - self, - chat_id: int, - ) -> DeletedPinMessage: - + self, + chat_id: int, + ) -> DeletedPinMessage: + """ Удаляет закрепленное сообщение в чате. - :param chat_id: ID чата + Args: + chat_id (int): ID чата. - :return: Результат удаления + Returns: + DeletedPinMessage: Результат удаления. """ - + return await DeletePinMessage( bot=self, chat_id=chat_id, ).fetch() - + async def get_me_from_chat( - self, - chat_id: int, - ) -> ChatMember: - - """ - Получает информацию о боте в конкретном чате. + self, + chat_id: int, + ) -> ChatMember: - :param chat_id: ID чата - - :return: Информация о боте в чате """ - + Получает информацию о боте в чате. + + Args: + chat_id (int): ID чата. + + Returns: + ChatMember: Информация о боте в чате. + """ + return await GetMeFromChat( bot=self, chat_id=chat_id, ).fetch() - + async def delete_me_from_chat( - self, - chat_id: int, - ) -> DeletedBotFromChat: - + self, + chat_id: int, + ) -> DeletedBotFromChat: + """ Удаляет бота из чата. - :param chat_id: ID чата + Args: + chat_id (int): ID чата. - :return: Результат удаления + Returns: + DeletedBotFromChat: Результат удаления. """ - + return await DeleteMeFromMessage( bot=self, chat_id=chat_id, ).fetch() - + async def get_list_admin_chat( - self, - chat_id: int, - ) -> GettedListAdminChat: - + self, + chat_id: int, + ) -> GettedListAdminChat: + """ Получает список администраторов чата. - :param chat_id: ID чата + Args: + chat_id (int): ID чата. - :return: Список администраторов + Returns: + GettedListAdminChat: Список администраторов. """ - + return await GetListAdminChat( bot=self, chat_id=chat_id, ).fetch() - + async def add_list_admin_chat( - self, - chat_id: int, - admins: List[ChatAdmin], - marker: Optional[int] = None - ) -> AddedListAdminChat: - + self, + chat_id: int, + admins: List[ChatAdmin], + marker: Optional[int] = None + ) -> AddedListAdminChat: + """ Добавляет администраторов в чат. - :param chat_id: ID чата - :param admins: Список администраторов - :param marker: Маркер для пагинации + Args: + chat_id (int): ID чата. + admins (List[ChatAdmin]): Список администраторов. + marker (Optional[int]): Маркер для пагинации. - :return: Результат добавления + Returns: + AddedListAdminChat: Результат добавления. """ - + return await AddAdminChat( bot=self, chat_id=chat_id, admins=admins, marker=marker, ).fetch() - + async def remove_admin( - self, - chat_id: int, - user_id: int - ) -> RemovedAdmin: - + self, + chat_id: int, + user_id: int + ) -> RemovedAdmin: + """ Удаляет администратора из чата. - :param chat_id: ID чата - :param user_id: ID пользователя + Args: + chat_id (int): ID чата. + user_id (int): ID пользователя. - :return: Результат удаления + Returns: + RemovedAdmin: Результат удаления. """ - + return await RemoveAdmin( bot=self, chat_id=chat_id, user_id=user_id, ).fetch() - + async def get_chat_members( - self, - chat_id: int, - user_ids: Optional[List[int]] = None, - marker: Optional[int] = None, - count: Optional[int] = None, - ) -> GettedMembersChat: - + self, + chat_id: int, + user_ids: Optional[List[int]] = None, + marker: Optional[int] = None, + count: Optional[int] = None, + ) -> GettedMembersChat: + """ Получает участников чата. - :param chat_id: ID чата - :param user_ids: Список ID участников - :param marker: Маркер для пагинации - :param count: Количество участников + Args: + chat_id (int): ID чата. + user_ids (Optional[List[int]]): Список ID участников. + marker (Optional[int]): Маркер для пагинации. + count (Optional[int]): Количество участников. - :return: Список участников + Returns: + GettedMembersChat: Список участников. """ - + return await GetMembersChat( bot=self, chat_id=chat_id, @@ -662,192 +747,204 @@ class Bot(BaseConnection): marker=marker, count=count, ).fetch() - + async def get_chat_member( - self, - chat_id: int, - user_id: int, - ) -> Optional[ChatMember]: - + self, + chat_id: int, + user_id: int, + ) -> Optional[ChatMember]: + """ Получает участника чата. - :param chat_id: ID чата - :param user_id: ID участника + Args: + chat_id (int): ID чата. + user_id (int): ID участника. - :return: Участник + Returns: + Optional[ChatMember]: Участник. """ - + members = await self.get_chat_members( chat_id=chat_id, user_ids=[user_id] ) - + if members.members: return members.members[0] return None - + async def add_chat_members( - self, - chat_id: int, - user_ids: List[int], - ) -> AddedMembersChat: - + self, + chat_id: int, + user_ids: List[int], + ) -> AddedMembersChat: + """ Добавляет участников в чат. - :param chat_id: ID чата - :param user_ids: Список ID пользователей + Args: + chat_id (int): ID чата. + user_ids (List[int]): Список ID пользователей. - :return: Результат добавления + Returns: + AddedMembersChat: Результат добавления. """ - + return await AddMembersChat( bot=self, chat_id=chat_id, user_ids=user_ids, ).fetch() - + async def kick_chat_member( - self, - chat_id: int, - user_id: int, - block: bool = False, - ) -> RemovedMemberChat: - + self, + chat_id: int, + user_id: int, + block: bool = False, + ) -> RemovedMemberChat: + """ Исключает участника из чата. - :param chat_id: ID чата - :param user_id: ID пользователя - :param block: Блокировать пользователя (по умолчанию False) + Args: + chat_id (int): ID чата. + user_id (int): ID пользователя. + block (bool): Блокировать пользователя (по умолчанию False). - :return: Результат исключения + Returns: + RemovedMemberChat: Результат исключения. """ - + return await RemoveMemberChat( bot=self, chat_id=chat_id, user_id=user_id, block=block, ).fetch() - + async def get_updates( - self, - ) -> Dict: - + self, + ) -> Dict: + """ Получает обновления для бота. - :return: Список обновлений + Returns: + Dict: Список обновлений. """ - + return await GetUpdates( bot=self, ).fetch() - + async def get_upload_url( - self, - type: UploadType - ) -> GettedUploadUrl: - + self, + type: UploadType + ) -> GettedUploadUrl: + """ Получает URL для загрузки файлов. - :param type: Тип загружаемого файла + Args: + type (UploadType): Тип загружаемого файла. - :return: URL для загрузки + Returns: + GettedUploadUrl: URL для загрузки. """ - + return await GetUploadURL( bot=self, type=type ).fetch() - + async def set_my_commands( - self, - *commands: BotCommand - ) -> User: - + self, + *commands: BotCommand + ) -> User: + """ Устанавливает список команд бота. - :param commands: Список команд + Args: + *commands (BotCommand): Список команд. - :return: Обновленная информация о боте + Returns: + User: Обновленная информация о боте. """ - + return await ChangeInfo( bot=self, commands=list(commands) ).fetch() - + async def get_subscriptions(self) -> GettedSubscriptions: - + """ Получает список всех подписок. - :return: Объект со списком подписок + Returns: + GettedSubscriptions: Объект со списком подписок. """ - + return await GetSubscriptions(bot=self).fetch() - + async def subscribe_webhook( - self, - url: str, - update_types: Optional[List[UpdateType]] = None, - secret: Optional[str] = None - ) -> Subscribed: - - """ - Подписывает бота на получение обновлений через WebHook. - После вызова этого метода бот будет получать уведомления о новых событиях в чатах на указанный URL. - Ваш сервер должен прослушивать один из следующих портов: `80`, `8080`, `443`, `8443`, `16384`-`32383`. + self, + url: str, + update_types: Optional[List[UpdateType]] = None, + secret: Optional[str] = None + ) -> Subscribed: - :param url: URL HTTP(S)-эндпойнта вашего бота. Должен начинаться с http(s):// - :param update_types: Список типов обновлений, которые ваш бот хочет получать. - Для полного списка типов см. объект - :param secret: От 5 до 256 символов. Cекрет, который должен быть отправлен в заголовке X-Max-Bot-Api-Secret - в каждом запросе Webhook. Разрешены только символы A-Z, a-z, 0-9, и дефис. - Заголовок рекомендован, чтобы запрос поступал из установленного веб-узла - - :return: Обновленная информация о боте """ - + Подписывает бота на получение обновлений через WebHook. + + Args: + url (str): URL HTTP(S)-эндпойнта вашего бота. + update_types (Optional[List[UpdateType]]): Список типов обновлений. + secret (Optional[str]): Секрет для Webhook. + + Returns: + Subscribed: Результат подписки. + """ + return await SubscribeWebhook( bot=self, url=url, update_types=update_types, secret=secret ).fetch() - + async def unsubscribe_webhook( - self, - url: str, - ) -> Unsubscribed: - - """ - Отписывает бота от получения обновлений через WebHook. - После вызова этого метода бот перестает получать уведомления о новых событиях, - и доступна доставка уведомлений через API с длительным опросом. + self, + url: str, + ) -> Unsubscribed: - :param url: URL HTTP(S)-эндпойнта вашего бота. Должен начинаться с http(s):// - - :return: Обновленная информация о боте """ - + Отписывает бота от получения обновлений через WebHook. + + Args: + url (str): URL HTTP(S)-эндпойнта вашего бота. + + Returns: + Unsubscribed: Результат отписки. + """ + return await UnsubscribeWebhook( bot=self, url=url, ).fetch() - + async def delete_webhook(self): - + """ - Удаление всех подписок на Webhook + Удаляет все подписки на Webhook. + + Returns: + None """ - + subs = await self.get_subscriptions() if subs.subscriptions: @@ -855,28 +952,3 @@ class Bot(BaseConnection): await self.unsubscribe_webhook(sub.url) logger_bot.info('Удалена подписка на Webhook: %s', sub.url) - - - # async def download_file( - # self, - # path: str, - # url: str, - # token: str - # ): - - # """ - # Скачивает медиа с указанной ссылки по токену, сохраняя по определенному пути - - # :param path: Путь сохранения медиа - # :param url: Ссылка на медиа - # :param token: Токен медиа - - # :return: Числовой статус - # """ - - # return await DownloadMedia( - # bot=self, - # path=path, - # media_url=url, - # media_token=token - # ).fetch() \ No newline at end of file diff --git a/maxapi/client/default.py b/maxapi/client/default.py index 7c5dfea..9a8fdb6 100644 --- a/maxapi/client/default.py +++ b/maxapi/client/default.py @@ -1,10 +1,27 @@ - - from aiohttp import ClientTimeout - class DefaultConnectionProperties: - + ''' + Класс для хранения параметров соединения по умолчанию для aiohttp-клиента. + + Args: + timeout (int): Таймаут всего соединения в секундах (по умолчанию 5 * 30). + sock_connect (int): Таймаут установки TCP-соединения в секундах (по умолчанию 30). + **kwargs: Дополнительные параметры, которые будут сохранены как есть. + + Attributes: + timeout (ClientTimeout): Экземпляр aiohttp.ClientTimeout с заданными параметрами. + kwargs (dict): Дополнительные параметры. + ''' + def __init__(self, timeout: int = 5 * 30, sock_connect: int = 30, **kwargs): + ''' + Инициализация параметров соединения. + + Args: + timeout (int): Таймаут всего соединения в секундах. + sock_connect (int): Таймаут установки TCP-соединения в секундах. + **kwargs: Дополнительные параметры. + ''' self.timeout = ClientTimeout(total=timeout, sock_connect=sock_connect) - self.kwargs = kwargs \ No newline at end of file + self.kwargs = kwargs diff --git a/maxapi/connection/base.py b/maxapi/connection/base.py index 0e25d30..a3928ed 100644 --- a/maxapi/connection/base.py +++ b/maxapi/connection/base.py @@ -30,9 +30,7 @@ class BaseConnection: """ Базовый класс для всех методов API. - Содержит общую логику выполнения запроса (например, сериализацию, отправку HTTP-запроса, обработку ответа). - - Метод request() может быть переопределён в потомках при необходимости. + Содержит общую логику выполнения запроса (сериализация, отправка HTTP-запроса, обработка ответа). """ API_URL = 'https://botapi.max.ru' @@ -41,53 +39,67 @@ class BaseConnection: AFTER_MEDIA_INPUT_DELAY = 2.0 def __init__(self) -> None: + + """ + Инициализация BaseConnection. + + Атрибуты: + bot (Optional[Bot]): Экземпляр бота. + session (Optional[ClientSession]): aiohttp-сессия. + after_input_media_delay (float): Задержка после ввода медиа. + """ + self.bot: Optional[Bot] = None self.session: Optional[ClientSession] = None self.after_input_media_delay: float = self.AFTER_MEDIA_INPUT_DELAY async def request( - self, - method: HTTPMethod, - path: ApiPath | str, - model: BaseModel | Any = None, - is_return_raw: bool = False, - **kwargs - ): + self, + method: HTTPMethod, + path: ApiPath | str, + model: BaseModel | Any = None, + is_return_raw: bool = False, + **kwargs + ): """ - Выполняет HTTP-запрос к API, используя указанные параметры. + Выполняет HTTP-запрос к API. - :param method: HTTP-метод запроса (GET, POST и т.д.) - :param path: Путь к конечной точке API - :param model: Pydantic-модель, в которую будет десериализован ответ (если is_return_raw=False) - :param is_return_raw: Если True — вернуть "сырое" тело ответа, иначе — результат десериализации в model - :param kwargs: Дополнительные параметры (например, query, headers, json) + Args: + method (HTTPMethod): HTTP-метод (GET, POST и т.д.). + path (ApiPath | str): Путь до конечной точки. + model (BaseModel | Any, optional): Pydantic-модель для десериализации ответа, если is_return_raw=False. + is_return_raw (bool, optional): Если True — вернуть сырой ответ, иначе — результат десериализации. + **kwargs: Дополнительные параметры (query, headers, json). - :return: - - Объект model (если is_return_raw=False и model задан) - - - dict (если is_return_raw=True) + Returns: + model | dict | Error: Объект модели, dict или ошибка. + + Raises: + RuntimeError: Если бот не инициализирован. + MaxConnection: Ошибка соединения. + InvalidToken: Ошибка авторизации (401). """ if self.bot is None: raise RuntimeError('Bot не инициализирован') - + if not self.bot.session: self.bot.session = ClientSession( - base_url=self.bot.API_URL, - timeout=self.bot.default_connection.timeout, + base_url=self.bot.API_URL, + timeout=self.bot.default_connection.timeout, **self.bot.default_connection.kwargs ) try: r = await self.bot.session.request( - method=method.value, - url=path.value if isinstance(path, ApiPath) else path, + method=method.value, + url=path.value if isinstance(path, ApiPath) else path, **kwargs ) except ClientConnectionError as e: raise MaxConnection(f'Ошибка при отправке запроса: {e}') - + if r.status == 401: await self.bot.session.close() raise InvalidToken('Неверный токен!') @@ -97,38 +109,41 @@ class BaseConnection: error = Error(code=r.status, raw=raw) logger_bot.error(error) return error - + raw = await r.json() - if is_return_raw: + if is_return_raw: return raw - model = model(**raw) # type: ignore - + model = model(**raw) # type: ignore + if hasattr(model, 'message'): attr = getattr(model, 'message') if hasattr(attr, 'bot'): attr.bot = self.bot - + if hasattr(model, 'bot'): model.bot = self.bot return model - + async def upload_file( - self, - url: str, - path: str, - type: UploadType + self, + url: str, + path: str, + type: UploadType ): + """ - Загружает файл на указанный URL. + Загружает файл на сервер. - :param url: Конечная точка загрузки файла - :param path: Путь к локальному файлу - :param type: Тип файла (video, image, audio, file) + Args: + url (str): URL загрузки. + path (str): Путь к файлу. + type (UploadType): Тип файла. - :return: Сырой .text() ответ от сервера после загрузки файла + Returns: + str: Сырой .text() ответ от сервера. """ async with aiofiles.open(path, 'rb') as f: @@ -147,12 +162,12 @@ class BaseConnection: async with ClientSession() as session: response = await session.post( - url=url, + url=url, data=form ) return await response.text() - + async def upload_file_buffer( self, filename: str, @@ -160,16 +175,20 @@ class BaseConnection: buffer: bytes, type: UploadType ): + """ Загружает файл из буфера. - :param url: Конечная точка загрузки файла - :param buffer: Буфер (bytes) - :param type: Тип файла (video, image, audio, file) + Args: + filename (str): Имя файла. + url (str): URL загрузки. + buffer (bytes): Буфер данных. + type (UploadType): Тип файла. - :return: Сырой .text() ответ от сервера после загрузки файла + Returns: + str: Сырой .text() ответ от сервера. """ - + try: matches = puremagic.magic_string(buffer[:4096]) if matches: @@ -194,36 +213,7 @@ class BaseConnection: async with ClientSession() as session: response = await session.post( - url=url, + url=url, data=form ) - return await response.text() - - async def download_file( - self, - path: str, - url: str, - token: str, - ): - """ - Скачивает медиа с указанной ссылки по токену, сохраняя по определенному пути - - :param path: Путь сохранения медиа - :param url: Ссылка на медиа - :param token: Токен медиа - - :return: Числовой статус - """ - - headers = { - 'Authorization': f'Bearer {token}' - } - - async with ClientSession() as session: - async with session.get(url, headers=headers) as response: - - if response.status == 200: - async with aiofiles.open(path, 'wb') as f: - await f.write(await response.read()) - - return response.status \ No newline at end of file + return await response.text() \ No newline at end of file diff --git a/maxapi/context/state_machine.py b/maxapi/context/state_machine.py index a221810..3e11a89 100644 --- a/maxapi/context/state_machine.py +++ b/maxapi/context/state_machine.py @@ -1,4 +1,8 @@ +from typing import List + + class State: + """ Представляет отдельное состояние в FSM-группе. @@ -16,6 +20,7 @@ class State: class StatesGroup: + """ Базовый класс для описания группы состояний FSM. @@ -23,7 +28,8 @@ class StatesGroup: """ @classmethod - def states(cls) -> list[str]: + def states(cls) -> List[str]: + """ Получить список всех состояний в формате 'ИмяКласса:имя_состояния'. diff --git a/maxapi/dispatcher.py b/maxapi/dispatcher.py index bee4b8d..09824da 100644 --- a/maxapi/dispatcher.py +++ b/maxapi/dispatcher.py @@ -8,6 +8,8 @@ from asyncio.exceptions import TimeoutError as AsyncioTimeoutError from aiohttp import ClientConnectorError +from maxapi.exceptions.dispatcher import HandlerException + from .filters.filter import BaseFilter from .filters.middleware import BaseMiddleware from .filters.handler import Handler @@ -60,9 +62,9 @@ class Dispatcher: """ Инициализация диспетчера. - - :param router_id: Идентификатор роутера, используется при логгировании. - По умолчанию индекс зарегистированного роутера в списке + + Args: + router_id (str | None): Идентификатор роутера для логов. """ self.router_id = router_id @@ -132,6 +134,17 @@ class Dispatcher: handler: Callable[[Any, dict[str, Any]], Awaitable[Any]] ) -> Callable[[Any, dict[str, Any]], Awaitable[Any]]: + """ + Формирует цепочку вызова middleware вокруг хендлера. + + Args: + middlewares (list[BaseMiddleware]): Список middleware. + handler (Callable): Финальный обработчик. + + Returns: + Callable: Обёрнутый обработчик. + """ + for mw in reversed(middlewares): handler = functools.partial(mw, handler) @@ -142,7 +155,8 @@ class Dispatcher: """ Добавляет указанные роутеры в диспетчер. - :param routers: Роутеры для добавления. + Args: + *routers (Router): Роутеры для добавления. """ self.routers += [r for r in routers] @@ -150,9 +164,10 @@ class Dispatcher: def outer_middleware(self, middleware: BaseMiddleware) -> None: """ - Добавляет Middleware на первое место в списке - - :param: middleware: Middleware + Добавляет Middleware на первое место в списке. + + Args: + middleware (BaseMiddleware): Middleware. """ self.middlewares.insert(0, middleware) @@ -160,9 +175,10 @@ class Dispatcher: def middleware(self, middleware: BaseMiddleware) -> None: """ - Добавляет Middleware в список - - :param middleware: Middleware + Добавляет Middleware в конец списка. + + Args: + middleware (BaseMiddleware): Middleware. """ self.middlewares.append(middleware) @@ -170,9 +186,10 @@ class Dispatcher: def filter(self, base_filter: BaseFilter) -> None: """ - Добавляет фильтр в список - - :param base_filter: Фильтр + Добавляет фильтр в список. + + Args: + base_filter (BaseFilter): Фильтр. """ self.base_filters.append(base_filter) @@ -182,7 +199,8 @@ class Dispatcher: """ Подготавливает диспетчер: сохраняет бота, регистрирует обработчики, вызывает on_started. - :param bot: Экземпляр бота. + Args: + bot (Bot): Экземпляр бота. """ self.bot = bot @@ -208,11 +226,14 @@ class Dispatcher: def __get_memory_context(self, chat_id: int, user_id: int): """ - Возвращает существующий или создает новый контекст по chat_id и user_id. + Возвращает существующий или создаёт новый MemoryContext по chat_id и user_id. - :param chat_id: Идентификатор чата. - :param user_id: Идентификатор пользователя. - :return: Объект MemoryContext. + Args: + chat_id (int): Идентификатор чата. + user_id (int): Идентификатор пользователя. + + Returns: + MemoryContext: Контекст. """ for ctx in self.contexts: @@ -223,10 +244,23 @@ class Dispatcher: self.contexts.append(new_ctx) return new_ctx - async def call_handler(self, handler, event_object, data): + async def call_handler( + self, + handler: Callable[[Any, dict[str, Any]], Awaitable[Any]], + event_object: UpdateType, + data: Dict[str, Any] + ): """ - Правка аргументов конечной функции хендлера и ее вызов + Вызывает хендлер с нужными аргументами. + + Args: + handler: Handler. + event_object: Объект события. + data: Данные для хендлера. + + Returns: + None """ func_args = handler.func_event.__annotations__.keys() @@ -243,6 +277,17 @@ class Dispatcher: filters: List[BaseFilter] ) -> Optional[Dict[str, Any]] | Literal[False]: + """ + Асинхронно применяет фильтры к событию. + + Args: + event (UpdateUnion): Событие. + filters (List[BaseFilter]): Список фильтров. + + Returns: + Optional[Dict[str, Any]] | Literal[False]: Словарь с результатом или False. + """ + data = {} for _filter in filters: @@ -259,9 +304,10 @@ class Dispatcher: async def handle(self, event_object: UpdateUnion): """ - Основной обработчик события. Применяет фильтры, middleware и вызывает подходящий handler. + Основной обработчик события. Применяет фильтры, middleware и вызывает нужный handler. - :param event_object: Событие, пришедшее в бот. + Args: + event_object (UpdateUnion): Событие. """ try: @@ -335,26 +381,36 @@ class Dispatcher: ) kwargs_filtered = {k: v for k, v in kwargs.items() if k in func_args} - - await handler_chain(event_object, kwargs_filtered) + + try: + await handler_chain(event_object, kwargs_filtered) + except: + raise HandlerException( + handler_title=handler.func_event.__name__, + memory_context={ + 'data': await memory_context.get_data(), + 'state': current_state + } + ) - logger_dp.info(f'Обработано: {router_id} | {process_info}') + logger_dp.info(f'Обработано: router_id: {router_id} | {process_info}') is_handled = True break if not is_handled: - logger_dp.info(f'Проигнорировано: {router_id} | {process_info}') + logger_dp.info(f'Проигнорировано: router_id: {router_id} | {process_info}') except Exception as e: - logger_dp.error(f"Ошибка при обработке события: {router_id} | {process_info} | {e} ") + logger_dp.error(f"Ошибка при обработке события: router_id: {router_id} | {process_info} | {e} ") async def start_polling(self, bot: Bot): """ - Запускает цикл получения обновлений с сервера (long polling). + Запускает цикл получения обновлений (long polling). - :param bot: Экземпляр бота. + Args: + bot (Bot): Экземпляр бота. """ self.polling = True @@ -399,9 +455,10 @@ class Dispatcher: """ Запускает FastAPI-приложение для приёма обновлений через вебхук. - :param bot: Экземпляр бота. - :param host: Хост, на котором запускается сервер. - :param port: Порт сервера. + Args: + bot (Bot): Экземпляр бота. + host (str): Хост сервера. + port (int): Порт сервера. """ if not FASTAPI_INSTALLED: @@ -422,19 +479,6 @@ class Dispatcher: '\n\t pip install maxapi[webhook]' ) - # try: - # from fastapi import Request - # from fastapi.responses import JSONResponse - # except ImportError: - # raise ImportError( - # '\n\t Не установлен fastapi!' - # '\n\t Выполните команду для установки fastapi: ' - # '\n\t pip install fastapi>=0.68.0' - # '\n\t Или сразу все зависимости для работы вебхука:' - # '\n\t pip install maxapi[webhook]' - # ) - - @self.webhook_post('/') async def _(request: Request): event_json = await request.json() @@ -457,24 +501,14 @@ class Dispatcher: async def init_serve(self, bot: Bot, host: str = 'localhost', port: int = 8080, **kwargs): """ - Запускает сервер для обработки входящих вебхуков. + Запускает сервер для обработки вебхуков. - :param bot: Экземпляр бота. - :param host: Хост, на котором запускается сервер. - :param port: Порт сервера. + Args: + bot (Bot): Экземпляр бота. + host (str): Хост. + port (int): Порт. """ - # try: - # from uvicorn import Config, Server - # except ImportError: - # raise ImportError( - # '\n\t Не установлен uvicorn!' - # '\n\t Выполните команду для установки uvicorn: ' - # '\n\t pip install uvicorn>=0.15.0' - # '\n\t Или сразу все зависимости для работы вебхука:' - # '\n\t pip install maxapi[webhook]' - # ) - if not UVICORN_INSTALLED: raise ImportError( '\n\t Не установлен uvicorn!' @@ -504,10 +538,10 @@ class Router(Dispatcher): def __init__(self, router_id: str | None = None): """ - Инициализация диспетчера. - - :param router_id: Идентификатор роутера, используется при логгировании. - По умолчанию индекс зарегистированного роутера в списке + Инициализация роутера. + + Args: + router_id (str | None): Идентификатор роутера для логов. """ super().__init__(router_id) @@ -524,8 +558,9 @@ class Event: """ Инициализирует событие-декоратор. - :param update_type: Тип события (UpdateType). - :param router: Роутер или диспетчер, в который регистрируется обработчик. + Args: + update_type (UpdateType): Тип события. + router (Dispatcher | Router): Экземпляр роутера или диспетчера. """ self.update_type = update_type @@ -536,7 +571,8 @@ class Event: """ Регистрирует функцию как обработчик события. - :return: Исходная функция. + Returns: + Callable: Исходная функция. """ def decorator(func_event: Callable): diff --git a/maxapi/filters/__init__.py b/maxapi/filters/__init__.py index de46338..fdd3b2f 100644 --- a/maxapi/filters/__init__.py +++ b/maxapi/filters/__init__.py @@ -9,14 +9,19 @@ __all__ = [ def filter_attrs(obj: object, *filters: MagicFilter) -> bool: + """ Применяет один или несколько фильтров MagicFilter к объекту. - - :param obj: Любой объект с атрибутами (например, event/message) - :param filters: Один или несколько MagicFilter выражений - :return: True, если все фильтры возвращают True, иначе False + + Args: + obj (object): Объект, к которому применяются фильтры (например, event или message). + *filters (MagicFilter): Один или несколько выражений MagicFilter. + + Returns: + bool: True, если все фильтры возвращают True, иначе False. """ + try: return all(f.resolve(obj) for f in filters) except Exception: - return False \ No newline at end of file + return False diff --git a/maxapi/filters/command.py b/maxapi/filters/command.py index 709d07c..ed6d092 100644 --- a/maxapi/filters/command.py +++ b/maxapi/filters/command.py @@ -12,12 +12,12 @@ class Command(BaseFilter): Фильтр сообщений на соответствие команде. Args: - commands (str | list[str]): Ожидаемая команда или список команд без префикса. + commands (str | List[str]): Ожидаемая команда или список команд без префикса. prefix (str, optional): Префикс команды (по умолчанию '/'). check_case (bool, optional): Учитывать регистр при сравнении (по умолчанию False). Attributes: - commands (list[str]): Список команд без префикса. + commands (List[str]): Список команд без префикса. prefix (str): Префикс команды. check_case (bool): Флаг чувствительности к регистру. """ diff --git a/maxapi/filters/filter.py b/maxapi/filters/filter.py index 62c6ad1..b5cb3fa 100644 --- a/maxapi/filters/filter.py +++ b/maxapi/filters/filter.py @@ -6,5 +6,16 @@ if TYPE_CHECKING: class BaseFilter: + + """ + Базовый класс для фильтров. + + Определяет интерфейс фильтрации событий. + Потомки должны переопределять метод __call__. + + Methods: + __call__(event): Асинхронная проверка события на соответствие фильтру. + """ + async def __call__(self, event: UpdateUnion) -> bool | dict: - return True \ No newline at end of file + return True diff --git a/maxapi/filters/handler.py b/maxapi/filters/handler.py index 56e53e3..b95c649 100644 --- a/maxapi/filters/handler.py +++ b/maxapi/filters/handler.py @@ -17,27 +17,24 @@ class Handler: """ Обработчик события. - Позволяет связать функцию-обработчик с типом обновления, состоянием и набором фильтров. + Связывает функцию-обработчик с типом события, состояниями и фильтрами. """ def __init__( - self, - *args, - func_event: Callable, - update_type: UpdateType, - **kwargs - ): + self, + *args, + func_event: Callable, + update_type: UpdateType, + **kwargs + ): """ - Инициализация обработчика. + Создаёт обработчик события. - :param args: Список фильтров и состояний, в том числе: - - MagicFilter — фильтр события, - - State — состояние FSM, - - Command — команда для фильтрации по началу текста сообщения. - :param func_event: Функция-обработчик события - :param update_type: Тип обновления (события), на которое подписан обработчик - :param kwargs: Дополнительные параметры (не используются) + Args: + *args: Список фильтров (MagicFilter, State, Command, BaseFilter, BaseMiddleware). + func_event (Callable): Функция-обработчик. + update_type (UpdateType): Тип обновления. """ self.func_event: Callable = func_event @@ -57,5 +54,6 @@ class Handler: elif isinstance(arg, BaseFilter): self.base_filters.append(arg) else: - logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при ' - f'регистрации функции `{func_event.__name__}`') \ No newline at end of file + logger_dp.info( + f'Неизвестный фильтр `{arg}` при регистрации `{func_event.__name__}`' + ) diff --git a/maxapi/filters/middleware.py b/maxapi/filters/middleware.py index 7382188..54edaa3 100644 --- a/maxapi/filters/middleware.py +++ b/maxapi/filters/middleware.py @@ -1,10 +1,30 @@ from typing import Any, Callable, Awaitable class BaseMiddleware: + + """ + Базовый класс для мидлварей. + + Используется для обработки события до и после вызова хендлера. + """ + async def __call__( self, handler: Callable[[Any, dict[str, Any]], Awaitable[Any]], event_object: Any, data: dict[str, Any] ) -> Any: - return await handler(event_object, data) \ No newline at end of file + + """ + Вызывает хендлер с переданным событием и данными. + + Args: + handler (Callable): Хендлер события. + event_object (Any): Событие. + data (dict): Дополнительные данные. + + Returns: + Any: Результат работы хендлера. + """ + + return await handler(event_object, data) diff --git a/maxapi/types/attachments/attachment.py b/maxapi/types/attachments/attachment.py index 499fc3a..a25aed6 100644 --- a/maxapi/types/attachments/attachment.py +++ b/maxapi/types/attachments/attachment.py @@ -113,30 +113,4 @@ class Attachment(BaseModel): bot: Optional[Bot] # type: ignore class Config: - use_enum_values = True - - # async def download( - # self, - # path: str - # ): - - # """ - # Скачивает медиа, сохраняя по определенному пути - - # :param path: Путь сохранения медиа - - # :return: Числовой статус - # """ - - # if not hasattr(self.payload, 'token') or \ - # not hasattr(self.payload, 'url'): - # raise NotAvailableForDownload() - - # elif not self.payload.token or not self.payload.url: - # raise NotAvailableForDownload(f'Медиа типа `{self.type}` недоступно для скачивания') - - # return await self.bot.download_file( - # path=path, - # url=self.payload.url, - # token=self.payload.token, - # ) \ No newline at end of file + use_enum_values = True \ No newline at end of file diff --git a/maxapi/types/attachments/audio.py b/maxapi/types/attachments/audio.py index d0ec827..c4ee577 100644 --- a/maxapi/types/attachments/audio.py +++ b/maxapi/types/attachments/audio.py @@ -11,7 +11,6 @@ class Audio(Attachment): Вложение с типом аудио. Attributes: - type (Literal['audio']): Тип вложения, всегда 'audio'. transcription (Optional[str]): Транскрипция аудио (если есть). """ diff --git a/maxapi/types/attachments/buttons/request_geo_location_button.py b/maxapi/types/attachments/buttons/request_geo_location_button.py index cacdf52..d94076a 100644 --- a/maxapi/types/attachments/buttons/request_geo_location_button.py +++ b/maxapi/types/attachments/buttons/request_geo_location_button.py @@ -5,7 +5,8 @@ from .button import Button class RequestGeoLocationButton(Button): - """Кнопка запроса геолокации пользователя. + """ + Кнопка запроса геолокации пользователя. Attributes: quick: Если True, запрашивает геолокацию без дополнительного diff --git a/maxapi/types/attachments/contact.py b/maxapi/types/attachments/contact.py index d820d2f..e497f23 100644 --- a/maxapi/types/attachments/contact.py +++ b/maxapi/types/attachments/contact.py @@ -8,9 +8,6 @@ class Contact(Attachment): """ Вложение с типом контакта. - - Attributes: - type (Literal['contact']): Тип вложения, всегда 'contact'. """ type: Literal[AttachmentType.CONTACT] \ No newline at end of file diff --git a/maxapi/types/attachments/file.py b/maxapi/types/attachments/file.py index c4fd0c7..d8d7fab 100644 --- a/maxapi/types/attachments/file.py +++ b/maxapi/types/attachments/file.py @@ -11,7 +11,6 @@ class File(Attachment): Вложение с типом файла. Attributes: - type (Literal['file']): Тип вложения, всегда 'file'. filename (Optional[str]): Имя файла. size (Optional[int]): Размер файла в байтах. """ diff --git a/maxapi/types/attachments/location.py b/maxapi/types/attachments/location.py index fe692d9..ae108ad 100644 --- a/maxapi/types/attachments/location.py +++ b/maxapi/types/attachments/location.py @@ -11,7 +11,6 @@ class Location(Attachment): Вложение с типом геолокации. Attributes: - type (Literal['location']): Тип вложения, всегда 'location'. latitude (Optional[float]): Широта. longitude (Optional[float]): Долгота. """ diff --git a/maxapi/types/attachments/share.py b/maxapi/types/attachments/share.py index f3967cd..4066df3 100644 --- a/maxapi/types/attachments/share.py +++ b/maxapi/types/attachments/share.py @@ -11,7 +11,6 @@ class Share(Attachment): Вложение с типом "share" (поделиться). Attributes: - type (Literal['share']): Тип вложения, всегда 'share'. title (Optional[str]): Заголовок для шаринга. description (Optional[str]): Описание. image_url (Optional[str]): URL изображения для предпросмотра. diff --git a/maxapi/types/attachments/sticker.py b/maxapi/types/attachments/sticker.py index 9da850c..9e754ac 100644 --- a/maxapi/types/attachments/sticker.py +++ b/maxapi/types/attachments/sticker.py @@ -11,7 +11,6 @@ class Sticker(Attachment): Вложение с типом стикера. Attributes: - type (Literal['sticker']): Тип вложения, всегда 'sticker'. width (Optional[int]): Ширина стикера в пикселях. height (Optional[int]): Высота стикера в пикселях. """ diff --git a/maxapi/types/attachments/video.py b/maxapi/types/attachments/video.py index 7c948e0..7c891b7 100644 --- a/maxapi/types/attachments/video.py +++ b/maxapi/types/attachments/video.py @@ -51,7 +51,6 @@ class Video(Attachment): Вложение с типом видео. Attributes: - type (Optional[Literal['video']]): Тип вложения, всегда 'video'. token (Optional[str]): Токен видео. urls (Optional[VideoUrl]): URLs видео разных разрешений. thumbnail (VideoThumbnail): Миниатюра видео. diff --git a/maxapi/types/input_media.py b/maxapi/types/input_media.py index df01e94..2cd5668 100644 --- a/maxapi/types/input_media.py +++ b/maxapi/types/input_media.py @@ -6,6 +6,7 @@ from ..enums.upload_type import UploadType class InputMedia: + """ Класс для представления медиафайла. @@ -15,16 +16,19 @@ class InputMedia: """ def __init__(self, path: str): + """ Инициализирует объект медиафайла. Args: path (str): Путь к файлу. """ + self.path = path self.type = self.__detect_file_type(path) def __detect_file_type(self, path: str) -> UploadType: + """ Определяет тип файла на основе его содержимого (MIME-типа). @@ -34,6 +38,7 @@ class InputMedia: Returns: UploadType: Тип файла (VIDEO, IMAGE, AUDIO или FILE). """ + with open(path, 'rb') as f: sample = f.read(4096) @@ -60,6 +65,7 @@ class InputMedia: class InputMediaBuffer: + """ Класс для представления медиафайла из буфера. @@ -69,6 +75,7 @@ class InputMediaBuffer: """ def __init__(self, buffer: bytes, filename: str | None = None): + """ Инициализирует объект медиафайла из буфера. @@ -76,6 +83,7 @@ class InputMediaBuffer: buffer (IO): Буфер с содержимым файла. filename (str): Название файла (по умолчанию присваивается uuid4). """ + self.filename = filename self.buffer = buffer self.type = self.__detect_file_type(buffer) diff --git a/maxapi/types/updates/message_chat_created.py b/maxapi/types/updates/message_chat_created.py index 96de461..98f6d1a 100644 --- a/maxapi/types/updates/message_chat_created.py +++ b/maxapi/types/updates/message_chat_created.py @@ -6,6 +6,17 @@ from .update import Update class MessageChatCreated(Update): + + """ + Событие создания чата. + + Attributes: + chat (Chat): Объект чата. + title (Optional[str]): Название чата. + message_id (Optional[str]): ID сообщения. + start_payload (Optional[str]): Payload для старта. + """ + chat: Chat title: Optional[str] = None message_id: Optional[str] = None diff --git a/maxapi/utils/inline_keyboard.py b/maxapi/utils/inline_keyboard.py index 0efe03f..11ae4dc 100644 --- a/maxapi/utils/inline_keyboard.py +++ b/maxapi/utils/inline_keyboard.py @@ -5,7 +5,8 @@ from ..types.attachments.attachment import Attachment, ButtonsPayload class InlineKeyboardBuilder: - """Конструктор инлайн-клавиатур. + """ + Конструктор инлайн-клавиатур. Позволяет удобно собирать кнопки в ряды и формировать из них клавиатуру для отправки в сообщениях. @@ -16,7 +17,8 @@ class InlineKeyboardBuilder: def row(self, *buttons: InlineButtonUnion): - """Добавить новый ряд кнопок в клавиатуру. + """ + Добавить новый ряд кнопок в клавиатуру. Args: *buttons: Произвольное количество кнопок для добавления в ряд. @@ -26,7 +28,8 @@ class InlineKeyboardBuilder: def add(self, button: InlineButtonUnion): - """Добавить кнопку в последний ряд клавиатуры. + """ + Добавить кнопку в последний ряд клавиатуры. Args: button: Кнопка для добавления. @@ -36,7 +39,8 @@ class InlineKeyboardBuilder: def as_markup(self): - """Собрать клавиатуру в объект для отправки. + """ + Собрать клавиатуру в объект для отправки. Returns: Объект вложения с типом INLINE_KEYBOARD. diff --git a/maxapi/utils/updates.py b/maxapi/utils/updates.py index faa4def..dabaa21 100644 --- a/maxapi/utils/updates.py +++ b/maxapi/utils/updates.py @@ -21,9 +21,20 @@ from ..enums.chat_type import ChatType if TYPE_CHECKING: from ..bot import Bot - async def enrich_event(event_object: Any, bot: Bot) -> Any: + + """ + Дополняет объект события данными чата, пользователя и ссылкой на бота. + + Args: + event_object (Any): Событие, которое нужно дополнить. + bot (Bot): Экземпляр бота. + + Returns: + Any: Обновлённый объект события. + """ + if not bot.auto_requests: return event_object