mirror of
https://gitflic.ru/project/alt-gnome/karkas.git
synced 2024-12-23 16:23:02 +03:00
Merged with feat/config-module
This commit is contained in:
parent
eecc59ca94
commit
e2f5e8daba
5
.gitignore
vendored
5
.gitignore
vendored
@ -6,6 +6,5 @@ env
|
|||||||
venv
|
venv
|
||||||
__pycache__
|
__pycache__
|
||||||
OCAB.db
|
OCAB.db
|
||||||
src/paths.json
|
config.yaml
|
||||||
src/ocab_core/config.yaml
|
dist
|
||||||
src/ocab_core/log/**/*
|
|
||||||
|
7
.mailmap
Normal file
7
.mailmap
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
armatik <s.fomchenkov@yandex.ru> <57626821+armatik@users.noreply.github.com>
|
||||||
|
armatik <s.fomchenkov@yandex.ru> <57626821+Armatik@users.noreply.github.com>
|
||||||
|
armatik <s.fomchenkov@yandex.ru> Armatik <s.fomchenkov@yandex.ru>
|
||||||
|
|
||||||
|
ilyazheprog <ilyazheprog@gmail.com> <ilya_zhenetskij@vk.com>
|
||||||
|
|
||||||
|
Maxim Slipenko <maxim@slipenko.com> Максим Слипенко <maxim@slipenko.com>
|
80
README.md
80
README.md
@ -1,60 +1,44 @@
|
|||||||
# OpenChatAiBot V2
|
# OCAB - Open Chat Ai Bot
|
||||||
|
|
||||||
## Что такое OCAB?
|
## Что такое OCAB?
|
||||||
|
|
||||||
OCAB - это бот для Telegram, который призван помочь во взаимодействии с чатом.
|
OCAB - это платформа для разработки модульных Telegram-ботов, которая призвана упростить взаимодействие с чатами.
|
||||||
Бот поддерживает интеграцию модулей для расширения функционала.
|
OCAB предоставляет возможность расширять функциональность бота с помощью интеграции различных модулей.
|
||||||
Фактически бот является платформой для запуска созданных для него модулей.
|
Код платформы и набор стандартных модулей находятся в этом монорепозитории.
|
||||||
Модули могут взаимодействовать друг с другом или быть полностью независимыми.
|
|
||||||
|
|
||||||
## Что такое модуль?
|
## Структура монорепозитория
|
||||||
|
|
||||||
Модуль - это директория, которая содержит в себе код модуля и его конфигурацию.
|
Монорепозиторий OCAB включает в себя:
|
||||||
|
* **Ядро OCAB (src/ocab_core):** Содержит основные компоненты платформы, такие как система управления модулями,
|
||||||
|
логирование и утилиты.
|
||||||
|
* **Модули OCAB (src/ocab_modules):** Содержит стандартные и дополнительные модули, которые расширяют
|
||||||
|
функциональность ботов OCAB.
|
||||||
|
* **Пример бота (src/gnomik):** Пример реализации бота на платформе OCAB.
|
||||||
|
|
||||||
|
## Модули
|
||||||
|
|
||||||
|
Модули OCAB - это независимые компоненты, которые добавляют функциональность к боту.
|
||||||
|
|
||||||
### Структура модуля
|
### Структура модуля
|
||||||
|
|
||||||
*Будет дополнено после закрытия [issue #17](https://gitflic.ru/project/armatik/ocab/issue/17).*
|
Структура модуля представлена [здесь](docs/MODULES-SPEC.md).
|
||||||
|
|
||||||
## Стандартные модули
|
### Стандартные модули
|
||||||
|
|
||||||
В стандартный состав бота входят следующие модули:
|
Стандартные модули предоставляют базовые функции для работы бота:
|
||||||
|
* [admin](src/ocab_modules/ocab_modules/standard/admin/README.md) - модуль для модерирования чата.
|
||||||
|
* [roles](src/ocab_modules/ocab_modules/standard/roles/README.md) - модуль ролей пользователей.
|
||||||
|
* [config](src/ocab_modules/ocab_modules/standard/config/README.md) - модуль управления конфигурацией бота.
|
||||||
|
* [database](src/ocab_modules/ocab_modules/standard/database/README.md) - модуль для работы с базой данных.
|
||||||
|
* [fsm_database_storage](src/ocab_modules/ocab_modules/standard/fsm_database_storage/README.md) - модуль для хранения состояний FSM в базе данных.
|
||||||
|
* [filters](src/ocab_modules/ocab_modules/standard/filters/README.md) - модуль, предоставляющий фильтры для aiogram.
|
||||||
|
* [message_processing](src/ocab_modules/ocab_modules/standard/message_processing/README.md) - модуль обработки входящих сообщений.
|
||||||
|
* [miniapp](src/ocab_modules/ocab_modules/standard/miniapp/README.md) - модуль для реализации веб-интерфейса бота.
|
||||||
|
* [command_helper](src/ocab_modules/ocab_modules/standard/command_helper/README.md) - модуль для упрощения регистрации команд бота.
|
||||||
|
* [info](src/ocab_modules/ocab_modules/standard/info/README.md) - модуль предоставления информации о пользователях и чатах.
|
||||||
|
|
||||||
* `admin` - модуль для модерирования чата. Позволяет удалять сообщения, банить пользователей и т.д.
|
### Дополнительные официальные модули
|
||||||
* `reputation` - модуль репутации пользователей. Позволяет оценивать ответы пользователей и накапливать репутацию.
|
|
||||||
* `welcome` - модуль приветствия новых пользователей. Позволяет приветствовать новых пользователей в чате, а также
|
|
||||||
проверять пользователя капчей для предотвращения спама.
|
|
||||||
* `roles` - модуль ролей. Позволяет назначать пользователям роли и ограничивать доступ к командам бота по ролям.
|
|
||||||
Является важной частью системы прав доступа и модуля `admin`.
|
|
||||||
|
|
||||||
## Дополнительные официальные модули
|
Дополнительные официальные модули разработаны командой OCAB и предоставляют расширенные возможности для бота:
|
||||||
|
* [yandexgpt](src/ocab_modules/ocab_modules/external/yandexgpt/README.md) - модуль для интеграции с нейросетью YandexGPT.
|
||||||
* `yandexgpt` - модуль для генерации ответов на основе нейросети GPT-3.5. Позволяет боту отвечать на сообщения
|
* [create_report_apps](src/ocab_modules/ocab_modules/external/create_report_apps/README.md) - модуль для создания отчетов об ошибках.
|
||||||
пользователей, используя нейросеть. Ключевой особенностью является построение линии контекста для нейросети,
|
|
||||||
которая позволяет боту отвечать на вопросы, используя контекст предыдущих сообщений. Для этого используется
|
|
||||||
модуль база данных хранящий историю сообщений.
|
|
||||||
<!--
|
|
||||||
* `bugzilla` - модуль для интеграции с BugZilla. Позволяет получать уведомления о новых багах в BugZilla, отслеживать их
|
|
||||||
статус, формировать стандартизированные сообщения для корректного описания багов. В будущем планируется интеграция с
|
|
||||||
API BugZilla для возможности создания багов из чата.
|
|
||||||
* `alt_packages` - модуль для интеграции с AltLinux Packages. Позволяет получать уведомления о новых пакетах в репозитории
|
|
||||||
AltLinux, поиска пакетов по названию, получения истории изменений, команды для установки пакета из репозитория и
|
|
||||||
прочей информации о пакете.
|
|
||||||
* `notes` - модуль заметок. Позволяет сохранять заметки для пользователей и чатов. Заметки являются ссылками на
|
|
||||||
сообщения в чате.
|
|
||||||
-->
|
|
||||||
|
|
||||||
Список модулей будет пополняться. Идеи для модулей можно оставлять в [issues](https://gitflic.ru/project/armatik/ocab/issue/create).
|
|
||||||
|
|
||||||
## Установка бота
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
### Вручную
|
|
||||||
|
|
||||||
## Технологический стек
|
|
||||||
|
|
||||||
* Python 3.11.6 или выше - основной язык программирования.
|
|
||||||
* SQLite 3 - база данных для хранения информации о чате и пользователях.
|
|
||||||
* [Poetry](https://gitflic.ru/project/armatik/ocab/blob?file=how-to%20install%20deps.md&branch=OCAB-V2) - менеджер зависимостей.
|
|
||||||
* aiogram 3 - библиотека для работы с Telegram API.
|
|
||||||
* peewee - ORM для работы с базой данных.
|
|
||||||
|
39
docs/DEV.md
Normal file
39
docs/DEV.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
## Настройка рабочего окружения
|
||||||
|
|
||||||
|
Данная инструкция поможет вам настроить рабочее окружение для разработки OCAB.
|
||||||
|
|
||||||
|
### Предварительные требования
|
||||||
|
|
||||||
|
* **Python 3.12:** OCAB требует Python 3.12.
|
||||||
|
* **VSCode:** Рекомендуется использовать VSCode для разработки.
|
||||||
|
* **Git:** У вас должен быть установлен Git для клонирования репозитория.
|
||||||
|
|
||||||
|
### Шаги
|
||||||
|
|
||||||
|
1. **Клонируйте репозиторий:**
|
||||||
|
```bash
|
||||||
|
git clone https://gitflic.ru/project/armatik/ocab.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Откройте проект в VSCode:**
|
||||||
|
* Откройте папку `ocab` в VSCode.
|
||||||
|
* VSCode автоматически предложит открыть проект как workspace, используя файл `ocab.code-workspace`.
|
||||||
|
Нажмите "Открыть Workspace", чтобы принять предложение.
|
||||||
|
|
||||||
|
3. **Настройте Poetry:**
|
||||||
|
* Установите Poetry, следуя инструкциям на официальном сайте: [https://python-poetry.org/docs/](https://python-poetry.org/docs/).
|
||||||
|
* **Для каждого пакета:**
|
||||||
|
* Перейдите в папку пакета (например, `src/ocab_core`).
|
||||||
|
* Выполните команду `poetry install`, чтобы установить зависимости пакета.
|
||||||
|
* Poetry создаст виртуальное окружение внутри папки пакета (`.venv`).
|
||||||
|
|
||||||
|
4. **Активируйте виртуальное окружение:**
|
||||||
|
* Выполните команду `poetry shell` в папке пакета, чтобы активировать виртуальное окружение.
|
||||||
|
|
||||||
|
Теперь ваше рабочее окружение настроено, и вы можете начать.
|
||||||
|
|
||||||
|
### Дополнительная информация
|
||||||
|
|
||||||
|
* Каждый пакет в монорепозитории имеет свой собственный файл `pyproject.toml`, где указаны его зависимости.
|
||||||
|
* Poetry автоматически управляет виртуальными окружениями для каждого пакета.
|
||||||
|
* Вы можете использовать команду `poetry add <package_name>` для добавления новых зависимостей.
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## Метаинформация о модуле (info.json)
|
## Метаинформация о модуле (info.json)
|
||||||
|
|
||||||
Этот файл содержит метаинформацию о модуле в формате JSON. Пример структуры info.json приведён ниже:
|
Этот файл содержит метаинформацию о модуле в формате JSON. Пример структуры info.json приведен ниже:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -20,8 +20,26 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"privileged": false,
|
"privileged": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"required": {
|
||||||
"standard.roles": "^1.0.0",
|
"standard.roles": "^1.0.0",
|
||||||
"standard.database": "^1.0.0"
|
"standard.database": {
|
||||||
|
"version": "^1.0.0",
|
||||||
|
"uses": [
|
||||||
|
"db_api"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"external.yandexgpt": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pythonDependencies": {
|
||||||
|
"required": {
|
||||||
|
"some_package": "^1.2.3"
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"another_package": "*"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -30,31 +48,60 @@
|
|||||||
- `name`: Название модуля.
|
- `name`: Название модуля.
|
||||||
- `description`: Описание функциональности модуля.
|
- `description`: Описание функциональности модуля.
|
||||||
- `author`: Автор модуля.
|
- `author`: Автор модуля.
|
||||||
- `version`: Версия модуля.
|
- `version`: Версия модуля в формате [SemVer](https://semver.org/).
|
||||||
- `privileged`: Булево значение, указывающее, является ли модуль привилегированным.
|
- `privileged`: Булево значение, указывающее, является ли модуль привилегированным.
|
||||||
- `dependencies`: Объект, описывающий зависимости модуля от других модулей с указанием версии.
|
- `dependencies`: Объект, описывающий зависимости модуля от других **OCAB** модулей.
|
||||||
|
- `required`: Обязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`.
|
||||||
|
- `optional`: Необязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`.
|
||||||
|
- `pythonDependencies`: Объект, описывающий зависимости модуля от внешних Python пакетов.
|
||||||
|
- `required`: Обязательные зависимости. Ключ - название пакета, значение - версия.
|
||||||
|
- `optional`: Необязательные зависимости. Ключ - название пакета, значение - версия.
|
||||||
|
|
||||||
|
### DependencyInfo
|
||||||
|
|
||||||
|
Объект `DependencyInfo` позволяет указать не только версию зависимости, но и список разрешенных к использованию
|
||||||
|
атрибутов модуля (`uses`). Если `uses` не указан, то доступ к модулю целиком запрещен.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "^1.0.0",
|
||||||
|
"uses": [
|
||||||
|
"db_api"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `version`: Версия модуля.
|
||||||
|
- `uses`: Список разрешенных атрибутов модуля.
|
||||||
|
|
||||||
## Режимы выполнения модулей
|
## Режимы выполнения модулей
|
||||||
|
|
||||||
Непривилегированный режим (`privileged: false`):
|
**Непривилегированный режим** (`privileged: false`):
|
||||||
- Модуль выполняется в доверенной среде на основе RestrictedPython (это накладывает ряд ограничений);
|
- Модуль выполняется в доверенной среде на основе RestrictedPython (это накладывает ряд ограничений).
|
||||||
- Может использовать только определенный набор разрешенных пакетов
|
- Может импортировать только явно разрешенные модули, указанные в `pythonDependencies`,
|
||||||
|
а также несколько стандартных модулей, необходимых для работы.
|
||||||
- Имеет доступ к пакету `ocab_core.modules_system.public_api` для взаимодействия с ботом.
|
- Имеет доступ к пакету `ocab_core.modules_system.public_api` для взаимодействия с ботом.
|
||||||
|
|
||||||
Привилегированный режим (`privileged: true`):
|
**Привилегированный режим** (`privileged: true`):
|
||||||
- Модуль выполняется без ограничений.
|
- Модуль выполняется без ограничений.
|
||||||
- Имеет полный доступ ко всем пакетам.
|
- Имеет полный доступ ко всем пакетам, доступным в окружении.
|
||||||
- Должен использоваться с осторожностью и только для модулей, требующих расширенных прав.
|
- Должен использоваться с осторожностью и только для модулей, требующих расширенных прав.
|
||||||
|
|
||||||
## Жизненный цикл модуля
|
## Жизненный цикл модуля
|
||||||
|
|
||||||
1. Загрузка метаданных из `info.json`
|
1. Загрузка метаданных из `info.json`.
|
||||||
2. Проверка зависимостей
|
2. Проверка зависимостей:
|
||||||
3. Загрузка кода модуля из `__init__.py`
|
- Проверяется наличие всех обязательных зависимостей.
|
||||||
4. Вызов функции `module_init` (если она есть)
|
- Проверяется совместимость версий зависимостей.
|
||||||
|
- Проверяется наличие Python зависимостей.
|
||||||
|
3. Загрузка кода модуля из `__init__.py`.
|
||||||
|
4. Вызов функции `module_init` (если она есть).
|
||||||
|
5. После загрузки всех модулей вызывается функция `module_late_init` (если она есть).
|
||||||
|
|
||||||
## Взаимодействие между модулями
|
## Взаимодействие между модулями
|
||||||
|
|
||||||
Модули могут взаимодействовать друг с другом через [API](../src/ocab_core/modules_system/public_api/__init__.py), предоставляемое системой управления модулями.
|
Модули могут взаимодействовать друг с другом через [API](../src/ocab_core/ocab_core/modules_system/public_api/__init__.py),
|
||||||
|
предоставляемое системой управления модулями.
|
||||||
|
|
||||||
Например, есть функция `get_module`. Она позволяет получить модуль или предоставляемые им объекты по его идентификатору.
|
Например, есть функция `get_module`. Она позволяет получить модуль или предоставляемые им объекты по его
|
||||||
|
идентификатору.
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
## Poetry
|
|
||||||
|
|
||||||
### Установка с официального сайта
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl -sSL https://install.python-poetry.org | python3 -
|
|
||||||
```
|
|
||||||
|
|
||||||
### Установка с PyPi
|
|
||||||
|
|
||||||
```shell
|
|
||||||
python3 -m pip install poetry
|
|
||||||
```
|
|
||||||
|
|
||||||
Доп информация:https://www.8host.com/blog/ustanovka-menedzhera-zavisimostej-poetry/
|
|
||||||
|
|
||||||
## Зависимости
|
|
||||||
|
|
||||||
### Добавление зависимости
|
|
||||||
```shell
|
|
||||||
poetry add NAME
|
|
||||||
```
|
|
||||||
`NAME` - название зависимости.
|
|
||||||
|
|
||||||
### Установка зависимостей
|
|
||||||
```shell
|
|
||||||
poetry install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Обновление зависимостей
|
|
||||||
```shell
|
|
||||||
poetry update
|
|
||||||
```
|
|
||||||
|
|
||||||
## Виртуальное окружение
|
|
||||||
|
|
||||||
### Создание/активация
|
|
||||||
```shell
|
|
||||||
poetry shell
|
|
||||||
```
|
|
||||||
|
|
||||||
### Настройка
|
|
||||||
|
|
||||||
Хранить окружение внутри проекта
|
|
||||||
```shell
|
|
||||||
poetry config virtualenvs.in-project true
|
|
||||||
```
|
|
25
ocab.code-workspace
Normal file
25
ocab.code-workspace
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"name": "OCAB Monorepo Root",
|
||||||
|
"path": ".",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OCAB Modules",
|
||||||
|
"path": "src/ocab_modules"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OCAB Core",
|
||||||
|
"path": "src/ocab_core"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gnomik",
|
||||||
|
"path": "src/gnomik"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensions": {
|
||||||
|
"recommendations": [
|
||||||
|
"ms-python.python"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
850
poetry.lock
generated
850
poetry.lock
generated
@ -1,185 +1,5 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiofiles"
|
|
||||||
version = "23.2.1"
|
|
||||||
description = "File support for asyncio."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"},
|
|
||||||
{file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiogram"
|
|
||||||
version = "3.10.0"
|
|
||||||
description = "Modern and fully asynchronous framework for Telegram Bot API"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "aiogram-3.10.0-py3-none-any.whl", hash = "sha256:dc43bfbe68c736cca48d91ffbc55a397df24b56c332206af850965619689beca"},
|
|
||||||
{file = "aiogram-3.10.0.tar.gz", hash = "sha256:f500d4b309e3cc08a87ae5a053b229199034f382925de00aa2ed005d5e25d575"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
aiofiles = ">=23.2.1,<23.3.0"
|
|
||||||
aiohttp = ">=3.9.0,<3.10.0"
|
|
||||||
certifi = ">=2023.7.22"
|
|
||||||
magic-filter = ">=1.0.12,<1.1"
|
|
||||||
pydantic = ">=2.4.1,<2.9"
|
|
||||||
typing-extensions = ">=4.7.0,<=5.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
cli = ["aiogram-cli (>=1.0.3,<1.1.0)"]
|
|
||||||
dev = ["black (>=24.4.2,<24.5.0)", "isort (>=5.13.2,<5.14.0)", "motor-types (>=1.0.0b4,<1.1.0)", "mypy (>=1.10.0,<1.11.0)", "packaging (>=24.1,<25.0)", "pre-commit (>=3.5,<4.0)", "ruff (>=0.4.9,<0.5.0)", "toml (>=0.10.2,<0.11.0)"]
|
|
||||||
docs = ["furo (>=2023.9.10,<2023.10.0)", "markdown-include (>=0.8.1,<0.9.0)", "pygments (>=2.16.1,<2.17.0)", "pymdown-extensions (>=10.3,<11.0)", "sphinx (>=7.2.6,<7.3.0)", "sphinx-autobuild (>=2021.3.14,<2021.4.0)", "sphinx-copybutton (>=0.5.2,<0.6.0)", "sphinx-intl (>=2.1.0,<2.2.0)", "sphinx-substitution-extensions (>=2022.2.16,<2022.3.0)", "sphinxcontrib-towncrier (>=0.3.2a0,<0.4.0)", "towncrier (>=23.6.0,<23.7.0)"]
|
|
||||||
fast = ["aiodns (>=3.0.0)", "uvloop (>=0.17.0)"]
|
|
||||||
i18n = ["babel (>=2.13.0,<2.14.0)"]
|
|
||||||
mongo = ["motor (>=3.3.2,<3.4.0)"]
|
|
||||||
proxy = ["aiohttp-socks (>=0.8.3,<0.9.0)"]
|
|
||||||
redis = ["redis[hiredis] (>=5.0.1,<5.1.0)"]
|
|
||||||
test = ["aresponses (>=2.1.6,<2.2.0)", "pycryptodomex (>=3.19.0,<3.20.0)", "pytest (>=7.4.2,<7.5.0)", "pytest-aiohttp (>=1.0.5,<1.1.0)", "pytest-asyncio (>=0.21.1,<0.22.0)", "pytest-cov (>=4.1.0,<4.2.0)", "pytest-html (>=4.0.2,<4.1.0)", "pytest-lazy-fixture (>=0.6.3,<0.7.0)", "pytest-mock (>=3.12.0,<3.13.0)", "pytest-mypy (>=0.10.3,<0.11.0)", "pytz (>=2023.3,<2024.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiohttp"
|
|
||||||
version = "3.9.5"
|
|
||||||
description = "Async http client/server framework (asyncio)"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"},
|
|
||||||
{file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"},
|
|
||||||
{file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"},
|
|
||||||
{file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"},
|
|
||||||
{file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"},
|
|
||||||
{file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"},
|
|
||||||
{file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
aiosignal = ">=1.1.2"
|
|
||||||
attrs = ">=17.3.0"
|
|
||||||
frozenlist = ">=1.1.1"
|
|
||||||
multidict = ">=4.5,<7.0"
|
|
||||||
yarl = ">=1.0,<2.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
speedups = ["Brotli", "aiodns", "brotlicffi"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aiosignal"
|
|
||||||
version = "1.3.1"
|
|
||||||
description = "aiosignal: a list of registered asynchronous callbacks"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
|
|
||||||
{file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
frozenlist = ">=1.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "annotated-types"
|
|
||||||
version = "0.7.0"
|
|
||||||
description = "Reusable constraint types to use with typing.Annotated"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
|
|
||||||
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "attrs"
|
|
||||||
version = "23.2.0"
|
|
||||||
description = "Classes Without Boilerplate"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
|
|
||||||
{file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
|
|
||||||
dev = ["attrs[tests]", "pre-commit"]
|
|
||||||
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
|
|
||||||
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
|
||||||
tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
|
|
||||||
tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bandit"
|
name = "bandit"
|
||||||
version = "1.7.9"
|
version = "1.7.9"
|
||||||
@ -248,17 +68,6 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
|||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "certifi"
|
|
||||||
version = "2024.7.4"
|
|
||||||
description = "Python package for providing Mozilla's CA Bundle."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
|
|
||||||
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfgv"
|
name = "cfgv"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
@ -270,105 +79,6 @@ files = [
|
|||||||
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "charset-normalizer"
|
|
||||||
version = "3.3.2"
|
|
||||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7.0"
|
|
||||||
files = [
|
|
||||||
{file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
|
|
||||||
{file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
|
|
||||||
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
@ -394,21 +104,6 @@ files = [
|
|||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dataclasses-json"
|
|
||||||
version = "0.6.7"
|
|
||||||
description = "Easily serialize dataclasses to and from JSON."
|
|
||||||
optional = false
|
|
||||||
python-versions = "<4.0,>=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"},
|
|
||||||
{file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
marshmallow = ">=3.18.0,<4.0.0"
|
|
||||||
typing-inspect = ">=0.4.0,<1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "distlib"
|
name = "distlib"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@ -452,92 +147,6 @@ mccabe = ">=0.7.0,<0.8.0"
|
|||||||
pycodestyle = ">=2.12.0,<2.13.0"
|
pycodestyle = ">=2.12.0,<2.13.0"
|
||||||
pyflakes = ">=3.2.0,<3.3.0"
|
pyflakes = ">=3.2.0,<3.3.0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "frozenlist"
|
|
||||||
version = "1.4.1"
|
|
||||||
description = "A list-like structure which implements collections.abc.MutableSequence"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"},
|
|
||||||
{file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"},
|
|
||||||
{file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"},
|
|
||||||
{file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"},
|
|
||||||
{file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"},
|
|
||||||
{file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"},
|
|
||||||
{file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"},
|
|
||||||
{file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identify"
|
name = "identify"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@ -552,17 +161,6 @@ files = [
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
license = ["ukkonen"]
|
license = ["ukkonen"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "3.7"
|
|
||||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
files = [
|
|
||||||
{file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
|
|
||||||
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "isort"
|
name = "isort"
|
||||||
version = "5.13.2"
|
version = "5.13.2"
|
||||||
@ -577,20 +175,6 @@ files = [
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
colors = ["colorama (>=0.4.6)"]
|
colors = ["colorama (>=0.4.6)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "magic-filter"
|
|
||||||
version = "1.0.12"
|
|
||||||
description = ""
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "magic_filter-1.0.12-py3-none-any.whl", hash = "sha256:e5929e544f310c2b1f154318db8c5cdf544dd658efa998172acd2e4ba0f6c6a6"},
|
|
||||||
{file = "magic_filter-1.0.12.tar.gz", hash = "sha256:4751d0b579a5045d1dc250625c4c508c18c3def5ea6afaf3957cb4530d03f7f9"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dev = ["black (>=22.8.0,<22.9.0)", "flake8 (>=5.0.4,<5.1.0)", "isort (>=5.11.5,<5.12.0)", "mypy (>=1.4.1,<1.5.0)", "pre-commit (>=2.20.0,<2.21.0)", "pytest (>=7.1.3,<7.2.0)", "pytest-cov (>=3.0.0,<3.1.0)", "pytest-html (>=3.1.1,<3.2.0)", "types-setuptools (>=65.3.0,<65.4.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown-it-py"
|
name = "markdown-it-py"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
@ -615,25 +199,6 @@ profiling = ["gprof2dot"]
|
|||||||
rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
|
rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
|
||||||
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
|
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "marshmallow"
|
|
||||||
version = "3.21.3"
|
|
||||||
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"},
|
|
||||||
{file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
packaging = ">=17.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"]
|
|
||||||
docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"]
|
|
||||||
tests = ["pytest", "pytz", "simplejson"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mccabe"
|
name = "mccabe"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -656,105 +221,6 @@ files = [
|
|||||||
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "multidict"
|
|
||||||
version = "6.0.5"
|
|
||||||
description = "multidict implementation"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"},
|
|
||||||
{file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"},
|
|
||||||
{file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"},
|
|
||||||
{file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"},
|
|
||||||
{file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"},
|
|
||||||
{file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"},
|
|
||||||
{file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"},
|
|
||||||
{file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"},
|
|
||||||
{file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy-extensions"
|
name = "mypy-extensions"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -810,16 +276,6 @@ files = [
|
|||||||
{file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"},
|
{file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "peewee"
|
|
||||||
version = "3.17.6"
|
|
||||||
description = "a little orm"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "peewee-3.17.6.tar.gz", hash = "sha256:cea5592c6f4da1592b7cff8eaf655be6648a1f5857469e30037bf920c03fb8fb"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "4.2.2"
|
version = "4.2.2"
|
||||||
@ -865,126 +321,6 @@ files = [
|
|||||||
{file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"},
|
{file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pydantic"
|
|
||||||
version = "2.8.2"
|
|
||||||
description = "Data validation using Python type hints"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"},
|
|
||||||
{file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
annotated-types = ">=0.4.0"
|
|
||||||
pydantic-core = "2.20.1"
|
|
||||||
typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
email = ["email-validator (>=2.0.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pydantic-core"
|
|
||||||
version = "2.20.1"
|
|
||||||
description = "Core functionality for Pydantic validation and serialization"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"},
|
|
||||||
{file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"},
|
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"},
|
|
||||||
{file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyflakes"
|
name = "pyflakes"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
@ -1070,42 +406,6 @@ files = [
|
|||||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "requests"
|
|
||||||
version = "2.32.3"
|
|
||||||
description = "Python HTTP for Humans."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
|
||||||
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
certifi = ">=2017.4.17"
|
|
||||||
charset-normalizer = ">=2,<4"
|
|
||||||
idna = ">=2.5,<4"
|
|
||||||
urllib3 = ">=1.21.1,<3"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
|
||||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "restrictedpython"
|
|
||||||
version = "7.1"
|
|
||||||
description = "RestrictedPython is a defined subset of the Python language which allows to provide a program input into a trusted environment."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7, <3.13"
|
|
||||||
files = [
|
|
||||||
{file = "RestrictedPython-7.1-py3-none-any.whl", hash = "sha256:56d0c73e5de1757702053383601b0fcd3fb2e428039ee1df860409ad67b17d2b"},
|
|
||||||
{file = "RestrictedPython-7.1.tar.gz", hash = "sha256:875aeb51c139d78e34cef8605dc65309b449168060dd08551a1fe9edb47cb9a5"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["Sphinx", "sphinx-rtd-theme"]
|
|
||||||
test = ["pytest", "pytest-mock"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "13.7.1"
|
version = "13.7.1"
|
||||||
@ -1149,49 +449,6 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typing-extensions"
|
|
||||||
version = "4.12.2"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
|
||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typing-inspect"
|
|
||||||
version = "0.9.0"
|
|
||||||
description = "Runtime inspection utilities for typing module."
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
|
|
||||||
{file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
mypy-extensions = ">=0.3.0"
|
|
||||||
typing-extensions = ">=3.7.4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "urllib3"
|
|
||||||
version = "2.2.2"
|
|
||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
|
|
||||||
{file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
|
||||||
h2 = ["h2 (>=4,<5)"]
|
|
||||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
|
||||||
zstd = ["zstandard (>=0.18.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtualenv"
|
name = "virtualenv"
|
||||||
version = "20.26.3"
|
version = "20.26.3"
|
||||||
@ -1212,110 +469,7 @@ platformdirs = ">=3.9.1,<5"
|
|||||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
||||||
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yarl"
|
|
||||||
version = "1.9.4"
|
|
||||||
description = "Yet another URL library"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"},
|
|
||||||
{file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"},
|
|
||||||
{file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"},
|
|
||||||
{file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"},
|
|
||||||
{file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"},
|
|
||||||
{file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"},
|
|
||||||
{file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"},
|
|
||||||
{file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"},
|
|
||||||
{file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
idna = ">=2.0"
|
|
||||||
multidict = ">=4.0"
|
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.11.6,<3.13"
|
python-versions = "~3.12"
|
||||||
content-hash = "5df07f0efc29d67f3ef2952b7d26a58098c16d5a391f469258f91ba47ebb972f"
|
content-hash = "7db42302f410e90c105f188f32680864d9268137049af500f4221e69b4f9cc7f"
|
||||||
|
2
poetry.toml
Normal file
2
poetry.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
@ -1,6 +1,5 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
package-mode = false
|
name = "ocab-monorepo"
|
||||||
name = "ocab"
|
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
description = "OCAB is a modular Telegram bot"
|
description = "OCAB is a modular Telegram bot"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
@ -13,7 +12,9 @@ maintainers = [
|
|||||||
]
|
]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://gitflic.ru/project/armatik/ocab"
|
repository = "https://gitflic.ru/project/armatik/ocab"
|
||||||
packages = [{include = "scripts"}]
|
packages = [
|
||||||
|
{ include = "scripts" }
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry.urls]
|
[tool.poetry.urls]
|
||||||
"Bug Tracker" = "https://gitflic.ru/project/armatik/ocab/issue?status=OPEN"
|
"Bug Tracker" = "https://gitflic.ru/project/armatik/ocab/issue?status=OPEN"
|
||||||
@ -24,14 +25,7 @@ init = 'scripts.init:main'
|
|||||||
module = 'scripts.module:main'
|
module = 'scripts.module:main'
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.11.6,<3.13"
|
python = "~3.12"
|
||||||
aiogram = "^3.10.0"
|
|
||||||
peewee = "^3.17.6"
|
|
||||||
pyyaml = "^6.0.1"
|
|
||||||
requests = "^2.32.3"
|
|
||||||
restrictedpython = "^7.1"
|
|
||||||
dataclasses-json = "^0.6.7"
|
|
||||||
semver = "^3.0.2"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
flake8 = "^7.1.0"
|
flake8 = "^7.1.0"
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
import ocab_core
|
|
||||||
import service
|
|
23
src/gnomik/Dockerfile
Normal file
23
src/gnomik/Dockerfile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
FROM python:3.12-slim as builder
|
||||||
|
|
||||||
|
RUN pip install poetry
|
||||||
|
RUN mkdir -p /app
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
# Фикс
|
||||||
|
|
||||||
|
RUN sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/gnomik/pyproject.toml && \
|
||||||
|
sed -i '/ocab-modules = {/{s/, develop = true//}' /app/src/gnomik/pyproject.toml && \
|
||||||
|
sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/ocab_modules/pyproject.toml
|
||||||
|
|
||||||
|
WORKDIR /app/src/gnomik
|
||||||
|
|
||||||
|
RUN poetry lock && poetry install
|
||||||
|
|
||||||
|
FROM python:3.12-slim as base
|
||||||
|
|
||||||
|
COPY --from=builder /app/src/gnomik /app
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
|
CMD ["python", "-m", "gnomik"]
|
14
src/gnomik/Dockerfile.dockerignore
Normal file
14
src/gnomik/Dockerfile.dockerignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
**/Dockerfile
|
||||||
|
**/*.dockerignore
|
||||||
|
**/docker-compose.yml
|
||||||
|
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
|
||||||
|
**/.venv
|
||||||
|
|
||||||
|
**/.mypy_cache
|
||||||
|
**/__pycache__/
|
||||||
|
|
||||||
|
src/gnomik/config.yaml
|
||||||
|
src/gnomik/database/*
|
55
src/gnomik/README.md
Normal file
55
src/gnomik/README.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Gnomик
|
||||||
|
|
||||||
|
![Логотип](./docs/gnomik.jpg)
|
||||||
|
|
||||||
|
Чат-бот помощник в [ALT Gnome Chat](https://t.me/alt_gnome_chat).
|
||||||
|
|
||||||
|
|
||||||
|
ALT Regular Gnome Community - открытое сообщество пользователей операционной системы ALT Regular Gnome.
|
||||||
|
|
||||||
|
- [Канал](https://t.me/alt_gnome)
|
||||||
|
- [Wiki](https://alt-gnome.wiki)
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Gnomик - это чат-бот, разработанный на платформе Open Chat AI Bot (OCAB) для Telegram. Он предоставляет различные функции и возможности, помогающие пользователям операционной системы ALT Regular Gnome.
|
||||||
|
|
||||||
|
## Функционал
|
||||||
|
|
||||||
|
<!--
|
||||||
|
TODO: описать функционал
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
1. Соберите Docker-образ:
|
||||||
|
```bash
|
||||||
|
docker build -t gnomik .
|
||||||
|
```
|
||||||
|
2. Запустите контейнер:
|
||||||
|
```bash
|
||||||
|
docker run -p 9000:9000 -v ./config.yaml:/app/config.yaml -v ./database:/app/database gnomik
|
||||||
|
```
|
||||||
|
|
||||||
|
Замените `./config.yaml` и `./database` на пути к вашим локальным файлам конфигурации и паки для базы данных.
|
||||||
|
|
||||||
|
### Вручную
|
||||||
|
|
||||||
|
1. Активируйте виртуальное окружение Gnomика:
|
||||||
|
```bash
|
||||||
|
poetry shell
|
||||||
|
```
|
||||||
|
2. Запустите бота:
|
||||||
|
```bash
|
||||||
|
python -m gnomik
|
||||||
|
```
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
Конфигурация бота находится в файле `config.yaml`.
|
||||||
|
|
||||||
|
## Модули
|
||||||
|
|
||||||
|
Список загружаемых модулей указан в файле `__main__.py`.
|
18
src/gnomik/config-example.yaml
Normal file
18
src/gnomik/config-example.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
core:
|
||||||
|
mode: WEBHOOK
|
||||||
|
token: xxx
|
||||||
|
webhook:
|
||||||
|
public_url: xxx
|
||||||
|
filters:
|
||||||
|
approved_chat_id: -4128011756 | -4128011756
|
||||||
|
default_chat_tag: '@alt_gnome_chat'
|
||||||
|
miniapp:
|
||||||
|
public_url: xxx
|
||||||
|
yandexgpt:
|
||||||
|
catalogid: xxx
|
||||||
|
inword: помогите | не работает
|
||||||
|
prompt: Ты чат-бот ...
|
||||||
|
startword: Бот| Бот, | бот | бот,
|
||||||
|
token: xxx
|
||||||
|
token_for_answer: 2000
|
||||||
|
token_for_request: 8000
|
12
src/gnomik/docker-compose.yml
Normal file
12
src/gnomik/docker-compose.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: src/gnomik/Dockerfile
|
||||||
|
ports:
|
||||||
|
- 9000:9000
|
||||||
|
volumes:
|
||||||
|
- ./config.yaml:/app/config.yaml
|
||||||
|
- ./database:/app/database
|
BIN
src/gnomik/docs/gnomik.jpg
Normal file
BIN
src/gnomik/docs/gnomik.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
29
src/gnomik/gnomik/__main__.py
Normal file
29
src/gnomik/gnomik/__main__.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
from ocab_core import OCAB
|
||||||
|
from ocab_modules import module_loader
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
ocab = OCAB()
|
||||||
|
await ocab.init_app(
|
||||||
|
[
|
||||||
|
module_loader("standard", "config", safe=False),
|
||||||
|
module_loader("standard", "database", safe=False),
|
||||||
|
module_loader("standard", "fsm_database_storage", safe=False),
|
||||||
|
module_loader("standard", "roles", safe=False),
|
||||||
|
module_loader("external", "yandexgpt", safe=False),
|
||||||
|
#
|
||||||
|
module_loader("standard", "command_helper"),
|
||||||
|
module_loader("standard", "info"),
|
||||||
|
module_loader("standard", "filters"),
|
||||||
|
module_loader("external", "create_report_apps"),
|
||||||
|
module_loader("standard", "admin"),
|
||||||
|
module_loader("standard", "message_processing"),
|
||||||
|
module_loader("standard", "miniapp", safe=False),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
await ocab.start()
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
2162
src/gnomik/poetry.lock
generated
Normal file
2162
src/gnomik/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
src/gnomik/poetry.toml
Normal file
2
src/gnomik/poetry.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
15
src/gnomik/pyproject.toml
Normal file
15
src/gnomik/pyproject.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "gnomik"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Максим Слипенко <maxim@slipenko.com>"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "~3.12"
|
||||||
|
ocab-core = { extras=["webhook"], path = "../ocab_core", develop = true }
|
||||||
|
ocab-modules = { path = "../ocab_modules", develop = true }
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
23
src/ocab_core/README.md
Normal file
23
src/ocab_core/README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# OCAB Core
|
||||||
|
|
||||||
|
Это ядро OCAB, содержащее базовые компоненты:
|
||||||
|
|
||||||
|
- Система управления модулями.
|
||||||
|
- Логирование.
|
||||||
|
- Утилиты.
|
||||||
|
|
||||||
|
## Система управления модулями
|
||||||
|
|
||||||
|
Система управления модулями отвечает за:
|
||||||
|
|
||||||
|
- Загрузку модулей.
|
||||||
|
- Проверку зависимостей.
|
||||||
|
- Предоставление API для взаимодействия между модулями.
|
||||||
|
|
||||||
|
## Логирование
|
||||||
|
|
||||||
|
Модуль логирования предоставляет функции для записи логов в консоль.
|
||||||
|
|
||||||
|
## Утилиты
|
||||||
|
|
||||||
|
Модуль утилит содержит вспомогательные функции, например, для форматирования текста.
|
@ -1,21 +0,0 @@
|
|||||||
TELEGRAM:
|
|
||||||
TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
APPROVED_CHAT_ID: "-123456789 | -012345678"
|
|
||||||
ADMINCHATID: -12345678
|
|
||||||
DEFAULT_CHAT_TAG: "@alt_gnome_chat"
|
|
||||||
CHECK_BOT: True
|
|
||||||
|
|
||||||
YANDEXGPT:
|
|
||||||
TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
TOKEN_FOR_REQUEST: 8000
|
|
||||||
TOKEN_FOR_ANSWER: 2000
|
|
||||||
CATALOGID: xxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
PROMPT: "Ты чат-бот ..."
|
|
||||||
STARTWORD: "Бот| Бот, | бот | бот,"
|
|
||||||
INWORD: "помогите | не работает"
|
|
||||||
|
|
||||||
ROLES:
|
|
||||||
ADMIN: 2
|
|
||||||
MODERATOR: 1
|
|
||||||
USER: 0
|
|
||||||
BOT: 3
|
|
@ -1,29 +0,0 @@
|
|||||||
import logging
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
def setup_logger():
|
|
||||||
"""
|
|
||||||
Настройка логирования
|
|
||||||
"""
|
|
||||||
current_date = time.strftime("%d-%m-%Y")
|
|
||||||
log_dir = os.path.join(os.path.dirname(__file__), "log")
|
|
||||||
os.makedirs(log_dir, exist_ok=True)
|
|
||||||
log_file = os.path.join(log_dir, f"log-{current_date}.log")
|
|
||||||
|
|
||||||
logging.basicConfig(
|
|
||||||
filename=log_file,
|
|
||||||
level=logging.INFO,
|
|
||||||
format="%(asctime)s %(message)s",
|
|
||||||
datefmt="%H:%M:%S",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def log(message):
|
|
||||||
if isinstance(message, Exception):
|
|
||||||
error_message = f"Error: {str(message)}\n{traceback.format_exc()}"
|
|
||||||
logging.error(error_message)
|
|
||||||
else:
|
|
||||||
logging.info(message)
|
|
@ -1,61 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from aiogram import Bot, Dispatcher
|
|
||||||
|
|
||||||
from ocab_core.logger import log, setup_logger
|
|
||||||
from ocab_core.modules_system import ModulesManager
|
|
||||||
from ocab_core.modules_system.loaders import FSLoader
|
|
||||||
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
|
||||||
from ocab_core.singleton import Singleton
|
|
||||||
from ocab_modules.standard.config.config import get_telegram_token
|
|
||||||
from service import paths
|
|
||||||
|
|
||||||
bot_modules = [
|
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/config"),
|
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/database"),
|
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/fsm_database_storage"),
|
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/roles"),
|
|
||||||
UnsafeFSLoader(f"{paths.modules_external}/yandexgpt"),
|
|
||||||
FSLoader(f"{paths.modules_standard}/command_helper"),
|
|
||||||
FSLoader(f"{paths.modules_standard}/info"),
|
|
||||||
FSLoader(f"{paths.modules_standard}/filters"),
|
|
||||||
FSLoader(f"{paths.modules_external}/create_report_apps"),
|
|
||||||
FSLoader(f"{paths.modules_standard}/admin"),
|
|
||||||
FSLoader(f"{paths.modules_standard}/message_processing"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
bot = None
|
|
||||||
setup_logger()
|
|
||||||
|
|
||||||
app = Singleton()
|
|
||||||
|
|
||||||
try:
|
|
||||||
app.bot = Bot(token=get_telegram_token())
|
|
||||||
app.modules_manager = ModulesManager()
|
|
||||||
|
|
||||||
for module_loader in bot_modules:
|
|
||||||
info = module_loader.info()
|
|
||||||
log(f"Loading {info.name}({info.id}) module")
|
|
||||||
await app.modules_manager.load(module_loader)
|
|
||||||
|
|
||||||
app.dp = Dispatcher(storage=app.storage["_fsm_storage"])
|
|
||||||
|
|
||||||
app.dp.include_routers(*app.storage["_routers"])
|
|
||||||
|
|
||||||
for middleware in app.storage["_outer_message_middlewares"]:
|
|
||||||
app.dp.message.outer_middleware.register(middleware)
|
|
||||||
|
|
||||||
await app.modules_manager.late_init()
|
|
||||||
await app.dp.start_polling(app.bot)
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
finally:
|
|
||||||
if bot is not None:
|
|
||||||
await app.bot.session.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
asyncio.run(main())
|
|
@ -1 +0,0 @@
|
|||||||
from .fs_loader import FSLoader
|
|
@ -1,24 +0,0 @@
|
|||||||
import types
|
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
from dataclasses_json import dataclass_json
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass_json
|
|
||||||
@dataclass
|
|
||||||
class ModuleInfo:
|
|
||||||
id: str
|
|
||||||
name: str
|
|
||||||
description: str
|
|
||||||
version: str
|
|
||||||
author: str | list[str]
|
|
||||||
privileged: bool
|
|
||||||
dependencies: dict
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractLoader:
|
|
||||||
def info(self) -> ModuleInfo:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def load(self) -> types.ModuleType:
|
|
||||||
raise NotImplementedError
|
|
@ -1,85 +0,0 @@
|
|||||||
import semver
|
|
||||||
|
|
||||||
from ocab_core.modules_system.loaders.base import AbstractLoader
|
|
||||||
|
|
||||||
|
|
||||||
def is_version_compatible(version, requirement):
|
|
||||||
def parse_requirement(req):
|
|
||||||
if req.startswith("^"):
|
|
||||||
base_version = req[1:]
|
|
||||||
base_version_info = semver.VersionInfo.parse(base_version)
|
|
||||||
range_start = base_version_info
|
|
||||||
range_end = base_version_info.bump_major()
|
|
||||||
return [f">={range_start}", f"<{range_end}"]
|
|
||||||
else:
|
|
||||||
return [req]
|
|
||||||
|
|
||||||
for r in parse_requirement(requirement):
|
|
||||||
if not semver.Version.parse(version).match(r):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class ModulesManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.modules = []
|
|
||||||
|
|
||||||
async def load(self, loader: AbstractLoader):
|
|
||||||
info = loader.info()
|
|
||||||
|
|
||||||
# Check if the module is already loaded
|
|
||||||
if any(mod["info"].id == info.id for mod in self.modules):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Check dependencies
|
|
||||||
for dependency, version in info.dependencies.items():
|
|
||||||
loaded_dependency = next(
|
|
||||||
(mod for mod in self.modules if mod["info"].id == dependency), None
|
|
||||||
)
|
|
||||||
if not loaded_dependency:
|
|
||||||
raise Exception(
|
|
||||||
f"Module {info.id} depends on {dependency}, but it is not loaded"
|
|
||||||
)
|
|
||||||
loaded_dependency_info = loaded_dependency["info"]
|
|
||||||
if not is_version_compatible(loaded_dependency_info.version, version):
|
|
||||||
raise Exception(
|
|
||||||
f"Module {info.id} depends on {dependency}, "
|
|
||||||
f"but version {version} is not compatible"
|
|
||||||
)
|
|
||||||
|
|
||||||
module = loader.load()
|
|
||||||
|
|
||||||
self.modules.append(
|
|
||||||
{
|
|
||||||
"info": info,
|
|
||||||
"module": module,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if hasattr(module, "module_init"):
|
|
||||||
await module.module_init()
|
|
||||||
|
|
||||||
async def late_init(self):
|
|
||||||
for m in self.modules:
|
|
||||||
module = m["module"]
|
|
||||||
if hasattr(module, "module_late_init"):
|
|
||||||
await module.module_late_init()
|
|
||||||
|
|
||||||
def get_by_id(self, module_id: str):
|
|
||||||
module = next(
|
|
||||||
(mod for mod in self.modules if mod["info"].id == module_id), None
|
|
||||||
)
|
|
||||||
if not module:
|
|
||||||
raise Exception(f"Module with id {module_id} not loaded")
|
|
||||||
|
|
||||||
return module["module"]
|
|
||||||
|
|
||||||
def get_info_by_id(self, module_id: str):
|
|
||||||
module = next(
|
|
||||||
(mod for mod in self.modules if mod["info"].id == module_id), None
|
|
||||||
)
|
|
||||||
if not module:
|
|
||||||
raise Exception(f"Module with id {module_id} not loaded")
|
|
||||||
|
|
||||||
return module["info"]
|
|
1
src/ocab_core/ocab_core/__init__.py
Normal file
1
src/ocab_core/ocab_core/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .main import OCAB
|
38
src/ocab_core/ocab_core/lib.py
Normal file
38
src/ocab_core/ocab_core/lib.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
from aiogram.types import Update
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_directory(module_name):
|
||||||
|
spec = importlib.util.find_spec(module_name)
|
||||||
|
if spec is None:
|
||||||
|
raise ImportError(f"Module {module_name} not found")
|
||||||
|
module_path = spec.origin
|
||||||
|
if module_path is None:
|
||||||
|
raise ImportError(f"Module {module_name} has no origin path")
|
||||||
|
return os.path.dirname(module_path)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
|
||||||
|
async def register_bot_webhook(app: FastAPI, bot: Bot, dp: Dispatcher):
|
||||||
|
async def handle_webhook(request: Request):
|
||||||
|
try:
|
||||||
|
update = Update.model_validate(
|
||||||
|
await request.json(), context={"bot": bot}
|
||||||
|
)
|
||||||
|
await dp.feed_update(bot, update)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"ok": False}
|
||||||
|
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
app.post("/webhook")(handle_webhook)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
pass
|
46
src/ocab_core/ocab_core/logger.py
Normal file
46
src/ocab_core/ocab_core/logger.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
app_logger = logging.getLogger("ocab")
|
||||||
|
log_level = logging.INFO
|
||||||
|
|
||||||
|
|
||||||
|
def patch_logger(logger_: logging.Logger):
|
||||||
|
logger_.handlers = []
|
||||||
|
formatter = logging.Formatter("%(asctime)s %(message)s", datefmt="%H:%M:%S")
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
console_handler.setFormatter(formatter)
|
||||||
|
logger_.addHandler(console_handler)
|
||||||
|
logger_.propagate = False
|
||||||
|
logger_.setLevel(log_level)
|
||||||
|
return logger_
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logger():
|
||||||
|
"""
|
||||||
|
Настройка логирования
|
||||||
|
"""
|
||||||
|
patch_logger(app_logger)
|
||||||
|
|
||||||
|
|
||||||
|
def log(message):
|
||||||
|
if isinstance(message, Exception):
|
||||||
|
error_message = f"Error: {str(message)}\n{traceback.format_exc()}"
|
||||||
|
app_logger.error(error_message)
|
||||||
|
else:
|
||||||
|
app_logger.info(message)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from hypercorn.logging import Logger as HypercornLogger
|
||||||
|
|
||||||
|
class CustomLogger(HypercornLogger):
|
||||||
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if self.error_logger:
|
||||||
|
patch_logger(self.error_logger)
|
||||||
|
if self.access_logger:
|
||||||
|
patch_logger(self.access_logger)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
pass
|
118
src/ocab_core/ocab_core/main.py
Normal file
118
src/ocab_core/ocab_core/main.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import traceback
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
|
||||||
|
from ocab_core.lib import register_bot_webhook
|
||||||
|
from ocab_core.logger import CustomLogger, log, setup_logger
|
||||||
|
from ocab_core.modules_system import ModulesManager
|
||||||
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
from ocab_core.singleton import Singleton
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.config import IConfig
|
||||||
|
|
||||||
|
|
||||||
|
class OCAB:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def init_app(self, bot_modules):
|
||||||
|
setup_logger()
|
||||||
|
singleton = Singleton()
|
||||||
|
|
||||||
|
try:
|
||||||
|
singleton.modules_manager = ModulesManager()
|
||||||
|
|
||||||
|
for module_loader in bot_modules:
|
||||||
|
info = module_loader.info()
|
||||||
|
log(f"Loading {info.name} ({info.id}) module")
|
||||||
|
await singleton.modules_manager.load(module_loader)
|
||||||
|
|
||||||
|
register_config()
|
||||||
|
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
config.load()
|
||||||
|
|
||||||
|
singleton.bot = Bot(token=config.get("core::token"))
|
||||||
|
singleton.dp = Dispatcher(storage=singleton.storage["_fsm_storage"])
|
||||||
|
singleton.dp.include_routers(*singleton.storage["_routers"])
|
||||||
|
|
||||||
|
for middleware in singleton.storage["_outer_message_middlewares"]:
|
||||||
|
singleton.dp.message.outer_middleware.register(middleware)
|
||||||
|
|
||||||
|
await singleton.modules_manager.late_init()
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
if config.get("core::mode") == "WEBHOOK":
|
||||||
|
await self.start_webhook_mode()
|
||||||
|
else:
|
||||||
|
await self.start_long_polling_mode()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
async def start_long_polling_mode(self):
|
||||||
|
singleton = Singleton()
|
||||||
|
await singleton.bot.delete_webhook()
|
||||||
|
await singleton.dp.start_polling(singleton.bot)
|
||||||
|
|
||||||
|
async def start_webhook_mode(self):
|
||||||
|
try:
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from hypercorn.asyncio import serve
|
||||||
|
from hypercorn.config import Config as HyperConfig
|
||||||
|
except ImportError:
|
||||||
|
log(
|
||||||
|
"Error: FastAPI and Hypercorn are required"
|
||||||
|
"for webhook mode. Please install them."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
singleton = Singleton()
|
||||||
|
app = FastAPI()
|
||||||
|
config = get_module("standard.config", "config")
|
||||||
|
app.mount(config.get("miniapp::prefix"), singleton.storage["webapp"])
|
||||||
|
await register_bot_webhook(app, singleton.bot, singleton.dp)
|
||||||
|
await singleton.bot.set_webhook(config.get("core::webhook::public_url"))
|
||||||
|
hyperConfig = HyperConfig()
|
||||||
|
hyperConfig.bind = [f"0.0.0.0:{config.get("core::webhook::port")}"]
|
||||||
|
hyperConfig.logger_class = CustomLogger
|
||||||
|
await serve(app, hyperConfig)
|
||||||
|
|
||||||
|
|
||||||
|
def register_config():
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::token",
|
||||||
|
"password",
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::mode",
|
||||||
|
"select",
|
||||||
|
options=["WEBHOOK", "LONG_POLLING"],
|
||||||
|
default_value="WEBHOOK",
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::webhook::port",
|
||||||
|
"int",
|
||||||
|
default_value=9000,
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::webhook::public_url",
|
||||||
|
"string",
|
||||||
|
visible=False,
|
||||||
|
)
|
@ -0,0 +1,2 @@
|
|||||||
|
from .fs_loader import FSLoader
|
||||||
|
from .unsafe_fs_loader import UnsafeFSLoader
|
43
src/ocab_core/ocab_core/modules_system/loaders/base.py
Normal file
43
src/ocab_core/ocab_core/modules_system/loaders/base.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import types
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Dict, List, Optional, Union
|
||||||
|
|
||||||
|
from dataclasses_json import dataclass_json
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass_json
|
||||||
|
@dataclass
|
||||||
|
class DependencyInfo:
|
||||||
|
version: str
|
||||||
|
uses: Optional[List[str]] = None
|
||||||
|
|
||||||
|
|
||||||
|
DependencyType = Union[str, DependencyInfo]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass_json
|
||||||
|
@dataclass
|
||||||
|
class Dependencies:
|
||||||
|
required: Optional[Dict[str, DependencyType]] = None
|
||||||
|
optional: Optional[Dict[str, DependencyType]] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass_json
|
||||||
|
@dataclass
|
||||||
|
class ModuleInfo:
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
version: str
|
||||||
|
author: Union[str, List[str]]
|
||||||
|
privileged: bool
|
||||||
|
dependencies: Dependencies
|
||||||
|
pythonDependencies: Optional[Dependencies] = None
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractLoader:
|
||||||
|
def info(self) -> ModuleInfo:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def load(self) -> types.ModuleType:
|
||||||
|
raise NotImplementedError
|
@ -3,6 +3,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from RestrictedPython import compile_restricted_exec
|
from RestrictedPython import compile_restricted_exec
|
||||||
|
|
||||||
|
# from ocab_core.logger import log
|
||||||
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
||||||
from ocab_core.modules_system.safe.policy import (
|
from ocab_core.modules_system.safe.policy import (
|
||||||
ALLOWED_IMPORTS,
|
ALLOWED_IMPORTS,
|
||||||
@ -16,13 +17,30 @@ class FSLoader(UnsafeFSLoader):
|
|||||||
super().__init__(path)
|
super().__init__(path)
|
||||||
self.builtins = BUILTINS.copy()
|
self.builtins = BUILTINS.copy()
|
||||||
self.builtins["__import__"] = self._hook_import
|
self.builtins["__import__"] = self._hook_import
|
||||||
|
self.module_info = self.info()
|
||||||
|
self.allowed_python_dependencies = self._get_allowed_python_dependencies()
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
info = self.info()
|
if self.module_info.privileged:
|
||||||
if info.privileged:
|
|
||||||
raise Exception("Only non privileged modules are allowed to be imported")
|
raise Exception("Only non privileged modules are allowed to be imported")
|
||||||
|
self.module_id = self.module_info.id
|
||||||
|
|
||||||
return self._hook_import(".")
|
return self._hook_import(".")
|
||||||
|
|
||||||
|
def _get_allowed_python_dependencies(self):
|
||||||
|
allowed = {}
|
||||||
|
|
||||||
|
if self.module_info.pythonDependencies:
|
||||||
|
if self.module_info.pythonDependencies.required:
|
||||||
|
allowed.update(self.module_info.pythonDependencies.required)
|
||||||
|
if self.module_info.pythonDependencies.optional:
|
||||||
|
allowed.update(self.module_info.pythonDependencies.optional)
|
||||||
|
|
||||||
|
for allowed_module in ALLOWED_IMPORTS:
|
||||||
|
allowed[allowed_module] = "*"
|
||||||
|
|
||||||
|
return allowed
|
||||||
|
|
||||||
def _resolve_module_from_path(self, module_name: str):
|
def _resolve_module_from_path(self, module_name: str):
|
||||||
path = Path(self.path)
|
path = Path(self.path)
|
||||||
|
|
||||||
@ -44,11 +62,13 @@ class FSLoader(UnsafeFSLoader):
|
|||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
def _hook_import(self, name: str, *args, **kwargs):
|
def _hook_import(self, name: str, *args, **kwargs):
|
||||||
for allowed in ALLOWED_IMPORTS:
|
|
||||||
if name == allowed or name.startswith(f"{allowed}."):
|
|
||||||
return __import__(name, *args, **kwargs)
|
|
||||||
|
|
||||||
if name == "ocab_core.modules_system.public_api":
|
if name == "ocab_core.modules_system.public_api":
|
||||||
|
module = __import__(name, *args, **kwargs)
|
||||||
|
module.__ocab_module_id__ = self.module_id
|
||||||
|
return module
|
||||||
|
|
||||||
|
for key in self.allowed_python_dependencies.keys():
|
||||||
|
if name == key or name.startswith(f"{key}."):
|
||||||
return __import__(name, *args, **kwargs)
|
return __import__(name, *args, **kwargs)
|
||||||
|
|
||||||
module_file_path = self._resolve_module_from_path(name)
|
module_file_path = self._resolve_module_from_path(name)
|
||||||
@ -58,9 +78,7 @@ class FSLoader(UnsafeFSLoader):
|
|||||||
|
|
||||||
module = types.ModuleType(name)
|
module = types.ModuleType(name)
|
||||||
module.__dict__.update(
|
module.__dict__.update(
|
||||||
{
|
{"__builtins__": self.builtins, "__ocab_module_id__": self.module_id}
|
||||||
"__builtins__": self.builtins,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
result = compile_restricted_exec(src, "<string>", policy=RestrictedPythonPolicy)
|
result = compile_restricted_exec(src, "<string>", policy=RestrictedPythonPolicy)
|
||||||
|
|
169
src/ocab_core/ocab_core/modules_system/modules_manager.py
Normal file
169
src/ocab_core/ocab_core/modules_system/modules_manager.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
|
import semver
|
||||||
|
|
||||||
|
from ocab_core.modules_system.loaders.base import (
|
||||||
|
AbstractLoader,
|
||||||
|
DependencyInfo,
|
||||||
|
ModuleInfo,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_version_compatible(version, requirement):
|
||||||
|
def parse_requirement(req):
|
||||||
|
if req.startswith("^"):
|
||||||
|
base_version = req[1:]
|
||||||
|
base_version_info = semver.VersionInfo.parse(base_version)
|
||||||
|
range_start = base_version_info
|
||||||
|
range_end = base_version_info.bump_major()
|
||||||
|
return [f">={range_start}", f"<{range_end}"]
|
||||||
|
else:
|
||||||
|
return [req]
|
||||||
|
|
||||||
|
for r in parse_requirement(requirement):
|
||||||
|
if r == "*":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not semver.Version.parse(version).match(r):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def check_python_dependencies(info: ModuleInfo):
|
||||||
|
if info.pythonDependencies and info.pythonDependencies.required:
|
||||||
|
for dependency, req in info.pythonDependencies.required.items():
|
||||||
|
try:
|
||||||
|
importlib.import_module(dependency)
|
||||||
|
except ImportError:
|
||||||
|
raise Exception(
|
||||||
|
f"Module {info.id} requires {dependency}, "
|
||||||
|
f"but it is not installed"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
installed_version = pkg_resources.get_distribution(dependency).version
|
||||||
|
except pkg_resources.DistributionNotFound:
|
||||||
|
installed_version = "*"
|
||||||
|
|
||||||
|
if isinstance(req, str):
|
||||||
|
required_version = req
|
||||||
|
elif isinstance(req, DependencyInfo):
|
||||||
|
required_version = req.version
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid dependency specification for {dependency}")
|
||||||
|
|
||||||
|
if not is_version_compatible(installed_version, required_version):
|
||||||
|
raise Exception(
|
||||||
|
f"Module {info.id} depends on {dependency} {required_version}, "
|
||||||
|
f"but version {installed_version} is installed"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def check_dependency_uses(
|
||||||
|
loaded_dependency, required_uses, dependent_module_id, dependency_id
|
||||||
|
):
|
||||||
|
module = loaded_dependency.get("module")
|
||||||
|
if not module:
|
||||||
|
raise Exception(f"Module object not found for dependency {dependency_id}")
|
||||||
|
|
||||||
|
for required_attr in required_uses:
|
||||||
|
if not hasattr(module, required_attr):
|
||||||
|
raise Exception(
|
||||||
|
f"Module {dependent_module_id} requires '{required_attr}' "
|
||||||
|
f"from {dependency_id}, but it is not available"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def await_if_async(module, method_name):
|
||||||
|
if hasattr(module, method_name):
|
||||||
|
method = getattr(module, method_name)
|
||||||
|
if inspect.iscoroutinefunction(method):
|
||||||
|
await method()
|
||||||
|
else:
|
||||||
|
method()
|
||||||
|
|
||||||
|
|
||||||
|
class ModulesManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.modules = []
|
||||||
|
|
||||||
|
async def load(self, loader: AbstractLoader):
|
||||||
|
info = loader.info()
|
||||||
|
|
||||||
|
# Check if the module is already loaded
|
||||||
|
if any(mod["info"].id == info.id for mod in self.modules):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.check_module_dependencies(info)
|
||||||
|
check_python_dependencies(info)
|
||||||
|
|
||||||
|
module_info = {
|
||||||
|
"info": info,
|
||||||
|
"module": None,
|
||||||
|
}
|
||||||
|
self.modules.append(module_info)
|
||||||
|
module = loader.load()
|
||||||
|
module_info["module"] = module
|
||||||
|
|
||||||
|
await await_if_async(module, "module_init")
|
||||||
|
|
||||||
|
def check_module_dependencies(self, info: ModuleInfo):
|
||||||
|
if info.dependencies.required:
|
||||||
|
for dependency, req in info.dependencies.required.items():
|
||||||
|
loaded_dependency = next(
|
||||||
|
(mod for mod in self.modules if mod["info"].id == dependency), None
|
||||||
|
)
|
||||||
|
if not loaded_dependency:
|
||||||
|
raise Exception(
|
||||||
|
f"Module {info.id} depends on {dependency},"
|
||||||
|
f"but it is not loaded"
|
||||||
|
)
|
||||||
|
|
||||||
|
loaded_dependency_info = loaded_dependency["info"]
|
||||||
|
|
||||||
|
if isinstance(req, str):
|
||||||
|
required_version = req
|
||||||
|
elif isinstance(req, DependencyInfo):
|
||||||
|
required_version = req.version
|
||||||
|
if req.uses:
|
||||||
|
check_dependency_uses(
|
||||||
|
loaded_dependency, req.uses, info.id, dependency
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid dependency specification for {dependency}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not is_version_compatible(
|
||||||
|
loaded_dependency_info.version, required_version
|
||||||
|
):
|
||||||
|
raise Exception(
|
||||||
|
f"Module {info.id} depends on {dependency} {required_version}, "
|
||||||
|
f"but version {loaded_dependency_info.version} is loaded"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def late_init(self):
|
||||||
|
for m in self.modules:
|
||||||
|
module = m["module"]
|
||||||
|
await await_if_async(module, "module_late_init")
|
||||||
|
|
||||||
|
def get_by_id(self, module_id: str):
|
||||||
|
module = next(
|
||||||
|
(mod for mod in self.modules if mod["info"].id == module_id), None
|
||||||
|
)
|
||||||
|
if not module:
|
||||||
|
raise Exception(f"Module with id {module_id} not loaded")
|
||||||
|
|
||||||
|
return module["module"]
|
||||||
|
|
||||||
|
def get_info_by_id(self, module_id: str):
|
||||||
|
module = next(
|
||||||
|
(mod for mod in self.modules if mod["info"].id == module_id), None
|
||||||
|
)
|
||||||
|
if not module:
|
||||||
|
raise Exception(f"Module with id {module_id} not loaded")
|
||||||
|
|
||||||
|
return module["info"]
|
@ -1,10 +1,12 @@
|
|||||||
|
from ocab_core.logger import log
|
||||||
|
|
||||||
from .public_api import (
|
from .public_api import (
|
||||||
Storage,
|
Storage,
|
||||||
get_fsm_context,
|
get_fsm_context,
|
||||||
get_module,
|
get_module,
|
||||||
log,
|
|
||||||
register_outer_message_middleware,
|
register_outer_message_middleware,
|
||||||
register_router,
|
register_router,
|
||||||
|
set_chat_menu_button,
|
||||||
set_my_commands,
|
set_my_commands,
|
||||||
)
|
)
|
||||||
from .utils import Utils
|
from .utils import Utils
|
@ -1,3 +1,4 @@
|
|||||||
|
import inspect
|
||||||
import types
|
import types
|
||||||
from typing import Any, Tuple, Union
|
from typing import Any, Tuple, Union
|
||||||
|
|
||||||
@ -5,10 +6,16 @@ from aiogram import BaseMiddleware, Router
|
|||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.fsm.storage.base import StorageKey
|
from aiogram.fsm.storage.base import StorageKey
|
||||||
|
|
||||||
from ocab_core.logger import log
|
# from ocab_core.logger import log
|
||||||
|
from ocab_core.modules_system.loaders.base import DependencyInfo
|
||||||
from ocab_core.singleton import Singleton
|
from ocab_core.singleton import Singleton
|
||||||
|
|
||||||
|
|
||||||
|
async def set_chat_menu_button(menu_button):
|
||||||
|
app = Singleton()
|
||||||
|
await app.bot.set_chat_menu_button(menu_button=menu_button)
|
||||||
|
|
||||||
|
|
||||||
def register_router(router: Router):
|
def register_router(router: Router):
|
||||||
app = Singleton()
|
app = Singleton()
|
||||||
app.storage["_routers"].append(router)
|
app.storage["_routers"].append(router)
|
||||||
@ -40,17 +47,47 @@ async def get_fsm_context(chat_id: int, user_id: int) -> FSMContext:
|
|||||||
|
|
||||||
def set_fsm(storage):
|
def set_fsm(storage):
|
||||||
app = Singleton()
|
app = Singleton()
|
||||||
log(storage)
|
|
||||||
app.storage["_fsm_storage"] = storage
|
app.storage["_fsm_storage"] = storage
|
||||||
|
|
||||||
|
|
||||||
def get_module(
|
def get_module(
|
||||||
module_id: str, paths=None
|
module_id: str, paths=None
|
||||||
) -> Union[types.ModuleType, Union[Any, None], Tuple[Union[Any, None], ...]]:
|
) -> Union[types.ModuleType, Union[Any, None], Tuple[Union[Any, None], ...]]:
|
||||||
|
|
||||||
|
caller_globals = inspect.currentframe().f_back.f_globals
|
||||||
app = Singleton()
|
app = Singleton()
|
||||||
|
|
||||||
|
allowed_uses = None
|
||||||
|
|
||||||
|
if "__ocab_module_id__" in caller_globals:
|
||||||
|
caller_module_id = caller_globals["__ocab_module_id__"]
|
||||||
|
caller_module_info = app.modules_manager.get_info_by_id(caller_module_id)
|
||||||
|
|
||||||
|
if caller_module_info and caller_module_info.dependencies:
|
||||||
|
dependency = None
|
||||||
|
if caller_module_info.dependencies.required:
|
||||||
|
dependency = caller_module_info.dependencies.required.get(module_id)
|
||||||
|
if not dependency and caller_module_info.dependencies.optional:
|
||||||
|
dependency = caller_module_info.dependencies.optional.get(module_id)
|
||||||
|
|
||||||
|
if (
|
||||||
|
dependency
|
||||||
|
and isinstance(dependency, DependencyInfo)
|
||||||
|
and dependency.uses
|
||||||
|
):
|
||||||
|
allowed_uses = set(dependency.uses)
|
||||||
|
|
||||||
module = app.modules_manager.get_by_id(module_id)
|
module = app.modules_manager.get_by_id(module_id)
|
||||||
|
|
||||||
|
if not module:
|
||||||
|
raise ModuleNotFoundError(f"Module {module_id} not found")
|
||||||
|
|
||||||
if paths is None:
|
if paths is None:
|
||||||
|
if allowed_uses is not None:
|
||||||
|
raise PermissionError(
|
||||||
|
f"Direct access to module {module_id} is "
|
||||||
|
f"not allowed for {caller_module_id}. Specify allowed attributes."
|
||||||
|
)
|
||||||
return module
|
return module
|
||||||
|
|
||||||
if isinstance(paths, str):
|
if isinstance(paths, str):
|
||||||
@ -63,9 +100,16 @@ def get_module(
|
|||||||
try:
|
try:
|
||||||
parts = path.split(".")
|
parts = path.split(".")
|
||||||
for part in parts:
|
for part in parts:
|
||||||
|
if allowed_uses is not None and part not in allowed_uses:
|
||||||
|
raise AttributeError(
|
||||||
|
f"Access to '{part}' is not allowed "
|
||||||
|
+ f"for module {caller_module_id}"
|
||||||
|
)
|
||||||
current_obj = getattr(current_obj, part)
|
current_obj = getattr(current_obj, part)
|
||||||
results.append(current_obj)
|
results.append(current_obj)
|
||||||
except AttributeError:
|
except AttributeError as e:
|
||||||
|
if "is not allowed" in str(e):
|
||||||
|
raise PermissionError(str(e))
|
||||||
results.append(None)
|
results.append(None)
|
||||||
|
|
||||||
if len(results) == 1:
|
if len(results) == 1:
|
@ -1,3 +1,4 @@
|
|||||||
|
import types
|
||||||
from _ast import AnnAssign
|
from _ast import AnnAssign
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -9,8 +10,8 @@ from RestrictedPython import (
|
|||||||
utility_builtins,
|
utility_builtins,
|
||||||
)
|
)
|
||||||
from RestrictedPython.Eval import default_guarded_getitem, default_guarded_getiter
|
from RestrictedPython.Eval import default_guarded_getitem, default_guarded_getiter
|
||||||
from RestrictedPython.Guards import (
|
from RestrictedPython.Guards import ( # guarded_setattr,; full_write_guard,
|
||||||
full_write_guard,
|
_write_wrapper,
|
||||||
guarded_unpack_sequence,
|
guarded_unpack_sequence,
|
||||||
safer_getattr,
|
safer_getattr,
|
||||||
)
|
)
|
||||||
@ -95,6 +96,39 @@ def safes_getattr(object, name, default=None, getattr=safer_getattr):
|
|||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
|
|
||||||
|
|
||||||
|
trusted_settters_classes = []
|
||||||
|
|
||||||
|
|
||||||
|
def safes_setattr(self, key, value):
|
||||||
|
if (
|
||||||
|
isinstance(getattr(type(self), key, None), property)
|
||||||
|
and getattr(type(self), key).fset is not None
|
||||||
|
):
|
||||||
|
getattr(type(self), key).fset(self, value)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def write_guard():
|
||||||
|
# ed scope abuse!
|
||||||
|
# safetypes and Wrapper variables are used by guard()
|
||||||
|
safetypes = {dict, list}
|
||||||
|
Wrapper = _write_wrapper()
|
||||||
|
|
||||||
|
def guard(ob):
|
||||||
|
# Don't bother wrapping simple types, or objects that claim to
|
||||||
|
# handle their own write security.
|
||||||
|
if type(ob) in safetypes or hasattr(ob, "_guarded_writes"):
|
||||||
|
return ob
|
||||||
|
|
||||||
|
if type(ob) in trusted_settters_classes:
|
||||||
|
setattr(ob, "__guarded_setattr__", types.MethodType(safes_setattr, ob))
|
||||||
|
|
||||||
|
# Hand the object to the Wrapper instance, then return the instance.
|
||||||
|
return Wrapper(ob)
|
||||||
|
|
||||||
|
return guard
|
||||||
|
|
||||||
|
|
||||||
BUILTINS = safe_builtins.copy()
|
BUILTINS = safe_builtins.copy()
|
||||||
BUILTINS.update(utility_builtins)
|
BUILTINS.update(utility_builtins)
|
||||||
BUILTINS.update(limited_builtins)
|
BUILTINS.update(limited_builtins)
|
||||||
@ -103,7 +137,8 @@ BUILTINS["__metaclass__"] = _metaclass
|
|||||||
BUILTINS["_getitem_"] = default_guarded_getitem
|
BUILTINS["_getitem_"] = default_guarded_getitem
|
||||||
BUILTINS["_getattr_"] = safes_getattr
|
BUILTINS["_getattr_"] = safes_getattr
|
||||||
BUILTINS["_getiter_"] = default_guarded_getiter
|
BUILTINS["_getiter_"] = default_guarded_getiter
|
||||||
BUILTINS["_write_"] = full_write_guard
|
BUILTINS["_write_"] = write_guard()
|
||||||
BUILTINS["_unpack_sequence_"] = guarded_unpack_sequence
|
BUILTINS["_unpack_sequence_"] = guarded_unpack_sequence
|
||||||
BUILTINS["staticmethod"] = staticmethod
|
BUILTINS["staticmethod"] = staticmethod
|
||||||
BUILTINS["tuple"] = tuple
|
BUILTINS["tuple"] = tuple
|
||||||
|
BUILTINS["reversed"] = reversed
|
2140
src/ocab_core/poetry.lock
generated
Normal file
2140
src/ocab_core/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
src/ocab_core/poetry.toml
Normal file
2
src/ocab_core/poetry.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
26
src/ocab_core/pyproject.toml
Normal file
26
src/ocab_core/pyproject.toml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "ocab-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Максим Слипенко <maxim@slipenko.com>"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "~3.12"
|
||||||
|
aiogram = "^3.10.0"
|
||||||
|
setuptools = "^71.0.1"
|
||||||
|
restrictedpython = "^7.1"
|
||||||
|
semver = "^3.0.2"
|
||||||
|
dataclasses-json = "^0.6.7"
|
||||||
|
fastapi = { version = "^0.111.1", optional = true }
|
||||||
|
hypercorn = { version = "^0.17.3", optional = true }
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
ocab-modules = { path = "../ocab_modules", develop = true }
|
||||||
|
|
||||||
|
[tool.poetry.extras]
|
||||||
|
webhook = ["fastapi", "hypercorn"]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
12
src/ocab_modules/README.md
Normal file
12
src/ocab_modules/README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# OCAB Modules
|
||||||
|
|
||||||
|
OCAB Modules содержит набор модулей для платформы Open Chat AI Bot (OCAB).
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
OCAB - это платформа для создания чат-ботов Telegram. Модули - это расширения, которые добавляют функциональность ботам OCAB.
|
||||||
|
|
||||||
|
## Типы модулей
|
||||||
|
|
||||||
|
* **Стандартные модули (standard.*):** Предоставляют основные функции, такие как управление пользователями, ролями и настройками.
|
||||||
|
* **Дополнительные официальные модули (external.*):** Разработаны командой OCAB и предоставляют расширенные возможности, такие как интеграция с нейросетями, внешними сервисами и API.
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "external.yandexgpt",
|
|
||||||
"name": "Yandex GPT",
|
|
||||||
"description": "Модуль для работы с Yandex GPT",
|
|
||||||
"author": "OCAB Team",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"privileged": true,
|
|
||||||
"dependencies": {}
|
|
||||||
}
|
|
1
src/ocab_modules/ocab_modules/__init__.py
Normal file
1
src/ocab_modules/ocab_modules/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .lib import module_loader
|
19
src/ocab_modules/ocab_modules/external/create_report_apps/README.md
vendored
Normal file
19
src/ocab_modules/ocab_modules/external/create_report_apps/README.md
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Модуль Create Report Apps
|
||||||
|
|
||||||
|
Модуль `create_report_apps` предназначен для помощи пользователям в создании отчетов об ошибках в приложениях.
|
||||||
|
|
||||||
|
## Функциональность
|
||||||
|
|
||||||
|
- Задает пользователю ряд вопросов, необходимых для составления отчета.
|
||||||
|
- Собирает информацию о системе пользователя.
|
||||||
|
- Формирует отчет в текстовом формате.
|
||||||
|
|
||||||
|
## Команды
|
||||||
|
|
||||||
|
- `/create_report_apps` - запустить процесс создания отчета.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
1. Отправьте команду `/create_report_apps` боту в личных сообщениях или в групповом чате.
|
||||||
|
2. Ответьте на вопросы бота.
|
||||||
|
3. Бот сформирует отчет и отправит его вам.
|
22
src/ocab_modules/ocab_modules/external/yandexgpt/README.md
vendored
Normal file
22
src/ocab_modules/ocab_modules/external/yandexgpt/README.md
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Модуль YandexGPT
|
||||||
|
|
||||||
|
Модуль `yandexgpt` интегрирует в бота OCAB нейросеть YandexGPT.
|
||||||
|
|
||||||
|
## Функциональность
|
||||||
|
|
||||||
|
- Позволяет боту отвечать на сообщения пользователей, используя YandexGPT.
|
||||||
|
- Строит линию контекста для нейросети, используя историю сообщений.
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
- `yandexgpt::token` - API-ключ для доступа к YandexGPT.
|
||||||
|
- `yandexgpt::catalogid` - идентификатор каталога YandexGPT.
|
||||||
|
- `yandexgpt::prompt` - системная подсказка для YandexGPT.
|
||||||
|
- `yandexgpt::startword` - слова, с которых должно начинаться сообщение, чтобы бот ответил.
|
||||||
|
- `yandexgpt::inword` - слова, которые должны быть в сообщении, чтобы бот ответил.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
1. Настройте конфигурационные параметры модуля.
|
||||||
|
2. Отправьте боту сообщение, которое соответствует условиям, указанным в параметрах `startword` и `inword`.
|
||||||
|
3. Бот ответит на сообщение, используя YandexGPT.
|
@ -1 +1,2 @@
|
|||||||
from .handlers import answer_to_message
|
from .handlers import answer_to_message
|
||||||
|
from .main import module_init
|
@ -1,14 +1,36 @@
|
|||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from aiogram import Bot
|
from aiogram import Bot
|
||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
|
|
||||||
from ocab_modules.external.yandexgpt.yandexgpt import *
|
from ocab_core.modules_system.public_api import get_module, log
|
||||||
from ocab_modules.standard.config.config import (
|
|
||||||
get_yandexgpt_catalog_id,
|
from .yandexgpt import YandexGPT
|
||||||
get_yandexgpt_prompt,
|
|
||||||
get_yandexgpt_token,
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.config import IConfig
|
||||||
|
from ocab_modules.standard.database.db_api import add_message as IAddMessage
|
||||||
|
|
||||||
|
config: "IConfig" = get_module(
|
||||||
|
"standard.config",
|
||||||
|
"config",
|
||||||
)
|
)
|
||||||
from ocab_modules.standard.database.db_api import add_message
|
|
||||||
|
|
||||||
|
def get_yandexgpt_catalog_id():
|
||||||
|
return config.get("yandexgpt::catalogid")
|
||||||
|
|
||||||
|
|
||||||
|
def get_yandexgpt_token():
|
||||||
|
return config.get("yandexgpt::token")
|
||||||
|
|
||||||
|
|
||||||
|
def get_yandexgpt_prompt():
|
||||||
|
return config.get("yandexgpt::prompt")
|
||||||
|
|
||||||
|
|
||||||
|
add_message: "IAddMessage" = get_module("standard.database", "db_api.add_message")
|
||||||
|
|
||||||
|
|
||||||
async def answer_to_message(message: Message, bot: Bot):
|
async def answer_to_message(message: Message, bot: Bot):
|
21
src/ocab_modules/ocab_modules/external/yandexgpt/info.json
vendored
Normal file
21
src/ocab_modules/ocab_modules/external/yandexgpt/info.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"id": "external.yandexgpt",
|
||||||
|
"name": "Yandex GPT",
|
||||||
|
"description": "Модуль для работы с Yandex GPT",
|
||||||
|
"author": "OCAB Team",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"privileged": false,
|
||||||
|
"dependencies": {
|
||||||
|
"required": {
|
||||||
|
"standard.config": "^1.0.0",
|
||||||
|
"standard.database": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pythonDependencies": {
|
||||||
|
"required": {
|
||||||
|
"aiohttp": "*",
|
||||||
|
"requests": "*",
|
||||||
|
"json": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
src/ocab_modules/ocab_modules/external/yandexgpt/main.py
vendored
Normal file
50
src/ocab_modules/ocab_modules/external/yandexgpt/main.py
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.config import IConfig
|
||||||
|
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
|
||||||
|
def module_init():
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::token",
|
||||||
|
"password",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::token_for_request",
|
||||||
|
"int",
|
||||||
|
default_value=8000,
|
||||||
|
)
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::token_for_answer",
|
||||||
|
"int",
|
||||||
|
default_value=2000,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::catalogid",
|
||||||
|
"password",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::prompt",
|
||||||
|
"string",
|
||||||
|
default_value="Ты чат-бот ...",
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::startword",
|
||||||
|
"string",
|
||||||
|
default_value="Бот| Бот, | бот | бот,",
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"yandexgpt::inword",
|
||||||
|
"string",
|
||||||
|
default_value="помогите | не работает",
|
||||||
|
)
|
@ -1,7 +1,7 @@
|
|||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
from aiogram import F, Router
|
from aiogram import F, Router
|
||||||
|
|
||||||
from src.ocab_modules.external.yandexgpt.handlers import answer_to_message
|
from .handlers import answer_to_message
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
# Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message
|
# Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message
|
@ -1,14 +1,31 @@
|
|||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
import asyncio
|
|
||||||
import json
|
import json
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from ocab_core.logger import log
|
from ocab_core.modules_system.public_api import get_module, log
|
||||||
|
|
||||||
from ...standard.config.config import *
|
if TYPE_CHECKING:
|
||||||
from ...standard.database import *
|
from ocab_modules.standard.config import IConfig
|
||||||
|
from ocab_modules.standard.database import db_api as IDbApi
|
||||||
|
|
||||||
|
db_api: "IDbApi" = get_module("standard.database", "db_api")
|
||||||
|
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
|
||||||
|
def get_yandexgpt_token_for_answer():
|
||||||
|
return config.get("yandexgpt::token_for_answer")
|
||||||
|
|
||||||
|
|
||||||
|
def get_yandexgpt_token_for_request():
|
||||||
|
return config.get("yandexgpt::token_for_request")
|
||||||
|
|
||||||
|
|
||||||
|
def get_yandexgpt_prompt():
|
||||||
|
return config.get("yandexgpt::prompt")
|
||||||
|
|
||||||
|
|
||||||
class YandexGPT:
|
class YandexGPT:
|
||||||
@ -108,8 +125,11 @@ class YandexGPT:
|
|||||||
input_messages,
|
input_messages,
|
||||||
stream=False,
|
stream=False,
|
||||||
temperature=0.6,
|
temperature=0.6,
|
||||||
max_tokens=get_yandexgpt_token_for_request(),
|
max_tokens=None,
|
||||||
):
|
):
|
||||||
|
if max_tokens is None:
|
||||||
|
max_tokens = get_yandexgpt_token_for_request()
|
||||||
|
|
||||||
url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
|
url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
|
||||||
gpt = f"gpt://{self.catalog_id}/yandexgpt/latest"
|
gpt = f"gpt://{self.catalog_id}/yandexgpt/latest"
|
||||||
headers = {
|
headers = {
|
25
src/ocab_modules/ocab_modules/lib.py
Normal file
25
src/ocab_modules/ocab_modules/lib.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ocab_core.modules_system.loaders.fs_loader import FSLoader
|
||||||
|
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_directory(module_name):
|
||||||
|
spec = importlib.util.find_spec(module_name)
|
||||||
|
if spec is None:
|
||||||
|
raise ImportError(f"Module {module_name} not found")
|
||||||
|
module_path = spec.origin
|
||||||
|
if module_path is None:
|
||||||
|
raise ImportError(f"Module {module_name} has no origin path")
|
||||||
|
return os.path.dirname(module_path)
|
||||||
|
|
||||||
|
|
||||||
|
ocab_modules_path = get_module_directory("ocab_modules")
|
||||||
|
|
||||||
|
|
||||||
|
def module_loader(namespace: str, module_name: str, safe=True):
|
||||||
|
if not safe:
|
||||||
|
return UnsafeFSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
||||||
|
else:
|
||||||
|
return FSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
20
src/ocab_modules/ocab_modules/standard/admin/README.md
Normal file
20
src/ocab_modules/ocab_modules/standard/admin/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Модуль Admin
|
||||||
|
|
||||||
|
Модуль `admin` предоставляет администраторам и модераторам чата инструменты для управления:
|
||||||
|
|
||||||
|
## Функциональность
|
||||||
|
|
||||||
|
- Удаление сообщений.
|
||||||
|
- Получение ID чата.
|
||||||
|
|
||||||
|
## Команды
|
||||||
|
|
||||||
|
- `/rm` - удалить сообщение, на которое отвечает команда.
|
||||||
|
- `/chatID` - получить ID текущего чата.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
1. Ответьте на сообщение, которое нужно удалить.
|
||||||
|
2. Отправьте команду `/rm`.
|
||||||
|
|
||||||
|
Чтобы получить ID чата, отправьте команду `/chatID`.
|
@ -1,10 +1,19 @@
|
|||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from aiogram import Bot
|
from aiogram import Bot
|
||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
|
|
||||||
from ocab_core.modules_system.public_api import get_module
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
|
||||||
get_default_chat_tag = get_module("standard.config", "get_default_chat_tag")
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.config import IConfig
|
||||||
|
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_chat_tag():
|
||||||
|
return config.get("filters::default_chat_tag")
|
||||||
|
|
||||||
|
|
||||||
async def delete_message(message: Message, bot: Bot):
|
async def delete_message(message: Message, bot: Bot):
|
@ -6,6 +6,8 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"privileged": false,
|
"privileged": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"required": {
|
||||||
"standard.filters": "^1.0.0"
|
"standard.filters": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
# Модуль Command Helper
|
||||||
|
|
||||||
|
Модуль `command_helper` упрощает регистрацию команд бота и управление ими.
|
||||||
|
|
||||||
|
## Функциональность
|
||||||
|
|
||||||
|
- Регистрация команд бота.
|
||||||
|
- Установка команд для пользователей в зависимости от их роли.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
1. Импортируйте функцию `register_command`.
|
||||||
|
2. Вызовите функцию `register_command`, передав ей название команды, ее описание и роль пользователя,
|
||||||
|
которому доступна эта команда.
|
||||||
|
|
||||||
|
## Пример
|
||||||
|
|
||||||
|
```python
|
||||||
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
|
||||||
|
register_command = get_module("standard.command_helper", "register_command")
|
||||||
|
|
||||||
|
register_command("my_command", "Описание моей команды", role="ADMIN")
|
||||||
|
```
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"id": "standard.command_helper",
|
||||||
|
"name": "Command helper",
|
||||||
|
"description": "Модуль для отображения команд при вводе '/'",
|
||||||
|
"author": "OCAB Team",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"privileged": false,
|
||||||
|
"dependencies": {
|
||||||
|
"required": {
|
||||||
|
"standard.roles": "^1.0.0",
|
||||||
|
"standard.database": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Awaitable, Callable, Dict
|
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict
|
||||||
|
|
||||||
from aiogram import BaseMiddleware
|
from aiogram import BaseMiddleware
|
||||||
from aiogram.types import BotCommand, TelegramObject
|
from aiogram.types import BotCommand, TelegramObject
|
||||||
@ -9,15 +9,18 @@ from ocab_core.modules_system.public_api import (
|
|||||||
set_my_commands,
|
set_my_commands,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.database import db_api as IDbApi
|
||||||
|
from ocab_modules.standard.roles import Roles as IRoles
|
||||||
|
|
||||||
commands = dict()
|
commands = dict()
|
||||||
|
|
||||||
|
db_api: "IDbApi" = get_module(
|
||||||
db_api = get_module(
|
|
||||||
"standard.database",
|
"standard.database",
|
||||||
"db_api",
|
"db_api",
|
||||||
)
|
)
|
||||||
|
|
||||||
Roles = get_module("standard.roles", "Roles")
|
Roles: "IRoles" = get_module("standard.roles", "Roles")
|
||||||
|
|
||||||
|
|
||||||
def register_command(command, description, role="USER"):
|
def register_command(command, description, role="USER"):
|
28
src/ocab_modules/ocab_modules/standard/config/README.md
Normal file
28
src/ocab_modules/ocab_modules/standard/config/README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Модуль Config
|
||||||
|
|
||||||
|
Модуль `config` управляет конфигурацией бота.
|
||||||
|
|
||||||
|
## Функциональность
|
||||||
|
|
||||||
|
- Загрузка конфигурации из файла `config.yaml`.
|
||||||
|
- Сохранение конфигурации в файл.
|
||||||
|
- Регистрация параметров конфигурации.
|
||||||
|
- Получение значений параметров.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
1. Импортируйте объект `config`.
|
||||||
|
2. Вызовите метод `register`, чтобы зарегистрировать параметр конфигурации.
|
||||||
|
3. Вызовите метод `get`, чтобы получить значение параметра.
|
||||||
|
|
||||||
|
## Пример
|
||||||
|
|
||||||
|
```python
|
||||||
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
|
||||||
|
config = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
config.register("my_parameter", "string", default_value="default")
|
||||||
|
|
||||||
|
value = config.get("my_parameter")
|
||||||
|
```
|
@ -0,0 +1,2 @@
|
|||||||
|
from .config import IConfig, config
|
||||||
|
from .main import module_late_init
|
7
src/ocab_modules/ocab_modules/standard/config/config.py
Normal file
7
src/ocab_modules/ocab_modules/standard/config/config.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# flake8: noqa
|
||||||
|
|
||||||
|
from .config_manager import ConfigManager
|
||||||
|
|
||||||
|
IConfig = ConfigManager
|
||||||
|
|
||||||
|
config: ConfigManager = ConfigManager(config_path="config.yaml")
|
113
src/ocab_modules/ocab_modules/standard/config/config_manager.py
Normal file
113
src/ocab_modules/ocab_modules/standard/config/config_manager.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import inspect
|
||||||
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigManager:
|
||||||
|
def __init__(self, config_path: str):
|
||||||
|
self.config_path = config_path
|
||||||
|
|
||||||
|
self._config: Dict[str, Dict[str, Any]] = {}
|
||||||
|
|
||||||
|
self._metadata: Dict[str, Dict[str, Any]] = {}
|
||||||
|
|
||||||
|
def load(self, file_path: str = ""):
|
||||||
|
if not file_path:
|
||||||
|
file_path = self.config_path
|
||||||
|
|
||||||
|
def build_key(prev, next):
|
||||||
|
if prev:
|
||||||
|
return f"{prev}::{next}"
|
||||||
|
return next
|
||||||
|
|
||||||
|
def recurse_set(value, key=""):
|
||||||
|
if isinstance(value, dict):
|
||||||
|
for k, v in value.items():
|
||||||
|
recurse_set(v, build_key(key, k))
|
||||||
|
return
|
||||||
|
if key in self._metadata:
|
||||||
|
self._config[key] = value
|
||||||
|
|
||||||
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
|
data = yaml.safe_load(file)
|
||||||
|
recurse_set(data)
|
||||||
|
|
||||||
|
def save(self, file_path: str = ""):
|
||||||
|
if not file_path:
|
||||||
|
file_path = self.config_path
|
||||||
|
|
||||||
|
def nested_dict(flat_dict):
|
||||||
|
result = {}
|
||||||
|
for key, value in flat_dict.items():
|
||||||
|
keys = key.split("::")
|
||||||
|
d = result
|
||||||
|
for k in keys[:-1]:
|
||||||
|
d = d.setdefault(k, {})
|
||||||
|
d[keys[-1]] = value
|
||||||
|
return result
|
||||||
|
|
||||||
|
with open(file_path, "w", encoding="utf-8") as file:
|
||||||
|
yaml.dump(nested_dict(self._config), file, allow_unicode=True)
|
||||||
|
|
||||||
|
def _check_rights(self, key, module_id, access_type="get"):
|
||||||
|
return
|
||||||
|
|
||||||
|
def get(self, key: str):
|
||||||
|
module_id = self._get_module_id()
|
||||||
|
self._check_rights(key, module_id)
|
||||||
|
return self._config.get(key, self._metadata.get(key).get("default_value"))
|
||||||
|
|
||||||
|
def get_meta(self, key: str):
|
||||||
|
module_id = self._get_module_id()
|
||||||
|
self._check_rights(key, module_id, "get_meta")
|
||||||
|
return self._metadata.get(key)
|
||||||
|
|
||||||
|
def _get_module_id(self):
|
||||||
|
caller_frame = inspect.currentframe().f_back.f_back
|
||||||
|
caller_globals = caller_frame.f_globals
|
||||||
|
module_id = caller_globals.get("__ocab_module_id__")
|
||||||
|
return module_id
|
||||||
|
|
||||||
|
def mass_set(self, updates: Dict[str, Any]):
|
||||||
|
module_id = self._get_module_id()
|
||||||
|
for key, value in updates.items():
|
||||||
|
self._check_rights(key, module_id, "set")
|
||||||
|
if key in self._metadata:
|
||||||
|
# TODO: add checks to validate the type and value based on metadata
|
||||||
|
self._config[key] = value
|
||||||
|
else:
|
||||||
|
raise KeyError(f"Key {key} is not registered.")
|
||||||
|
|
||||||
|
def register(
|
||||||
|
self,
|
||||||
|
key: str,
|
||||||
|
value_type: str,
|
||||||
|
options: List[Any] = None,
|
||||||
|
default_value=None,
|
||||||
|
editable: bool = True,
|
||||||
|
shared: bool = False,
|
||||||
|
required: bool = False,
|
||||||
|
visible: bool = True,
|
||||||
|
pretty_name: str = "",
|
||||||
|
description: str = "",
|
||||||
|
):
|
||||||
|
module_id = self._get_module_id()
|
||||||
|
|
||||||
|
self._check_rights(key, module_id, "register")
|
||||||
|
|
||||||
|
if key in self._metadata:
|
||||||
|
raise ValueError("ERROR")
|
||||||
|
|
||||||
|
self._metadata[key] = {
|
||||||
|
"type": value_type,
|
||||||
|
"options": options,
|
||||||
|
"default_value": default_value,
|
||||||
|
"visible": visible,
|
||||||
|
"editable": editable,
|
||||||
|
"shared": shared,
|
||||||
|
"required": required,
|
||||||
|
"pretty_name": pretty_name,
|
||||||
|
"description": description,
|
||||||
|
"module_id": module_id,
|
||||||
|
}
|
@ -5,5 +5,14 @@
|
|||||||
"author": "OCAB Team",
|
"author": "OCAB Team",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"privileged": true,
|
"privileged": true,
|
||||||
"dependencies": {}
|
"dependencies": {
|
||||||
|
"optional": {
|
||||||
|
"standard.miniapp": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pythonDependencies": {
|
||||||
|
"optional": {
|
||||||
|
"flet": "^0.23.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
30
src/ocab_modules/ocab_modules/standard/config/main.py
Normal file
30
src/ocab_modules/ocab_modules/standard/config/main.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from ocab_core.modules_system.public_api import get_module, log
|
||||||
|
|
||||||
|
from .config import config
|
||||||
|
from .miniapp_ui import get_miniapp_blueprint
|
||||||
|
|
||||||
|
|
||||||
|
def register_settings_page():
|
||||||
|
try:
|
||||||
|
register_page = get_module("standard.miniapp", "register_page")
|
||||||
|
|
||||||
|
prefix = "settings"
|
||||||
|
|
||||||
|
register_page(
|
||||||
|
name="Настройки",
|
||||||
|
path="/settings",
|
||||||
|
blueprint=get_miniapp_blueprint(config, prefix),
|
||||||
|
prefix=prefix,
|
||||||
|
role="ADMIN",
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log(str(e))
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def module_late_init():
|
||||||
|
register_settings_page()
|
||||||
|
|
||||||
|
pass
|
266
src/ocab_modules/ocab_modules/standard/config/miniapp_ui.py
Normal file
266
src/ocab_modules/ocab_modules/standard/config/miniapp_ui.py
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
import asyncio
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from .config_manager import ConfigManager
|
||||||
|
|
||||||
|
try:
|
||||||
|
import dash_bootstrap_components as dbc
|
||||||
|
import flask
|
||||||
|
from dash_extensions.enrich import ALL, Input, Output, State, dcc, html
|
||||||
|
|
||||||
|
DASH_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
DASH_AVAILABLE = False
|
||||||
|
|
||||||
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.roles import Roles as IRoles
|
||||||
|
|
||||||
|
|
||||||
|
def create_control(key: str, config: ConfigManager):
|
||||||
|
value = config.get(key)
|
||||||
|
meta = config.get_meta(key)
|
||||||
|
|
||||||
|
component_id = {
|
||||||
|
"type": "setting",
|
||||||
|
"key": key,
|
||||||
|
}
|
||||||
|
|
||||||
|
label_text = meta.get("pretty_name") or key
|
||||||
|
|
||||||
|
if meta.get("type") in ["string", "int", "float", "password"]:
|
||||||
|
input_type = {
|
||||||
|
"string": "text",
|
||||||
|
"int": "number",
|
||||||
|
"float": "number",
|
||||||
|
"password": "password",
|
||||||
|
}.get(meta.get("type"), "text")
|
||||||
|
|
||||||
|
input_props = {
|
||||||
|
"id": component_id,
|
||||||
|
"type": input_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
if meta.get("type") != "password":
|
||||||
|
input_props["value"] = value
|
||||||
|
|
||||||
|
if meta.get("type") == "int":
|
||||||
|
input_props["step"] = 1
|
||||||
|
input_props["pattern"] = r"\d+"
|
||||||
|
elif meta.get("type") == "float":
|
||||||
|
input_props["step"] = "any"
|
||||||
|
|
||||||
|
component = dbc.Input(**input_props, invalid=False)
|
||||||
|
|
||||||
|
elif meta.get("type") == "select":
|
||||||
|
options = [{"label": opt, "value": opt} for opt in meta.get("options", [])]
|
||||||
|
component = dcc.Dropdown(
|
||||||
|
id=component_id,
|
||||||
|
options=options,
|
||||||
|
value=value,
|
||||||
|
style={
|
||||||
|
"padding-left": 0,
|
||||||
|
"padding-right": 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif meta.get("type") == "checkbox":
|
||||||
|
component = dbc.Checkbox(
|
||||||
|
id=component_id,
|
||||||
|
checked=value,
|
||||||
|
label=label_text,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
row = []
|
||||||
|
if meta.get("type") != "checkbox":
|
||||||
|
row.append(dbc.Label(label_text))
|
||||||
|
|
||||||
|
row.append(component)
|
||||||
|
|
||||||
|
if meta.get("description"):
|
||||||
|
row.append(dbc.FormText(meta.get("description")))
|
||||||
|
|
||||||
|
return dbc.Row(row, className="mb-3 mx-1")
|
||||||
|
|
||||||
|
|
||||||
|
def build_settings_tree(config: ConfigManager):
|
||||||
|
tree = {}
|
||||||
|
|
||||||
|
for key, value in config._metadata.items():
|
||||||
|
if not value["visible"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
parts = key.split("::")
|
||||||
|
control = create_control(key, config)
|
||||||
|
|
||||||
|
current = tree
|
||||||
|
for i, part in enumerate(parts[:-1]):
|
||||||
|
if part not in current:
|
||||||
|
current[part] = {"__controls": []}
|
||||||
|
current = current[part]
|
||||||
|
|
||||||
|
current["__controls"].append(control)
|
||||||
|
|
||||||
|
return tree
|
||||||
|
|
||||||
|
|
||||||
|
def create_card(category, controls):
|
||||||
|
return dbc.Card(
|
||||||
|
[
|
||||||
|
dbc.CardHeader(html.H3(category, className="mb-0")),
|
||||||
|
dbc.CardBody(controls),
|
||||||
|
],
|
||||||
|
className="mb-3",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_settings_components(tree, level=0):
|
||||||
|
components = []
|
||||||
|
|
||||||
|
for category, subtree in tree.items():
|
||||||
|
if category == "__controls":
|
||||||
|
continue
|
||||||
|
|
||||||
|
controls = subtree.get("__controls", [])
|
||||||
|
subcomponents = create_settings_components(subtree, level + 1)
|
||||||
|
|
||||||
|
if controls or subcomponents:
|
||||||
|
card_content = controls + subcomponents
|
||||||
|
card = create_card(category, card_content)
|
||||||
|
components.append(card)
|
||||||
|
|
||||||
|
return components
|
||||||
|
|
||||||
|
|
||||||
|
def get_miniapp_blueprint(config: ConfigManager, prefix: str):
|
||||||
|
Roles: "type[IRoles]" = get_module("standard.roles", "Roles")
|
||||||
|
|
||||||
|
roles = Roles()
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from dash_extensions.enrich import DashBlueprint
|
||||||
|
|
||||||
|
bp = DashBlueprint()
|
||||||
|
|
||||||
|
def create_layout():
|
||||||
|
settings_tree = build_settings_tree(config)
|
||||||
|
settings_components = create_settings_components(settings_tree)
|
||||||
|
|
||||||
|
layout = html.Div(
|
||||||
|
[
|
||||||
|
html.Script(),
|
||||||
|
html.H1("Настройки"),
|
||||||
|
dbc.Form(settings_components),
|
||||||
|
html.Div(id="save-confirmation"),
|
||||||
|
dbc.Button(
|
||||||
|
"Сохранить",
|
||||||
|
id="save-settings",
|
||||||
|
color="primary",
|
||||||
|
className="mt-3 w-100",
|
||||||
|
n_clicks=0,
|
||||||
|
),
|
||||||
|
html.Div(id="settings-update-trigger", style={"display": "none"}),
|
||||||
|
dcc.Store(id="settings-store"),
|
||||||
|
],
|
||||||
|
style={
|
||||||
|
"padding": "20px",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return layout
|
||||||
|
|
||||||
|
bp.layout = create_layout
|
||||||
|
|
||||||
|
@bp.callback(
|
||||||
|
Output("save-confirmation", "children"),
|
||||||
|
Output("settings-store", "data"),
|
||||||
|
Input("save-settings", "n_clicks"),
|
||||||
|
State({"type": "setting", "key": ALL}, "value"),
|
||||||
|
State({"type": "setting", "key": ALL}, "id"),
|
||||||
|
prevent_initial_call=True,
|
||||||
|
allow_duplicate=True,
|
||||||
|
)
|
||||||
|
def save_settings(n_clicks, values, keys):
|
||||||
|
if n_clicks > 0:
|
||||||
|
user = getattr(flask.g, "user", None)
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
return (
|
||||||
|
dbc.Alert(
|
||||||
|
"Вы не авторизованы!",
|
||||||
|
color="danger",
|
||||||
|
duration=10000,
|
||||||
|
),
|
||||||
|
"-",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not asyncio.run(roles.check_admin_permission(user["id"])):
|
||||||
|
return (
|
||||||
|
dbc.Alert(
|
||||||
|
"Вы не администратор!",
|
||||||
|
color="danger",
|
||||||
|
duration=10000,
|
||||||
|
),
|
||||||
|
"-",
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: добавить валидацию значений
|
||||||
|
|
||||||
|
updated_settings = {}
|
||||||
|
for value, id_dict in zip(values, keys):
|
||||||
|
key: str = id_dict["key"]
|
||||||
|
if prefix:
|
||||||
|
key = key.removeprefix(f"{prefix}-")
|
||||||
|
|
||||||
|
meta = config.get_meta(key)
|
||||||
|
|
||||||
|
if meta["type"] == "password":
|
||||||
|
if value: # Only update if a new value is provided
|
||||||
|
updated_settings[key] = value
|
||||||
|
else:
|
||||||
|
updated_settings[key] = value
|
||||||
|
|
||||||
|
config.mass_set(updated_settings)
|
||||||
|
config.save()
|
||||||
|
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
date_str = now.strftime("%H:%M:%S")
|
||||||
|
|
||||||
|
return (
|
||||||
|
dbc.Alert(
|
||||||
|
f"Настройки сохранены в {date_str}",
|
||||||
|
color="success",
|
||||||
|
duration=10000,
|
||||||
|
),
|
||||||
|
date_str,
|
||||||
|
)
|
||||||
|
|
||||||
|
bp.clientside_callback(
|
||||||
|
"""
|
||||||
|
function(n_clicks) {
|
||||||
|
const buttonSelector = '#%s-save-settings';
|
||||||
|
if (n_clicks > 0) {
|
||||||
|
document.querySelector(buttonSelector).disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
% (prefix),
|
||||||
|
Input("save-settings", "n_clicks"),
|
||||||
|
)
|
||||||
|
|
||||||
|
bp.clientside_callback(
|
||||||
|
"""
|
||||||
|
function(data) {
|
||||||
|
const buttonSelector = '#%s-save-settings';
|
||||||
|
if (data) {
|
||||||
|
document.querySelector(buttonSelector).disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
% (prefix),
|
||||||
|
Input("settings-store", "data"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return bp
|
@ -1,9 +1,7 @@
|
|||||||
import peewee as pw
|
import peewee as pw
|
||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
|
|
||||||
from src.service import paths
|
from .exceptions import NotExpectedModuleName
|
||||||
|
|
||||||
from .exceptions import MissingModuleName, NotExpectedModuleName
|
|
||||||
from .models.chat_stats import ChatStats
|
from .models.chat_stats import ChatStats
|
||||||
from .models.chats import Chats
|
from .models.chats import Chats
|
||||||
from .models.db import database_proxy
|
from .models.db import database_proxy
|
||||||
@ -14,14 +12,9 @@ from .models.users import Users
|
|||||||
|
|
||||||
|
|
||||||
def connect_database(is_test: bool = False, module: str | None = None):
|
def connect_database(is_test: bool = False, module: str | None = None):
|
||||||
if is_test:
|
|
||||||
if not module:
|
|
||||||
raise MissingModuleName()
|
|
||||||
db_path = f"{paths.modules_standard}/{module}/tests/database"
|
|
||||||
else:
|
|
||||||
if module:
|
if module:
|
||||||
raise NotExpectedModuleName()
|
raise NotExpectedModuleName()
|
||||||
db_path = f"{paths.core}/database"
|
db_path = "database"
|
||||||
|
|
||||||
database = pw.SqliteDatabase(f"{db_path}/OCAB.db")
|
database = pw.SqliteDatabase(f"{db_path}/OCAB.db")
|
||||||
database_proxy.initialize(database)
|
database_proxy.initialize(database)
|
||||||
@ -158,7 +151,7 @@ def get_user_name(user_id):
|
|||||||
return user.user_name if user else None
|
return user.user_name if user else None
|
||||||
|
|
||||||
|
|
||||||
def get_user_role(user_id):
|
def get_user_role(user_id: str):
|
||||||
user = Users.get_or_none(Users.id == user_id)
|
user = Users.get_or_none(Users.id == user_id)
|
||||||
return user.user_role if user else None
|
return user.user_role if user else None
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user