Skip to content

Правила

Для того чтобы хендлер ловил только нужные сообщения/другие ивенты, нужны правила (rules, рулзы - устоявшаяся транслитерация в комьюнити вкботла), в вкботле существует множество рулзов прямо из коробки.

Внимание

Все встроенные рулзы работают только с объектом Message, для обработки сырых евентов нужно писать свою реализацию.

Есть несколько способов использования правил:

  1. Импортировать их из vkbottle.dispatch.rules.base и использовать, инициализируя прямо в декораторе или в любой другой части кода:

    1
    2
    3
    4
    5
    6
    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]}>>")
    
  2. Использовать шорткаты, список с названиями можно найти здесь

    1
    2
    3
    @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, но при использовании шортката можно передавать их в кортеже: @bot.on.message(command=("help", 0))

Создание собственных правил

Примечание

Правило - это класс соответствующий интерфейсу ABCRule, который должен реализовать лишь один асинхронный метод check, принимающий ивент и возвращающий False если проверка пройдена не была и True либо словарь с аргументами, которые будут распакованы в хендлер как непозиционные аргументы

Создание правил напрямую

Чтобы создать правила импортируем ABCRule и имплементируем асинхронный метод check, еще стоит импортировать Union из typing для типизации вашего кода:

1
2
3
4
5
6
7
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, в любом случае на сигнатуру это не повлияет

1
2
3
4
5
6
7
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__:

1
2
3
4
5
6
7
# Новый вид правила
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)

Экзамплы по этой части туториала