Правила
Для того чтобы хендлер ловил только нужные сообщения/другие ивенты, нужны правила (rules, рулзы - устоявшаяся транслитерация в комьюнити вкботла), в вкботле существует множество рулзов прямо из коробки.
Внимание
Все встроенные рулзы работают только с объектом Message
, для обработки сырых евентов нужно писать свою реализацию.
Есть несколько способов использования правил:
-
Импортировать их из
vkbottle.dispatch.rules.base
и использовать, инициализируя прямо в декораторе или в любой другой части кода:from vkbottle.dispatch.rules.base import CommandRule from typing import Tuple @bot.on.message(CommandRule("say", ["!", "/"], 1)) async def say_handler(message: Message, args: Tuple[str]): await message.answer(f"<<{args[0]}>>")
-
Использовать шорткаты, список с названиями можно найти здесь
@bot.on.message(command=("say", 1)) async def say_handler(message: Message, args: Tuple[str]): await message.answer(f"<<{args[0]}>>")
Примечание
Некоторые правила принимают в качестве аргумента итерируемый объект.
Например, CommandRule
, который принимает два аргумента: command
и args_count
, но при использовании шортката можно передавать их в кортеже:
python @bot.on.message(command=("help", 0))
Создание собственных правил
Примечание
Правило - это класс соответствующий интерфейсу ABCRule
, который должен реализовать лишь один асинхронный метод check
, принимающий ивент и возвращающий False
если проверка пройдена не была и True
либо словарь с аргументами, которые будут распакованы в хендлер как непозиционные аргументы
Создание правил напрямую
Чтобы создать правила импортируем ABCRule
и имплементируем асинхронный метод check
, еще стоит импортировать Union
из typing
для типизации вашего кода:
from typing import Union
from vkbottle.bot import Message
from vkbottle.dispatch.rules import ABCRule
class MyRule(ABCRule[Message]):
async def check(self, event: Message) -> Union[dict, bool]:
...
Теперь стоит имплементировать логику правила MyRule
, пусть оно будет просто проверять что длина сообщения меньше ста символов:
return len(message.text) < 100
Вот что получилось:
Примечание
Union в данном правиле не понадобился поэтому его допустимо опустить по стандартам mypy, в любом случае на сигнатуру это не повлияет
from typing import Union
from vkbottle.bot import Message
from vkbottle.dispatch.rules import ABCRule
class MyRule(ABCRule[Message]):
async def check(self, event: Message) -> bool:
return len(event.text) < 100
Теперь правило можно использовать как первым способом:
@bot.on.message(MyRule())
Вторым способом рулзом MyRule
в текущем состоянии воспользоваться не получится, из-за отсутствия каких-либо параметров правила, предлагается его кастомизировать с помощью метода __init__
:
# Новый вид правила
class MyRule(ABCRule[Message]):
def __init__(self, lt: int = 100):
self.lt = lt
async def check(self, event: Message) -> bool:
return len(event.text) < self.lt
Теперь, если предварительно (до объявления хендлеров) зарегистрировать правило в локальный лейблер
bot.labeler.custom_rules["my_rule"] = MyRule
Его можно будет использовать и вторым способом:
@bot.on.message(my_rule=50)
Создание правил через правила-врапперы
Примечание
Есть так называемые правила-врапперы, правила - которые исполняют какой-то код который получают как параметры
К правилам-врапперам из коробки можно отнести: func
, шорткат для FuncRule
; coro
или coroutine
, шорткат для CoroutineRule
FuncRule
принимает в качестве аргумента функцию (которая может быть лямбдой). Созданное напрямую правило MyRule
можно заменить вот так:
@bot.on.message(func=lambda message: len(message.text) < 100)