Universal async bot library for Telegram and Max with aiogram-compatible API
Project description
obabot
Универсальная асинхронная библиотека для ботов Telegram и Max с API, совместимым с aiogram.
Напишите код бота один раз, запустите его на Telegram, Max или на обеих платформах одновременно!
Возможности
- Минимальные изменения при миграции — меняются только импорты и инициализация
- API, совместимый с aiogram — используйте знакомые декораторы, фильтры и FSM
- Поддержка нескольких платформ — работайте на Telegram, Max или на обеих одновременно
- Нативная производительность для Telegram — без накладных расходов (прямой aiogram)
- Прозрачные адаптеры для Max — API Max автоматически преобразуется в интерфейс, похожий на aiogram
Установка
pip install obabot
Зависимости для платформ
После установки obabot необходимо установить библиотеки для платформ:
# Для поддержки Telegram
pip install aiogram>=3.0.0
# Для поддержки Max
pip install umaxbot>=0.1.7
# Или обе
pip install aiogram>=3.0.0 umaxbot>=0.1.7
Рекомендуемая версия aiogram: 3.24 (последняя стабильная версия 3.x, используется в тестах)
Быстрый старт
Только Telegram
from obabot import create_bot
from obabot.filters import Command
bot, dp, router = create_bot(tg_token="ВАШ_ТЕЛЕГРАМ_ТОКЕН")
@router.message(Command("start"))
async def start(message):
await message.answer(f"Привет с {message.platform}!")
await dp.start_polling(bot)
Только Max
from obabot import create_bot
from obabot.filters import Command
# Просто измените аргумент токена!
bot, dp, router = create_bot(max_token="ВАШ_МАКС_ТОКЕН")
@router.message(Command("start"))
async def start(message):
await message.answer(f"Привет с {message.platform}!")
await dp.start_polling(bot)
Обе платформы (двойной режим)
from obabot import create_bot
from obabot.filters import Command
# Передайте оба токена для режима двух платформ
bot, dp, router = create_bot(
tg_token="ВАШ_ТЕЛЕГРАМ_ТОКЕН",
max_token="ВАШ_МАКС_ТОКЕН"
)
@router.message(Command("start"))
async def start(message):
# message.platform показывает, с какой платформы пришло сообщение
await message.answer(f"Привет с {message.platform.upper()}!")
# Это запускает polling на ОБЕИХ платформах
await dp.start_polling(bot)
Миграция с aiogram
Миграция существующего бота на aiogram очень проста — просто измените импорты и инициализацию!
До (aiogram)
from aiogram import Bot, Dispatcher, Router
from aiogram.filters import Command
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.context import FSMContext
bot = Bot(token="TOKEN")
dp = Dispatcher()
router = Router()
dp.include_router(router)
@router.message(Command("start"))
async def start(message):
await message.answer("Привет!")
await dp.start_polling(bot)
После (obabot)
from obabot import create_bot
from obabot.filters import Command
from obabot.fsm import State, StatesGroup, FSMContext
bot, dp, router = create_bot(tg_token="TOKEN")
@router.message(Command("start"))
async def start(message):
await message.answer("Привет!")
await dp.start_polling(bot)
Изменения:
- ✅ Изменены импорты:
aiogram→obabot - ✅ Изменена инициализация:
Bot/Dispatcher/Router→create_bot() - ✅ Всё остальное на 100% идентично!
См. examples/aiogram_original.py и examples/aiogram_migrated.py для полного примера миграции.
Справочник API
create_bot()
Основная фабричная функция для создания бота.
def create_bot(
tg_token: str | None = None,
max_token: str | None = None,
fsm_storage: BaseStorage | None = None,
test_mode: bool | None = None,
) -> tuple[ProxyBot | StubBot, ProxyDispatcher | Dispatcher, ProxyRouter | Router]:
...
Аргументы:
tg_token- токен Telegram бота (опционально; в тестовом режиме не требуется)max_token- токен Max бота (опционально; в тестовом режиме не требуется)fsm_storage- хранилище для FSM состояний (опционально). Будет использоваться всеми платформами.test_mode- еслиTrue, включается тестовый режим (без токенов и сетевых вызовов). ЕслиNone, используется переменная окруженияTESTING=1.
Возвращает: Кортеж (bot, dispatcher, router)
Режимы:
- Только
tg_token→ режим Telegram - Только
max_token→ режим Max - Оба токена → режим двух платформ
test_mode=TrueилиTESTING=1→ тестовый режим
Обработчики
Используйте те же декораторы, что и в aiogram:
# Вариант 1: Использование router (рекомендуется)
@router.message(Command("start"))
async def cmd_start(message):
await message.answer("Привет!")
# Вариант 2: Использование dispatcher (тоже работает, как в aiogram)
@dp.message(Command("start"))
async def cmd_start_v2(message):
await message.answer("Привет!")
# Оба работают с фильтрами
@router.message(F.text)
async def text_handler(message):
await message.answer(f"Вы сказали: {message.text}")
@router.callback_query(F.data == "button")
async def callback_handler(callback):
await callback.answer("Кнопка нажата!")
await callback.message.edit_text("Обновлено!")
Объект Message
Все сообщения имеют эти свойства (как в aiogram):
message.text # Текст сообщения
message.from_user # Пользователь, отправивший сообщение
message.chat # Объект чата
message.message_id # ID сообщения
message.platform # "telegram" или "max"
# Методы
await message.answer("Текст ответа")
await message.reply("Ответить на это сообщение")
await message.delete()
await message.edit_text("Новый текст")
FSM (Конечный автомат состояний)
from obabot.fsm import State, StatesGroup, FSMContext
class Form(StatesGroup):
name = State()
age = State()
@router.message(Command("start"))
async def start(message, state: FSMContext):
await state.set_state(Form.name)
await message.answer("Как тебя зовут?")
@router.message(Form.name)
async def process_name(message, state: FSMContext):
await state.update_data(name=message.text)
await state.set_state(Form.age)
await message.answer("Сколько тебе лет?")
Клавиатуры
from obabot.types import InlineKeyboardMarkup, InlineKeyboardButton
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[
InlineKeyboardButton(text="Кнопка 1", callback_data="btn1"),
InlineKeyboardButton(text="Кнопка 2", callback_data="btn2"),
]
])
await message.answer("Выберите:", reply_markup=keyboard)
Фильтры
from obabot.filters import Command, F, StateFilter
@router.message(Command("start", "help")) # Несколько команд
@router.message(F.text.startswith("!")) # Магический фильтр
@router.message(F.photo) # Сообщения с фото
@router.callback_query(F.data == "click") # Callback data
Архитектура
obabot/
├── obabot/
│ ├── __init__.py # create_bot, BPlatform
│ ├── factory.py # Реализация create_bot()
│ ├── proxy/ # Proxy классы для мультиплексирования
│ │ ├── bot.py # ProxyBot
│ │ ├── dispatcher.py # ProxyDispatcher
│ │ └── router.py # ProxyRouter
│ ├── adapters/ # Адаптеры Max → aiogram
│ │ ├── message.py # MaxMessageAdapter
│ │ ├── max_callback.py # MaxCallbackQuery
│ │ ├── telegram_callback.py # TelegramCallbackQuery
│ │ ├── user.py # MaxUserAdapter, MaxChatAdapter
│ │ └── keyboard.py # Конвертер клавиатур
│ ├── platforms/ # Реализации платформ
│ │ ├── base.py # BasePlatform ABC
│ │ ├── telegram.py # TelegramPlatform (нативный aiogram)
│ │ └── max.py # MaxPlatform (адаптированный)
│ ├── filters.py # Реэкспортированные фильтры aiogram
│ ├── fsm.py # Реэкспортированные компоненты FSM
│ └── types.py # Enum BPlatform, реэкспорты типов
└── examples/
├── aiogram_original.py # Оригинальный бот на aiogram
├── aiogram_migrated.py # Мигрированный на obabot
├── telegram_only.py # Telegram с FSM и клавиатурами
├── max_only.py # Max с FSM и клавиатурами
└── dual_platform.py # Обе платформы одновременно
└── tests/
├── test_test_mode.py # Тесты тестового режима
├── test_basic.py # Базовые тесты
└── ...
Как это работает
- Telegram (нативный): Сообщения проходят напрямую к обработчикам aiogram. Добавляется только атрибут
message.platform. - Max (адаптированный): Сообщения оборачиваются в
MaxMessageAdapter, который предоставляет интерфейс, совместимый с aiogram. - Режим двух платформ: Обе платформы работают параллельно. Каждый обработчик регистрируется на обеих платформах.
Примеры
См. директорию examples/ для полных рабочих примеров:
aiogram_original.py- Полный пример бота на оригинальном aiogram 3.xaiogram_migrated.py- Тот же бот, мигрированный на obabottelegram_only.py- Бот для Telegram с FSM и клавиатурамиmax_only.py- Тот же бот для Maxdual_platform.py- Бот для обеих платформ одновременноtest_mode_example.py- Пример тестового режима
Тестирование
Библиотека тестируется на разных версиях Python и aiogram:
- Python: 3.10, 3.13, 3.14
- aiogram: 3.0.0, 3.24, default (>=3.0.0)
# Установка dev-зависимостей
pip install -e ".[dev]"
# Запуск тестов
pytest
# С покрытием
pytest --cov=obabot --cov-report=html
Лицензия
Proprietary License - см. файл LICENSE для деталей.
Вклад в проект
Вклад приветствуется! Пожалуйста, не стесняйтесь создавать issues и pull requests.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file obabot-0.1.0.tar.gz.
File metadata
- Download URL: obabot-0.1.0.tar.gz
- Upload date:
- Size: 106.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46a7ab22ffd7562dee08cef74a4b8da286e2c4d864b1c87c0a7cf5d96e667841
|
|
| MD5 |
07c1f09d7b5a6c17efdb5eb28c18799f
|
|
| BLAKE2b-256 |
2b3c38a1d9fbf60002c356ce6a6367dfacf97f02a46543cb38b2372d34599310
|
File details
Details for the file obabot-0.1.0-py3-none-any.whl.
File metadata
- Download URL: obabot-0.1.0-py3-none-any.whl
- Upload date:
- Size: 65.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90575cba2211fb567e22359d2db4ee923c4d4e4abe63237669bca14d34e53f72
|
|
| MD5 |
3ea3438152505c4b6b09a0682861e341
|
|
| BLAKE2b-256 |
8c73828d77027efe5c55ee56faffb9c02a9498dd49f038d2080245379dc32455
|