Правила
Для того чтобы хендлер ловил только нужные сообщения/другие ивенты нужны правила (rules, рулзы - устоявшаяся транслитерация в комьюнити вкботла), в вкботле существует множество рулзов прямо из коробки, но в большинстве своем они подходят только для одного ивента - ивента сообщений
Чтобы получить доступ к правилам из коробки вы можете поступить по-разному:
-
Импортировать их из
vkbottle.bot.rules
и использовать, инициализируя прямо в декораторе или в любой другой части кода: ```python from vkbottle.bot import rules from typing import Tuple@bot.on.message(rules.CommandRule("say", ["!", "/"], 1)) async def say_handler(message: Message, args: Tuple[str]): await message.answer(f"<<{args[0]}>>") ```
-
Использовать автораспаковщики рулзов из коробки, список с названиями можно найти здесь, в этом случае некоторые второстепенные параметры контролировать будет нельзя
python @bot.on.message(command=("say", 1)) async def say_handler(message: Message, args: Tuple[str]): await message.answer(f"<<{args[0]}>>")
Правил может быть любое количество, как первого, так и второго метода распаковки
Создание собственных правил
Правило - это класс соответствующий интерфейсу
ABCRule
, который должен реализовать лишь один асинхронный методcheck
, принимающий ивент и возвращающийFalse
если проверка пройдена не была иTrue
либо словарь с аргументами, которые будут распакованы в хендлер как непозиционные аргументы
Создание правил напрямую
Чтобы создать правила импортируем продолженный от ABCRule
абстрактный интерфейс ABCMessageRule
и имплементируем асинхронный метод check
, еще стоит импортировать Union
из typing
для типизации вашего кода:
from vkbottle.bot import rules
from typing import Union
class MyRule(rules.ABCMessageRule):
async def check(self, message: Message) -> Union[dict, bool]:
...
Теперь стоит имплементировать логику правила MyRule
, пусть оно будет просто проверять что длина сообщения меньше ста символов:
return len(message.text) < 100
Вот что получилось:
Union в данном правиле не понадобился поэтому его допустимо опустить по стандартам mypy, в любом случае на сигнатуру это не повлияет
from vkbottle.bot import rules
from typing import Union
class MyRule(rules.ABCMessageRule):
async def check(self, message: Message) -> bool:
return len(message.text) < 100
Теперь правило можно использовать как первым способом:
@bot.on.message(MyRule())
Вторым способом рулзом MyRule
в текущем состоянии воспользоваться не получится, из-за отсутствия каких-либо параметров правила, предлагается его кастомизировать с помощью метода __init__
:
# Новый вид правила
class MyRule(rules.ABCMessageRule):
def __init__(self, lt: int = 100):
self.lt = lt
async def check(self, message: Message) -> bool:
return len(message.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)
FuncRule
принимает корутину.
Еще существуют фильтры, они могут помочь контролировать какие-то множества рулзов которые могут исполняться выборочно. В vkbottle существует автоматическая распаковка и трансформация некоторых инстансов в фильтры (стоит заметить что рекурсивно это не работает), а именно: * сет (
set
) из рулзов конвертируется в фильтрAndFilter
* кортеж (tuple
) из рулзов конвертируется в фильтрOrFilter
Вместо фильтров еще можно использовать несколько разных хендлеров (это будет схоже с результатом использования
OrFilter
):python @bot.on.message(some_rule=1) @bot.on.message(some_rule=100)
Еще стоит заметить, что многие правила принимают в качестве аргумента итерабельный элемент для того чтобы самим имплементировать фильтр, как напримерVBMLRule
, стоящий заtext