Command filter
Command — встроенный фильтр aiomax2 для обработки текстовых команд.
Он проверяет текст входящего Message, разбирает имя команды и её аргументы,
а затем добавляет объект CommandObject в context handler.
Например:
from aiomax2.filters import Command
from aiomax2.types import Message
@router.message(Command("start"))
async def start(message: Message) -> None:
await message.answer("Бот запущен")
Этот handler будет вызван для сообщения:
Подробнее об общей системе фильтрации: Фильтры.
Как разбирается команда
По умолчанию команды начинаются с /.
Например, для сообщения:
фильтр:
разбирает строку на две части:
Имя команды заканчивается на первом пробельном символе.
Поэтому:
даёт:
Аргументы не разбиваются фильтром на отдельные значения. Их дальнейший разбор остаётся приложению.
CommandObject
Если команда подходит, Command добавляет в context объект CommandObject.
from aiomax2.filters import Command, CommandObject
from aiomax2.types import Message
@router.message(Command("start"))
async def start(
message: Message,
command: CommandObject,
) -> None:
print(command.prefix)
print(command.command)
print(command.args)
CommandObject содержит три поля:
Для сообщения:
значения будут следующими:
Команда без аргументов
Если после команды ничего нет:
то:
Например:
@router.message(Command("start"))
async def start(
message: Message,
command: CommandObject,
) -> None:
if command.args is None:
await message.answer("Команда вызвана без аргументов")
return
await message.answer(f"Аргументы: {command.args}")
Важно отличать None от пустой строки: при отсутствии аргументов используется
именно None.
Команда с аргументами
Аргументы можно получить через command.args:
@router.message(Command("echo"))
async def echo(
message: Message,
command: CommandObject,
) -> None:
if command.args is None:
await message.answer("Укажите текст")
return
await message.answer(command.args)
Например:
даст:
Несколько команд
Один фильтр Command может обрабатывать сразу несколько имён:
@router.message(Command("help", "about"))
async def information(
message: Message,
command: CommandObject,
) -> None:
await message.answer(f"Команда: {command.command}")
Handler подойдёт как для:
так и для:
Это удобно, когда несколько команд должны запускать один и тот же handler.
CommandStart
Для наиболее распространённой команды /start существует сокращение
CommandStart.
from aiomax2.filters import CommandStart
from aiomax2.types import Message
@router.message(CommandStart())
async def start(message: Message) -> None:
await message.answer("Привет")
Это эквивалентно:
@router.message(Command("start"))
async def start(message: Message) -> None:
await message.answer("Привет")
CommandStart также поддерживает prefix и ignore_case.
Префикс команды
По умолчанию используется:
Но его можно изменить через prefix.
Например:
@router.message(Command("help", prefix="!"))
async def help_command(message: Message) -> None:
await message.answer("Помощь")
Теперь handler ожидает:
а не:
Другой пример:
@router.message(Command("ping", prefix="."))
async def ping(message: Message) -> None:
await message.answer("pong")
Для сообщения:
Префикс можно указать и в имени команды
При создании фильтра aiomax2 удаляет переданный prefix из начала имени
команды.
Поэтому при стандартном префиксе /:
и:
эквивалентны.
То же относится к собственному префиксу:
и:
будут проверять команду:
Для единообразия в приложении обычно проще передавать имя команды без префикса:
Регистрозависимость
По умолчанию имя команды регистрозависимо:
подойдёт для:
но не для:
Чтобы отключить зависимость от регистра, используется ignore_case=True:
@router.message(Command("start", ignore_case=True))
async def start(message: Message) -> None:
await message.answer("Команда распознана")
Теперь будут приняты, например:
Для сравнения имён используется Unicode-aware нормализация через
casefold().
При этом CommandObject.command содержит исходное имя команды из сообщения.
Например, если пользователь отправил:
то при:
фильтр пройдёт, а:
CommandStart с параметрами
Параметры доступны и для CommandStart:
@router.message(
CommandStart(
prefix="!",
ignore_case=True,
)
)
async def start(message: Message) -> None: ...
Такой фильтр сможет обработать, например:
Совместное использование с другими фильтрами
Command можно комбинировать с любыми другими filters aiomax2.
Например, разрешить /admin только определённому пользователю:
from aiomax2 import F
from aiomax2.filters import Command
from aiomax2.types import Message
ADMIN_ID = 123456
@router.message(
Command("admin"),
F.user_id == ADMIN_ID,
)
async def admin(message: Message) -> None:
await message.answer("Панель администратора")
Оба фильтра должны пройти:
Можно комбинировать Command и с собственными классами Filter.
Подробнее: Фильтры.
CommandObject вместе с другими context-значениями
Поскольку результат Command добавляется в общий context, CommandObject
может использоваться вместе с другими зависимостями handler:
from aiomax2 import Bot
from aiomax2.filters import Command, CommandObject
from aiomax2.types import Message
@router.message(Command("send"))
async def send(
message: Message,
command: CommandObject,
bot: Bot,
) -> None:
if command.args is None:
await message.answer("Укажите текст")
return
await bot.send_message(
chat_id=message.chat_id,
text=command.args,
)
Command отвечает только за распознавание команды и создание
CommandObject. Остальные значения разрешаются обычным механизмом context
aiomax2.
Что считается командой
Команда должна:
- начинаться с настроенного
prefix; - содержать непустое имя;
- совпадать с одним из имён, переданных в
Command; - при наличии аргументов отделяться от них пробельным символом.
Например:
пройдёт для:
но не пройдёт для:
В последнем случае имя команды будет:
а не start.
Command следует модели сообщений MAX и не добавляет дополнительный синтаксис
команд, отсутствующий в MAX.
Не текстовые сообщения
Command работает только с Message, содержащими непустой текст.
Если событие не является Message или message.text отсутствует, фильтр
просто возвращает False.
Поэтому отдельная проверка:
перед Command обычно не требуется:
достаточно.
Валидация конфигурации
Необходимо передать хотя бы одно имя команды:
приведёт к:
Имя команды также не может быть пустым:
и не может содержать пробельные символы:
Оба варианта являются ошибками конфигурации.
Правильно:
Аргументы пользователя не нужно указывать в имени фильтра.
Неправильно:
Правильно:
а значение 123 затем будет доступно через:
Регистрация без декоратора
Command можно использовать и с .register():
async def start(
message: Message,
command: CommandObject,
) -> None:
await message.answer("Start")
router.message.register(
start,
Command("start"),
)
Это эквивалентно:
@router.message(Command("start"))
async def start(
message: Message,
command: CommandObject,
) -> None:
await message.answer("Start")
Краткая справка
| Возможность | Пример |
|---|---|
| Одна команда | Command("start") |
| Несколько команд | Command("help", "about") |
/start |
CommandStart() |
| Собственный префикс | Command("help", prefix="!") |
| Без учёта регистра | Command("start", ignore_case=True) |
| Получить имя | command.command |
| Получить аргументы | command.args |
| Получить префикс | command.prefix |
Для простых проверок полей события вместе с командами можно использовать
magic filter F.