Lightweight aiogram-style client for Yandex Messenger Bot API.
Project description
yandex-bot-client — библиотека для ботов Яндекс.Мессенджера
Лёгкий aiogram-style клиент к Bot API Яндекс.Мессенджера: long polling, роутеры, фильтры, FSM и inline-кнопки без внешних SDK.
GitHub: https://github.com/IvanKostin98/yandex-bot-client
Именование:
- пакет в PyPI:
yandex-bot-client - импорт в Python-коде:
yandex_bot_client
Что внутри:
Botсmessage_handler,button_handler,callback_handler,default_handlerRouterдля разбиения логики на модулиF/Filter/StateFilter(в стиле aiogram)State,FSMContext,set_state/get_stateMessage,CallbackQuery,UserтипыKeyboardbuilder для inline-кнопок
Быстрый старт
- Установка:
pip install yandex-bot-client
Важно: имя пакета в PyPI и имя модуля для импорта могут отличаться.
Для этого проекта установка: yandex-bot-client, импорт: yandex_bot_client.
- Добавьте токен в
.env:
YANDEX_BOT_API_KEY=ваш_oauth_токен_бота
- Минимальный запуск:
import os
import asyncio
from yandex_bot_client import Bot, Message
bot = Bot(os.getenv("YANDEX_BOT_API_KEY"))
@bot.message_handler("/start")
async def start(message: Message):
await bot.reply("Привет! Бот запущен.")
if __name__ == "__main__":
asyncio.run(bot.run())
Установка из исходников (локальная разработка)
pip install -r requirements.txt
Запуск примера
В .env в корне проекта:
YANDEX_BOT_API_KEY=ваш_oauth_токен_бота
Запуск примера бота с кнопками:
python bot.py
или
python -m test.example
Структура проекта
yandex_bot_client/ # библиотека
__init__.py # экспорт Bot, Keyboard, Router, F, Filter, StateFilter, State, ...
client.py # класс Bot, long polling, middleware chain
filters.py # фильтры F, Filter, StateFilter, and_f, or_f
fsm.py # FSM: State, get_state, set_state, FSMContext
keyboard.py # класс Keyboard
middleware.py # контракт Middleware
router.py # класс Router
types.py # Message, CallbackQuery, User (как в aiogram)
config/ # конфиг из .env
__init__.py # API_KEY
test/
example.py # пример бота (роутеры + FSM)
bot.py # точка входа
Как пользоваться: класс Bot
Импорт:
import os
from yandex_bot_client import Bot, Keyboard
API_KEY = os.getenv("YANDEX_BOT_API_KEY")
Bot(api_key, log=None, poll_active_sleep=0.2, poll_idle_sleep=1.0)
Создаёт экземпляр бота.
- api_key — OAuth-токен бота.
- log — логгер (по умолчанию
loguru.logger). Можно передать свой экземпляр loguru. - poll_active_sleep — пауза цикла long polling, когда обновления есть (по умолчанию
0.2сек). - poll_idle_sleep — пауза цикла long polling, когда обновлений нет (по умолчанию
1.0сек). Можно уменьшить для более быстрого отклика или увеличить, чтобы снизить нагрузку на API.
Bot.current()
Возвращает бота, обрабатывающего текущее обновление. Вызывайте только из хендлера — так можно обойтись без глобальной переменной. Вне хендлера вернёт None.
- Возвращает: экземпляр Bot или None.
Пример: bot = Bot.current(); if bot: await bot.reply(...) (см. test/example.py).
bot.state(login)
Возвращает словарь данных пользователя (сессию), изолированный от других.
Используйте для своих полей (выбранный поставщик, email и т.д.). FSM-состояние хранится отдельно (set_state/get_state), не в этом словаре — конфликта ключей нет.
- login — логин пользователя (обычно email).
- Возвращает: словарь; изменения сохраняются.
Пример: bot.state(login)["flow"] = "payments".
bot.message_handler(text=None, filters=None, state=None)
Регистрирует обработчик текстовых сообщений.
- text — строка команды/текста (например
"/start"). ЕслиNone— любое сообщение. - filters — опционально: фильтр
(update) -> bool, напримерF.text == "/start". - state — опционально: FSM-состояние (строка), в котором хендлер активен;
None— любое состояние. - Обработчик:
async def handler(message: Message): .... В хендлер всегда передаётся Message (поля: text, from_user, message_id, raw). Ответ — черезbot.reply(...).
Пример:
@bot.message_handler("/start")
async def start(message: Message):
await bot.reply(f"Привет, {message.from_user.display_name or message.from_user.login}!")
bot.button_handler(action, state=None)
Регистрирует обработчик нажатия кнопки по команде из callback_data["cmd"].
- action — имя действия без слэша (как в кнопке:
cmd="/opt1"→action="opt1"). - state — опционально: FSM-состояние;
None— любое. - Обработчик:
async def handler(callback: CallbackQuery): .... В хендлер всегда передаётся CallbackQuery (поля: payload, data, from_user, raw_update).
Пример:
@bot.button_handler("opt1")
async def on_opt1(callback: CallbackQuery):
await bot.reply("Нажата опция 1")
bot.callback_handler(func)
Регистрирует обработчик для произвольного callback_data (например с полем "hash").
Вызывается, если в payload нет "cmd" или для данного cmd нет button_handler.
- func —
async def handler(callback: CallbackQuery): ...
bot.default_handler(func)
Обработчик по умолчанию для текста: вызывается, когда ни один message_handler не обработал сообщение.
- func —
async def handler(update): ...
Если не задан, бот отправит: «Не понимаю. Введите /start или /menu.»
bot.reply(text, keyboard=None)
Отправляет сообщение текущему пользователю (тому, чьё обновление обрабатывается). Используйте в обработчиках вместо send_message(login, ...) — логин берётся из контекста.
- text — текст.
- keyboard — необязательно; результат
Keyboard().build(). - Возвращает:
message_idпри успехе, иначеNone. Вне обработчика залогирует предупреждение и вернётNone.
bot.current_login()
Возвращает логин пользователя, чьё обновление сейчас обрабатывается. Удобно для bot.state(bot.current_login()) и т.п.
- Возвращает: строка логина или
None, если вызвано вне контекста обновления.
bot.send_message(login, text, keyboard=None)
Отправляет пользователю текстовое сообщение по явному login (например, другому пользователю или из кода вне обработчика).
- login — логин получателя.
- text — текст.
- keyboard — необязательно; результат
Keyboard().build()(список рядов кнопок). - Возвращает:
message_idпри успехе, иначеNone.
bot.run()
Запускает long polling: цикл запросов к API до остановки (Ctrl+C или bot.stop()). Блокирует выполнение.
bot.stop()
Останавливает цикл (run() завершится при следующей итерации).
bot.include_router(router)
Подключает роутер к боту: все обработчики роутера добавляются в конец очереди. Порядок: сначала хендлеры бота, затем каждого роутера в порядке вызова.
- router — экземпляр
Router. - Возвращает:
self(для цепочки).
bot.middleware(mw)
Регистрирует middleware (как в aiogram). Вызывается в порядке регистрации перед каждым хендлером.
- mw —
async def mw(handler, event, data): ... return await handler(event, data).event— Message или CallbackQuery,data— dict, можно дополнять для передачи в хендлер. - Возвращает: переданную функцию (удобно как декоратор).
Пример: логирование, дополнение data для хендлера.
@bot.middleware
async def my_mw(handler, event, data):
data["request_time"] = time.time()
return await handler(event, data)
Типы Message и CallbackQuery (как в aiogram)
В хендлеры всегда передаются типизированные объекты: в message_handler — Message, в button_handler и callback_handler — CallbackQuery. Один способ, без сырых dict.
- Message:
text,message_id,from_user(User),chat,update_id,timestamp,raw. - CallbackQuery:
from_user,payload,data(alias),message_id,update_id,raw_update,raw_payload. - User:
id,login,display_name,robot,_raw.
Импорт: from yandex_bot_client import Bot, Message, CallbackQuery, User.
Роутеры (Router)
Группа обработчиков с тем же API, что и у Bot. Удобно разбивать логику по модулям (меню, оплаты, обратная связь).
from yandex_bot_client import Bot, Keyboard, Router
router = Router()
@router.message_handler("/menu")
async def menu(update):
await bot.reply("Меню", menu_keyboard())
@router.button_handler("back")
async def back(callback):
await bot.reply("Главное меню", menu_keyboard())
bot = Bot(API_KEY)
bot.include_router(router)
У роутера те же параметры: text, filters, state у message_handler; state у button_handler и default_handler; filters у callback_handler.
Фильтры (F)
В стиле aiogram: декларативная проверка update и payload.
- F.text == "/start" — текст сообщения ровно
"/start". - F.callback_data.has("cmd") — в payload кнопки есть ключ
"cmd". - F.callback_data["hash"] == "abc" —
payload["hash"] == "abc". - and_f(f1, f2), or_f(f1, f2) — объединение фильтров.
Пример:
from yandex_bot_client import Bot, F
@bot.message_handler(filters=F.text == "/help")
async def help_cmd(update):
await bot.reply("Справка: /start, /menu")
Расширенные фильтры: & | ~ и StateFilter
Фильтры для сообщений можно комбинировать операторами и фильтром по FSM-состоянию:
- (F.text == "/start") & StateFilter(MyState.menu) — текст ровно
/startи текущее состояние пользователя —MyState.menu. - (F.text == "/a") | (F.text == "/b") — текст
/aили/b. - ~StateFilter(MyState.busy) — состояние не
busy.
StateFilter(state_or_states) — один state (строка) или список/кортеж допустимых. Использует Bot.current() и login из update.
from yandex_bot_client import Bot, F, StateFilter, State
class MyState(State):
menu = "menu"
busy = "busy"
@bot.message_handler(filters=(F.text == "/menu") & StateFilter(MyState.menu))
async def menu_cmd(message):
await bot.reply("Меню")
FSM (State)
Конечный автомат по пользователю: состояние хранится отдельно от bot.state(login) (внутри бота), конфликта ключей нет.
- State — базовый класс; наследуйтесь и задавайте атрибуты-строки (состояния).
- get_state(bot, login) — текущее состояние пользователя.
- set_state(bot, login, state) — установить состояние (
None— сброс). - clear_state(bot, login) — сбросить состояние.
- FSMContext(bot) — внутри обработчика:
state = FSMContext(bot);state.get_state(),state.set_state(...),state.clear_state().
Хендлеры с параметром state= срабатывают только когда текущее состояние пользователя совпадает (или state=None — любое).
from yandex_bot_client import Bot, State, set_state, get_state, FSMContext
class Auth(State):
wait_email = "wait_email"
wait_code = "wait_code"
@bot.message_handler("/start")
async def start(message: Message):
bot = Bot.current()
if bot:
set_state(bot, bot.current_login(), Auth.wait_email)
await bot.reply("Введите email")
@bot.message_handler(state=Auth.wait_email)
async def got_email(message: Message):
bot = Bot.current()
if bot:
set_state(bot, bot.current_login(), Auth.wait_code)
await bot.reply("Введите код из письма")
Как пользоваться: класс Keyboard
Служит для сборки inline-клавиатуры под send_message(..., keyboard=...).
Keyboard.button(text, cmd=None, callback_data=None, url=None)
Создаёт одну кнопку.
- text — подпись на кнопке.
- cmd — команда при нажатии (попадает в
button_handlerбез слэша). Пример:cmd="/opt1"илиcmd="opt1". - callback_data — произвольный dict (например
{"hash": "abc"}для выбора из списка; обрабатывается вcallback_handler). - url — опционально, ссылка для кнопки.
Возвращает: словарь кнопки для передачи в .row().
Keyboard().row(btn1, btn2, ...)
Добавляет один ряд кнопок. Можно вызывать цепочкой.
- Аргументы: одна или несколько кнопок, созданных через
Keyboard.button(). - Возвращает: self (для цепочки).
Keyboard().build()
Возвращает клавиатуру в формате для bot.send_message(..., keyboard=...).
- Возвращает: список рядов (каждый ряд — список кнопок).
Пример:
keyboard = (
Keyboard()
.row(
Keyboard.button("Да", cmd="/yes"),
Keyboard.button("Нет", cmd="/no"),
)
.build()
)
await bot.reply("Подтвердите?", keyboard)
Keyboard.from_rows(rows)
Собирает клавиатуру из готового списка рядов (каждый ряд — список кнопок).
Возвращает: значение в формате для send_message.
Минимальный пример своего бота
import asyncio
import os
from yandex_bot_client import Bot, Keyboard, Message, CallbackQuery
API_KEY = os.getenv("YANDEX_BOT_API_KEY")
bot = Bot(API_KEY)
@bot.message_handler("/start")
async def start(message: Message):
k = Keyboard().row(
Keyboard.button("Кнопка 1", cmd="/btn1"),
Keyboard.button("Кнопка 2", cmd="/btn2"),
).build()
await bot.reply("Выберите:", k)
@bot.button_handler("btn1")
async def btn1(callback: CallbackQuery):
await bot.reply("Нажата кнопка 1")
if __name__ == "__main__":
asyncio.run(bot.run())
Project details
Release history Release notifications | RSS feed
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 yandex_bot_client-0.1.0.tar.gz.
File metadata
- Download URL: yandex_bot_client-0.1.0.tar.gz
- Upload date:
- Size: 25.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d65202373c7b9bd1d3bfc44e8cc07aeb1979a99acd20c50034810deb4f18f99e
|
|
| MD5 |
92cf6e5d015d43352b849bbf0eaa2a6d
|
|
| BLAKE2b-256 |
f70b97cdff5204a24c3c67d053d95e3ee8b37e34c3642d071bab1650d31fac6a
|
File details
Details for the file yandex_bot_client-0.1.0-py3-none-any.whl.
File metadata
- Download URL: yandex_bot_client-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6e0a3da83cf3801647c9e30c153fba6a1993565683222aaa5092716b42adc71
|
|
| MD5 |
8e9ca800a8f7187fcf08b33a43eb5a10
|
|
| BLAKE2b-256 |
fc3753c367aab7c5449a97f2dfd33fccba0505587313204ff94ea977e8a34fac
|