Структура проекта бота
├── LICENSE
├── README.md
├── data
│ ├── configs
│ │ ├── custom.toml
│ │ ├── deploy.toml
│ │ ├── dev.toml
│ │ ├── docs.toml
│ │ └── tests.toml
│ ├── logs
│ │ ├── annotype.log
│ │ ├── api.log
│ │ ├── longpoll.log
│ │ ├── reaction.log
│ │ └── validator.log
│ └── patterns
│ ├── annotype.txt
│ ├── reaction.txt
│ ├── signal.txt
│ └── validator.txt
├── docs
├── src
│ ├── annotypes
│ ├── event_handlers
│ ├── signal_handlers
│ └── validators
└── tests
├── test_annotypes
├── test_event_handlers
├── test_signal_handlers
└── test_validators
Я не очень в курсе, как обычно содежат логи, поэтому если есть какое-то решение лучше -- без проблем добавим его. Конфиги по своей структуре тоже под вопросом.
Нейминг
Reaction
-> EventHandler
(EventsHandler
?)
Signal
-> SignalHandler
Photo
-> PhotoUploader
(Делать отдельный класс для работы с полями пришедшего объекта от вк)
Doc
-> DocumentUploader
rexp
. Может regex
?
VkErr
-> APIError
/ VKAPIError
/ VkApiError
Изменения
- Немного уже обсудили аннотипы, но все-таки по мне все выглядит очень громоздко, в частности
BuildType
, WordType
и все ..Type
. Честно, не вижу смысла в замене круглых скобок на квадратных и введении более "композиционного" стиля. Да, подвязать typing.List
и билдиновский лист и что-то подобное не только для листа это круто, но я думаю это можно сделать не ввязывая Type'ы для более детальной настройки. Однако, у меня есть одна мысль на этот счет. Я думаю, ты видел, как описывается терминальный инструмент через click
-- все флаги через декораторы, а дальше это уже падает в аргументы. И нагромождений нет, и расписать можно. Может, вот такие "детальные" настройки, по типу количества элементов выносить в декоратор? Но декораторы уже забиты под валидаторы...
Мы как-то уже обсуждали гибкость аннотипов и пришли к тому, что нужно лишь несколько типов:
- List(...)
- Integer
- Word
- String
- Literal
- Разного рода упоминания
- Optional
- GroupedList, он же список с туплами
- Кастомный регекс на самый крайний случай
- Возможно что-то с временем и датой, но тут очень тонко
Возможно, мы что-то упустили, но команды бота -- это не bash, поэтому нужна ли им такая гибкость с билд типами и расширенными типами, или же можно просто обойтись аннотациями, какие они есть сейчас? (Я согласен на изменения логики внутри, меня не выткает именно использвоание)
-
Сейчас событие (vq.tools.event.Event
) -- это просто унаследованный от AttrMap
класс. Поскольку для v1.0 планируется добавление новых механик получения событий (в частности и возможность юзер ботов), было бы неплохо добавить общие методы по получение каких-то "межсобытийных" полей. Например, для сообщества (лп или кб событие) текст сообщения с версией 5.103
и выше будет event.object.message.text
, для ниже 5.103
event.object.text
, для пользователя вообще event[5]
. Поэтому для получения текста можно добавить метод, например, get_text()
, который бы рассматривал каждый кейс и получал текст сообщения в зависимости от события. И так с peer_id
, from_id
(здесь уже придется делать API запрос для юзерского лп) и другими полями. Для некоторых кейсов это даст универсальность написания ботов, которые будут совместимы как и с аккаунтом пользователя, так и сообщества, причем под апи разных версий. Как бы это странно не было, но юзер боты действительно пользуются популярностью, поэтому постараться сделать для них почти одинаковый интерфейс очень хорошая мысль.
-
Скорее всего bot
будет переделан с click
на cleo
, имхо, стиль гораздо удобнее
-
Убрать ReactionList
и SignalsList
вообще, а всю логику перенести в Bot
. Лишнее нагромождение.
-
Нужна ли поддержка своего стиля написания бота? Я боюсь, что если пользователю один раз показать, как делать бота в 1 файле -- он и будет делать его в 1 файле, вообще забивая на рефакторинг (что сейчас происходит в vk_api, vk.py, vkbottle, vkwave и во всех библиотеках)
-
Сущесвтует несколько оберток для вк апишных объектов (структура пользователя, структура фотографии, документа...). Все они немного похожи, поэтому, возможно, стоит задать им общий интерфейc.
-
Сейчас мне не очень нравится то, как выглядит загрузка фотографий и документов. Не только изнутри, но и внешне. Сама загрузка через апи (сырая) происходит в 3 этапа
- Получение урла сервера, куда отправить запрос
- Отправление фотографии/документа на этот урл
- Сохранение через определенный апишный метод
2ой пункт полностью автоматизированный. Для 1ого и 3ьего можно передать некоторые параметры при запросе. Из этого можно составить примерную схему всей загрузки (уже используемую)
- Инициализация объекта по байтами/пути до файла/скачиванию по урлу/BytesIO/TextIOWrapper/ все, что возможно. Очевидно, что кажадя инициализация будет через свой статический метод
- Загрузка (передача параметров для метода при загрузке)
- Сохранение (передача параметров для метода при сохранении)
Либо объеденить 2ой и третий и запрашивать словарь парамтеров (если такое надо) на каждый из способов. Что-то в этом роде
photo = PhotoUploader.from_bytes(b'123')
await photo.upload_and_save.to_message(
{"peer_id": 123}, {"name": "foo"}
)
...
return vq.Message(attachment=photo)
Можно не мучать точки и передать путь загрузки на 2ом этапе,
photo = PhotoUploader.from_bytes(
b'123',
)
await photo.upload_and_save(
"message", # PhotoUploadPath.TO_MESSAGE ???
{"peer_id": 123}, {"name": "foo"}
)
Либо разбить на 3 этапа (можно оставить поддержку 2х способов)
photo = PhotoUploader.from_bytes(b'123',)
photo.upload_path = PhotoUploadPath.TO_MESSAGE
await photo.upload(peer_id=123)
await photo.save(name="foo")
Должен ли photo
сам стать объектом (используя мутабельность) -- или он вернет уже другой объект? Наверно, это две разные вещи, поэтому переменные нужно будет перебиндить
photo = PhotoUploader.from_bytes(
b'123',
)
# Вместо `await photo.upload_and_save(...`
photo = await photo.upload_and_save(
"message",
{"peer_id": 123}, {"name": "foo"}
)
Возможно, есть какие-то уже готовые инструменты, чтобы можно было обернуть байты/байтсио/что-угодно и получить сами байты.
-
В новой версии доки (стиль сайта будет тот же, старая уедет в отдельный раздел) хотелось бы четко разделить документацию от туториала. Я посмотрел инструменты, которые могут по сурсам сделать .md странички как документацию, но ничего толкового не нашел (не отрицаю, что плохо искал). Возможно, это тема уже нового проекта
-
Хачю пользователскую доку к боту на mkdocs material, как и дока vkquick
-
Как проекту бота работать с зависимостями? Просто вести requirements.txt или же вносить poetry? Или это уже забота пользвоателя?
-
Касательно того, как могут проходить тестирования. Сначала тесты нужно забилдить (построются файлы по сурсам). После чего можно будет эмулировать вызовы (используя параметрайз, естесна), куда будет "инъекцироваться" свое собственное собранное событие, идентичное вкшному (о нем чуть ниже). В ответ на эмуляцию вызова будет прилетать объект, описывающий вообще все, что приключилось внутри.
# Используя старый нейминг
import vkquick as vq
@vq.Cmd(names=["foo"])
@vq.Reaction("message_new")
async def foo(sender: vq.Sender()):
await api.some.method(param=1)
...
И где-то в тестах ты эмулируешь вызов с разными собыйтиями, на что получаешь такую схему:
{
"all_validators_passed": True,
"actions": { # Вызов апи, запросы к бд, еще что-нибудь, что происходит внутри реакции
"api_calling": [ # Все ретурны и илды также расцениваются как вызов апи метода
{
"method_name": "some.method",
"parameters": {
"param": 1
}
}
],
}
"arguments": {
"sender": <vq.Sender object at /dev/null lalala>
}
# Либо
# "arguments": [
# {
# "argument_name": "sender",
# "content": <vq.Sender object at /dev/null lalala>
# }
# ]
}
Как добавлять свои actions
? Либо оборачивать нужный класс/функцию специальной оберткой, либо хз. Честно. Но если придумать, как создавать свои штукенции для actions
, можно будет обеспечить шедевральную тестируемость, полностью совместимую с возможностями питеста.
Откуда брать события, которыми эмулируется вызов? Было бы круто, если бы vkquick сам записывал все события вызова команды, а потом сам предлагал на выбор какое-либо из них, а там уже, если надо, поля можно будет поменять под свои данные.