Compare commits

...

7 Commits

7 changed files with 91 additions and 49 deletions

106
README.md
View File

@@ -1,23 +1,53 @@
# Асинхронный MAX API
<p align="center">
<a href="https://github.com/love-apples/maxapi"><img src="https://s.iimg.su/s/29/DCvw4dx2HZgFdTcpqGAs6xdnJnvD44r9zLga2GGe.png" alt="MaxAPI"></a>
</p>
[![PyPI version](https://img.shields.io/pypi/v/maxapi.svg)](https://pypi.org/project/maxapi/)
[![Python Version](https://img.shields.io/pypi/pyversions/maxapi.svg)](https://pypi.org/project/maxapi/)
[![License](https://img.shields.io/github/license/love-apples/maxapi.svg)](https://love-apples/maxapi/blob/main/LICENSE)
---
<p align="center">
<a href='https://github.com/love-apples/maxapi/wiki'>Документация</a>
<a href='https://github.com/love-apples/maxapi/tree/main/examples'>Примеры</a>
<a href='https://max.ru/join/IPAok63C3vFqbWTFdutMUtjmrAkGqO56YeAN7iyDfc8'>MAX Чат</a>
<a href='https://t.me/maxapi_github'>TG Чат</a>
</p>
## 📦 Установка
<p align="center">
<a href='https://pypi.org/project/maxapi/'>
<img src='https://img.shields.io/pypi/v/maxapi.svg' alt='PyPI version'>
</a>
<a href='https://pypi.org/project/maxapi/'>
<img src='https://img.shields.io/pypi/pyversions/maxapi.svg' alt='Python Version'>
</a>
<a href='https://love-apples/maxapi/blob/main/LICENSE'>
<img src='https://img.shields.io/github/license/love-apples/maxapi.svg' alt='License'>
</a>
</p>
## 📦 Установка из PyPi
Стабильная версия
```bash
pip install maxapi
```
---
## 🐱‍👤 Установка из GitHub
Свежая версия, возможны баги. Рекомендуется только для ознакомления с новыми коммитами.
```bash
pip install git+https://github.com/love-apples/maxapi.git
```
## 🚀 Быстрый старт
Если вы тестируете бота в чате - не забудьте дать ему права администратора!
### Запуск Polling
Если у бота установлены подписки на Webhook - события не будут приходить при методе `start_polling`. При таком случае удалите подписки на Webhook через [MasterBot](https://web.max.ru/masterbot) или через `await bot.delete_webhook()` перед `start_polling`.
```python
import asyncio
import logging
@@ -30,7 +60,7 @@ logging.basicConfig(level=logging.INFO)
bot = Bot(ут_ваш_токен')
dp = Dispatcher()
# Ответ бота при нажатии на кнопку "Начать"
@dp.bot_started()
async def bot_started(event: BotStarted):
await event.bot.send_message(
@@ -38,7 +68,7 @@ async def bot_started(event: BotStarted):
text='Привет! Отправь мне /start'
)
# Ответ бота на команду /start
@dp.message_created(Command('start'))
async def hello(event: MessageCreated):
await event.message.answer(f"Пример чат-бота для MAX 💙")
@@ -52,44 +82,42 @@ if __name__ == '__main__':
asyncio.run(main())
```
---
### Запуск Webhook
## 📚 Документация
Перед запуском бота через Webhook, вам нужно установить дополнительные зависимости (fastapi, uvicorn). Можно это сделать через команду:
```bash
pip install maxapi[webhook]
```
[Тут](https://github.com/love-apples/maxapi/wiki)
Указан пример простого запуска, для более низкого уровня можете рассмотреть [этот пример](https://github.com/love-apples/maxapi/blob/main/examples/webhook/low_level.py).
```python
import asyncio
import logging
---
from maxapi import Bot, Dispatcher
from maxapi.types import BotStarted, Command, MessageCreated
## ⭐️ Примеры
logging.basicConfig(level=logging.INFO)
[Тут](https://github.com/love-apples/maxapi/tree/main/examples)
---
bot = Bot(ут_ваш_токен')
dp = Dispatcher()
## 🧩 Возможности
- ✅ Middleware
- ✅ Роутеры
- ✅ Билдер инлайн клавиатур
- ✅ Простая загрузка медиафайлов
- ✅ MagicFilter
- ✅ Внутренние функции моделей
- ✅ Контекстный менеджер
- ✅ Поллинг
- ✅ Вебхук
- ✅ Логгирование
---
# Команда /start боту
@dp.message_created(Command('start'))
async def hello(event: MessageCreated):
await event.message.answer(f"Привет из вебхука!")
## 💬 Обратная связь и поддержка
async def main():
await dp.handle_webhook(
bot=bot,
host='localhost',
port=8080,
log_level='critical' # Можно убрать для подробного логгирования
)
- MAX: [Чат](https://max.ru/join/IPAok63C3vFqbWTFdutMUtjmrAkGqO56YeAN7iyDfc8)
- Telegram: [@loveappless](https://t.me/loveappless)
- Telegram чат: [MAXApi | Обсуждение](https://t.me/maxapi_github)
---
## 📄 Лицензия
Этот проект распространяется под лицензией MIT. См. файл [LICENSE](https://github.com/love-apples/maxapi/blob/main/LICENSE) для подробностей.
if __name__ == '__main__':
asyncio.run(main())
```

View File

@@ -16,7 +16,12 @@ async def handle_message(event: MessageCreated):
async def main():
await dp.handle_webhook(bot, log_level='critical')
await dp.handle_webhook(
bot=bot,
host='localhost',
port=8080,
log_level='critical' # Можно убрать для подробного логгирования
)
if __name__ == '__main__':

View File

@@ -136,6 +136,10 @@ class Bot(BaseConnection):
def _resolve_parse_mode(self, mode: Optional[ParseMode]) -> Optional[ParseMode]:
return mode if mode is not None else self.parse_mode
async def close_session(self) -> None:
if self.session is not None:
await self.session.close()
async def send_message(
self,
@@ -343,7 +347,7 @@ class Bot(BaseConnection):
name: Optional[str] = None,
description: Optional[str] = None,
commands: Optional[List[BotCommand]] = None,
photo: Optional[Dict[str, Any]] = None
photo: Optional[PhotoAttachmentRequestPayload] = None
) -> User:
"""

View File

@@ -240,9 +240,10 @@ class Dispatcher:
if handler.filters:
if not filter_attrs(event_object, *handler.filters):
continue
if not handler.state == current_state and handler.state:
continue
if handler.states:
if current_state not in handler.states:
continue
func_args = handler.func_event.__annotations__.keys()

View File

@@ -44,14 +44,14 @@ class Handler:
self.func_event: Callable = func_event
self.update_type: UpdateType = update_type
self.filters = []
self.state: Optional[State] = None
self.states: Optional[List[State]] = []
self.middlewares: List[BaseMiddleware] = []
for arg in args:
if isinstance(arg, MagicFilter):
self.filters.append(arg)
elif isinstance(arg, State):
self.state = arg
self.states.append(arg)
elif isinstance(arg, (Command, CommandStart)):
self.filters.insert(0, F.message.body.text.split()[0] == arg.command)
elif isinstance(arg, BaseMiddleware):

View File

@@ -1,5 +1,7 @@
from typing import Any, Dict, List, TYPE_CHECKING, Optional
from ..types.attachments.image import PhotoAttachmentRequestPayload
from ..types.users import User
from ..types.command import BotCommand
@@ -23,7 +25,7 @@ class ChangeInfo(BaseConnection):
name (str, optional): Новое имя бота
description (str, optional): Новое описание
commands (List[BotCommand], optional): Список команд
photo (Dict[str, Any], optional): Данные фото
photo (PhotoAttachmentRequestPayload, optional): Данные фото
"""
def __init__(
@@ -32,7 +34,7 @@ class ChangeInfo(BaseConnection):
name: Optional[str] = None,
description: Optional[str] = None,
commands: Optional[List[BotCommand]] = None,
photo: Optional[Dict[str, Any]] = None
photo: Optional[PhotoAttachmentRequestPayload] = None
):
self.bot = bot
self.name = name
@@ -60,7 +62,7 @@ class ChangeInfo(BaseConnection):
if self.commands:
json['commands'] = [command.model_dump() for command in self.commands]
if self.photo:
json['photo'] = self.photo
json['photo'] = self.photo.model_dump()
return await super().request(
method=HTTPMethod.PATCH,

View File

@@ -28,6 +28,7 @@ from ..types.attachments.buttons.request_contact import RequestContactButton
from ..types.attachments.buttons.open_app_button import OpenAppButton
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
from ..types.attachments.buttons.message_button import MessageButton
from ..types.attachments.image import PhotoAttachmentRequestPayload
from ..types.message import Message
from ..types.command import Command, BotCommand, CommandStart
@@ -36,6 +37,7 @@ from .input_media import InputMedia
from .input_media import InputMediaBuffer
__all__ = [
'PhotoAttachmentRequestPayload',
'DialogUnmuted',
'DialogMuted',
'DialogCleared',