Welcome to vk_maria’s documentation!#

[Telegram] vk_maria live PyPi Package Version PyPi Month Downloads PyPi Total Downloads Supported python versions

vk_maria очень простой фреймворк для создания ботов сообществ Vk, написанный на Python 3.8.

Официальные ресурсы vk_maria#

Сильные стороны#

  • Простота и удобство

  • Наличие конечных автоматов (FSM)

  • Типизированная

Contents#

Установка#

Установка с помощью pip:#

(.venv) $ pip install vk_maria

Установка с github:#

(.venv) $ git clone https://github.com/lxstvayne/vk_maria
(.venv) $ cd vk_maria
(.venv) $ python setup.py install

Обычно рекомендуется использовать первый способ.

Хотя библиотека и готова к использованию, она всё ещё находится на стадии разработки, поэтому не забывайте регулярно её обновлять:

(.venv) $ pip install vk_maria --upgrade

Быстрый старт#

Прежде всего вы должны получить ключ доступа вашего сообщества.

Простейший пример#

Класс Vk инкапсулирует все методы работы с токеном сообщества.

Создайте файл echo_bot.py. Откройте его и создайте экземпляр класса Vk:

from vk_maria import Vk, types
from vk_maria.dispatcher import Dispatcher


vk = Vk(access_token='token')

Примечание

Обязательно замените token ключом доступа вашего сообщества.

Затем создайте экземпляр класса Dispatcher передав ему в качестве аргумента vk:

dp = Dispatcher(vk)

После этого нам необходимо зарегистрировать обработчик событий. Обработчики событий определяют фильтры, которые должно пройти событие. Если событие проходит фильтры, вызывается декорированная функция и входящее событие передаётся в качестве аргумента.

Давайте определим обработчик событий, который будет обрабатывать все входящие сообщения от пользователя в личные сообщения сообщества и отвечать на команду Начать:

@dp.message_handler(text='Начать')
def send_welcome(event: types.Message):
    vk.messages_send(user_id=event.message.from_id, message='Добро пожаловать!')

Добавим ещё один обработчик:

@dp.message_handler()
def echo(event: types.Message):
    event.answer(event.message.text)

Как вы могли заметить, event.answer является удобным аналогом vk.messages_send.

Декорированная функция может иметь произвольное имя, однако она должна принимать минимум 1 параметр (event).

Примечание

Все обработчики тестируются в том порядке, в котором они были объявлены.

Отлично, теперь у нас есть простой бот, который отвечает на сообщение Начать приветствием и повторяет остальные отправленные сообщения. Чтобы запустить бота добавьте в исходный код следующее:

dp.start_polling(debug=True)

Примечание

Параметр debug отвечает за вывод в консоль всех происходящих событий

Вот и всё! Наш исходный файл теперь выглядит так:

from vk_maria import Vk, types
from vk_maria.dispatcher import Dispatcher


vk = Vk(access_token='token')
dp = Dispatcher(vk)


@dp.message_handler(text='Начать')
def send_welcome(event: types.Message):
    vk.messages_send(user_id=event.message.from_id, message='Добро пожаловать!')


@dp.message_handler()
def echo(event: types.Message):
    event.answer(event.message.text)


if __name__ == '__main__':
    dp.start_polling(debug=True)

Чтобы запустить бота, просто откройте терминал, введите python echo_bot.py и протестируйте его.

Обработка событий#

Лонгполлинг#

События можно обрабатывать двумя способами

С помощью цикла#
from vk_maria import Vk
from vk_maria.longpoll import LongPoll

vk = Vk(access_token='token')
lp = LongPoll(vk)

for event in lp.listen():
    ...
С помощью диспетчера событий#
from vk_maria import Vk
from vk_maria.dispatcher import Dispatcher

vk = Vk(access_token='token')
dp = Dispatcher(vk)

@dp.message_handler()
def handler(event: types.Message)
    ...

if __name__ == '__main__':
    dp.start_polling()

Обработчики событий#

Обработчик событий это функция с декоратором event_handler(). Он определяет фильтры для обрабатываемых событий.

@dp.event_handler(event_type, *filters, **bound_filters)
def handler(event):
    ...

Для удобной работы с сообщениями, существует декоратор message_handler(*filters, **bound_filters), в который по стандарту передаётся types.EventType.MESSAGE_NEW.

Связанные фильтры устанавливаются следующим образом: name=argument

Доступные связанные фильтры#

Название

Аргументы

Условие

event_type

types.EventType

True, если типы событий совпадают.

text

Строка

True, если текст сообщения совпадает с аргументом text

regexp

Регулярное выражение или подстрока

True, если подстрока находится в сообщении или строка проходит проверку на наличие шаблона регулярного выражения (Подробнее Python Regular Expressions).

commands

Список строк

True, если текст сообщения совпадает с одной из команд

frm

От кого обрабатывать события (user, chat, group) по умолчанию user

True, если поле from_(user, chat, group) соответственно равно аргументу frm

state

Состояние автомата

True, если текущее состояние равно состаянию аргумента state

Чтобы начать обрабатывать события, необходимо запустить start_polling(). Для удобства разработки можно передать параметр debug=True. Тогда все происходящие события будут красиво выводиться в консоль.

Собственные фильтры#

Чтобы определить собственный фильтр, необходимо написать класс и переопределить функцию check.

from vk_maria.dispatcher.filters import AbstractFilter

class AdminFilter(AbstractFilter):
    def check(self, event: types.Message):
        return event.message.peer_id == 1234567890

И передать его в обработчик события:

@dp.message_handler(AdminFilter, commands=['/start'])
def cmd_start(event: types.Message):
    event.reply("Hi there! What's your name?")

Количество пользовательских фильтров неограничено, их необходимо передавать первым аргументом через запятую.

Загрузка файлов#

Класс Upload реализует готовые функции для загрузки файлов на сервера Вконтакте.

Доступные методы:

  • photo(photo)

  • set_chat_photo(file, chat_id, **kwargs)

  • set_group_cover_photo(photo)

  • document(document, peer_id, **kwargs)

Параметры photo и document могут быть как строкой относительного пути к файлу, так и файлом открытым с помощью open() на бинарное чтение rb стандартной библиотеки Python.

Клавиатуры#

Клавиатуры можно создавать двумя способами

KeyboardModel#

С помощью определения класса

from vk_maria.types import KeyboardModel, Button, Color

class TestKeyboard(KeyboardModel):

    one_time = True

    row1 = [
        Button.Text(Color.PRIMARY, 'Кнопка 1'),
        Button.Text(Color.PRIMARY, 'Кнопка 2')
    ]
    row2 = [
        Button.Text(Color.PRIMARY, 'Кнопка 3'),
        Button.Text(Color.PRIMARY, 'Кнопка 4')
    ]

KeyboardMarkup#

С помощью генерации через код

from vk_maria.types import KeyboardMarkup, Button, Color

markup = KeyboardMarkup(one_time=True)
markup.add_button(Button.Text(Color.PRIMARY, 'Кнопка 1'))
markup.add_button(Button.Text(Color.PRIMARY, 'Кнопка 2'))
markup.add_row()
markup.add_button(Button.Text(Color.PRIMARY, 'Кнопка 3'))
markup.add_button(Button.Text(Color.PRIMARY, 'Кнопка 4'))

Конечные автоматы (FSM)#

Если вашему боту необходима система диалогов, то в дело вступают конечные автоматы. Это некая математическая модель, которая представляет собой набор состояний, которые переключаются в определённых условиях. В библиотеке это реализовано с помощью классов

from vk_maria.dispatcher.fsm import StatesGroup, State, MemoryStorage, FSMContext

class Form(StatesGroup):
    waiting_for_name: State
    waiting_for_age: State
    waiting_for_gender: State

Необходимо описать в классе переменные состояний.

Чтобы имелась возможность запоминать текущие состояния для диалогов всех пользователей, в класс Dispatcher необходимо передать экземпляр хранилища состояний.

dp = Dispatcher(vk, MemoryStorage())

В библиотеке на данный момент реализованы следующие хранилища состояний: MemoryStorage, JSONStorage, PickleStorage.

Пример реализации#

from vk_maria import Vk, types
from vk_maria.dispatcher import Dispatcher
from vk_maria.dispatcher.fsm import StatesGroup, State, MemoryStorage, FSMContext
from vk_maria.types import KeyboardMarkup, Button, Color, RemoveReplyMarkup


vk = Vk(access_token='token')
dp = Dispatcher(vk, MemoryStorage())

GENDERS = ('Male', 'Female', 'Other')


class Form(StatesGroup):
    waiting_for_name: State
    waiting_for_age: State
    waiting_for_gender: State


@dp.message_handler(commands=['/start'])
def cmd_start(event: types.Message):
    event.reply("Hi there! What's your name?")
    Form.waiting_for_name.set()


@dp.message_handler(state=Form.waiting_for_name)
def process_name(event: types.Message, state: FSMContext):
    state.update_data(name=event.message.text)
    event.reply("How old are you?")
    Form.next()


@dp.message_handler(state=Form.waiting_for_age)
def process_age(event: types.Message, state: FSMContext):
    state.update_data(age=event.message.text)

    markup = KeyboardMarkup(one_time=False)
    for gender in GENDERS:
        markup.add_button(Button.Text(Color.PRIMARY, gender))

    event.reply('What is your gender?', keyboard=markup)
    Form.next()


@dp.message_handler(state=Form.waiting_for_gender)
def process_gender(event: types.Message, state: FSMContext):
    if event.message.text not in GENDERS:
        return event.reply('Bad gender name. Choose your gender from the keyboard.')

    state.update_data(gender=event.message.text)
    user_data = state.get_data()
    event.answer(f'Hi! Nice to meet you, {user_data["name"]}\n'
                 f'Age: {user_data["age"]}\n'
                 f'Gender: {user_data["gender"]}', keyboard=RemoveReplyMarkup)
    Form.finish()


if __name__ == '__main__':
    dp.start_polling(debug=True)

Примечание

Чтобы каждый раз не писать FSMContext.get_current(), можно передать аргумент state: FSMContext в функцию-обработчик.

Чтобы отлавливать состояние, передаётся аргумент state для message_handler

API#

Indices and tables#