From 067fa52719fd911e266cc9a2e73b85e2cc1cacd5 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Sun, 11 Aug 2024 09:13:30 +0300 Subject: [PATCH 01/38] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20src/altlinux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ocab.code-workspace | 4 + src/altlinux/Dockerfile | 23 + src/altlinux/Dockerfile.dockerignore | 14 + src/altlinux/README.md | 47 + src/altlinux/altlinux/__init__.py | 0 src/altlinux/altlinux/__main__.py | 19 + src/altlinux/config-example.yaml | 7 + src/altlinux/docker-compose.yml | 9 + src/altlinux/poetry.lock | 2162 ++++++++++++++++++++++++++ src/altlinux/poetry.toml | 2 + src/altlinux/pyproject.toml | 17 + 11 files changed, 2304 insertions(+) create mode 100644 src/altlinux/Dockerfile create mode 100644 src/altlinux/Dockerfile.dockerignore create mode 100644 src/altlinux/README.md create mode 100644 src/altlinux/altlinux/__init__.py create mode 100644 src/altlinux/altlinux/__main__.py create mode 100644 src/altlinux/config-example.yaml create mode 100644 src/altlinux/docker-compose.yml create mode 100644 src/altlinux/poetry.lock create mode 100644 src/altlinux/poetry.toml create mode 100644 src/altlinux/pyproject.toml diff --git a/ocab.code-workspace b/ocab.code-workspace index 2b34c84..96f794e 100644 --- a/ocab.code-workspace +++ b/ocab.code-workspace @@ -15,6 +15,10 @@ { "name": "Gnomik", "path": "src/gnomik" + }, + { + "name": "ALT Linux", + "path": "src/altlinux" } ], "extensions": { diff --git a/src/altlinux/Dockerfile b/src/altlinux/Dockerfile new file mode 100644 index 0000000..c789f02 --- /dev/null +++ b/src/altlinux/Dockerfile @@ -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/altlinux/pyproject.toml && \ + sed -i '/ocab-modules = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \ + sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/ocab_modules/pyproject.toml + +WORKDIR /app/src/altlinux + +RUN poetry lock && poetry install + +FROM python:3.12-slim as base + +COPY --from=builder /app/src/altlinux /app + +WORKDIR /app +ENV PATH="/app/.venv/bin:$PATH" +CMD ["python", "-m", "altlinux"] diff --git a/src/altlinux/Dockerfile.dockerignore b/src/altlinux/Dockerfile.dockerignore new file mode 100644 index 0000000..f9df4a3 --- /dev/null +++ b/src/altlinux/Dockerfile.dockerignore @@ -0,0 +1,14 @@ +**/Dockerfile +**/*.dockerignore +**/docker-compose.yml + +**/.git +**/.gitignore + +**/.venv + +**/.mypy_cache +**/__pycache__/ + +src/gnomik/config.yaml +src/gnomik/database/* diff --git a/src/altlinux/README.md b/src/altlinux/README.md new file mode 100644 index 0000000..c700e6b --- /dev/null +++ b/src/altlinux/README.md @@ -0,0 +1,47 @@ +# ALT Linux + +## Описание + + + +## Функционал + + + +## Запуск + +### 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`. diff --git a/src/altlinux/altlinux/__init__.py b/src/altlinux/altlinux/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/altlinux/altlinux/__main__.py b/src/altlinux/altlinux/__main__.py new file mode 100644 index 0000000..d99d89e --- /dev/null +++ b/src/altlinux/altlinux/__main__.py @@ -0,0 +1,19 @@ +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", "command_helper"), + # module_loader("standard", "report"), + ] + ) + await ocab.start() + + +asyncio.run(main()) diff --git a/src/altlinux/config-example.yaml b/src/altlinux/config-example.yaml new file mode 100644 index 0000000..6014227 --- /dev/null +++ b/src/altlinux/config-example.yaml @@ -0,0 +1,7 @@ +core: + mode: LONG_POLLING + token: xxx + +report: + allowed_groups: + - -1111111 \ No newline at end of file diff --git a/src/altlinux/docker-compose.yml b/src/altlinux/docker-compose.yml new file mode 100644 index 0000000..47c8c01 --- /dev/null +++ b/src/altlinux/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3' + +services: + app: + build: + context: ../.. + dockerfile: src/altlinux/Dockerfile + volumes: + - ./config.yaml:/app/config.yaml diff --git a/src/altlinux/poetry.lock b/src/altlinux/poetry.lock new file mode 100644 index 0000000..5224dc3 --- /dev/null +++ b/src/altlinux/poetry.lock @@ -0,0 +1,2162 @@ +# 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 = "anyio" +version = "4.4.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[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]] +name = "blinker" +version = "1.8.2" +description = "Fast, simple object-to-object and broadcast signaling" +optional = false +python-versions = ">=3.8" +files = [ + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, +] + +[[package]] +name = "cachelib" +version = "0.9.0" +description = "A collection of cache libraries in the same API interface." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cachelib-0.9.0-py3-none-any.whl", hash = "sha256:811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3"}, + {file = "cachelib-0.9.0.tar.gz", hash = "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5"}, +] + +[[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]] +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]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dash" +version = "2.17.1" +description = "A Python framework for building reactive web-apps. Developed by Plotly." +optional = false +python-versions = ">=3.8" +files = [ + {file = "dash-2.17.1-py3-none-any.whl", hash = "sha256:3eefc9ac67003f93a06bc3e500cae0a6787c48e6c81f6f61514239ae2da414e4"}, + {file = "dash-2.17.1.tar.gz", hash = "sha256:ee2d9c319de5dcc1314085710b72cd5fa63ff994d913bf72979b7130daeea28e"}, +] + +[package.dependencies] +dash-core-components = "2.0.0" +dash-html-components = "2.0.0" +dash-table = "5.0.0" +Flask = ">=1.0.4,<3.1" +importlib-metadata = "*" +nest-asyncio = "*" +plotly = ">=5.0.0" +requests = "*" +retrying = "*" +setuptools = "*" +typing-extensions = ">=4.1.1" +Werkzeug = "<3.1" + +[package.extras] +celery = ["celery[redis] (>=5.1.2)", "redis (>=3.5.3)"] +ci = ["black (==22.3.0)", "dash-dangerously-set-inner-html", "dash-flow-example (==0.0.5)", "flake8 (==7.0.0)", "flaky (==3.8.1)", "flask-talisman (==1.0.0)", "jupyterlab (<4.0.0)", "mimesis (<=11.1.0)", "mock (==4.0.3)", "numpy (<=1.26.3)", "openpyxl", "orjson (==3.10.3)", "pandas (>=1.4.0)", "pyarrow", "pylint (==3.0.3)", "pytest-mock", "pytest-rerunfailures", "pytest-sugar (==0.9.6)", "pyzmq (==25.1.2)", "xlrd (>=2.0.1)"] +compress = ["flask-compress"] +dev = ["PyYAML (>=5.4.1)", "coloredlogs (>=15.0.1)", "fire (>=0.4.0)"] +diskcache = ["diskcache (>=5.2.1)", "multiprocess (>=0.70.12)", "psutil (>=5.8.0)"] +testing = ["beautifulsoup4 (>=4.8.2)", "cryptography", "dash-testing-stub (>=0.0.2)", "lxml (>=4.6.2)", "multiprocess (>=0.70.12)", "percy (>=2.0.2)", "psutil (>=5.8.0)", "pytest (>=6.0.2)", "requests[security] (>=2.21.0)", "selenium (>=3.141.0,<=4.2.0)", "waitress (>=1.4.4)"] + +[[package]] +name = "dash-bootstrap-components" +version = "1.6.0" +description = "Bootstrap themed components for use in Plotly Dash" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "dash_bootstrap_components-1.6.0-py3-none-any.whl", hash = "sha256:97f0f47b38363f18863e1b247462229266ce12e1e171cfb34d3c9898e6e5cd1e"}, + {file = "dash_bootstrap_components-1.6.0.tar.gz", hash = "sha256:960a1ec9397574792f49a8241024fa3cecde0f5930c971a3fc81f016cbeb1095"}, +] + +[package.dependencies] +dash = ">=2.0.0" + +[package.extras] +pandas = ["numpy", "pandas"] + +[[package]] +name = "dash-core-components" +version = "2.0.0" +description = "Core component suite for Dash" +optional = false +python-versions = "*" +files = [ + {file = "dash_core_components-2.0.0-py3-none-any.whl", hash = "sha256:52b8e8cce13b18d0802ee3acbc5e888cb1248a04968f962d63d070400af2e346"}, + {file = "dash_core_components-2.0.0.tar.gz", hash = "sha256:c6733874af975e552f95a1398a16c2ee7df14ce43fa60bb3718a3c6e0b63ffee"}, +] + +[[package]] +name = "dash-extensions" +version = "1.0.18" +description = "Extensions for Plotly Dash." +optional = false +python-versions = "<4,>=3.9" +files = [ + {file = "dash_extensions-1.0.18-py3-none-any.whl", hash = "sha256:17f4469670bd70ce12fac1a05baaae119fb65eee7b012af47aff7377d0399eeb"}, + {file = "dash_extensions-1.0.18.tar.gz", hash = "sha256:a6b6c0952b3af7ae84c418fea4b43cbd0bd4e82f20d91f1573380b8a3d90df0a"}, +] + +[package.dependencies] +dash = ">=2.17.0" +dataclass-wizard = ">=0.22.2,<0.23.0" +Flask-Caching = ">=2.1.0,<3.0.0" +jsbeautifier = ">=1.14.3,<2.0.0" +more-itertools = ">=10.2.0,<11.0.0" +pydantic = ">=2.7.1,<3.0.0" +ruff = ">=0.4.5,<0.5.0" + +[package.extras] +mantine = ["dash-mantine-components (>=0.14.3,<0.15.0)"] + +[[package]] +name = "dash-html-components" +version = "2.0.0" +description = "Vanilla HTML components for Dash" +optional = false +python-versions = "*" +files = [ + {file = "dash_html_components-2.0.0-py3-none-any.whl", hash = "sha256:b42cc903713c9706af03b3f2548bda4be7307a7cf89b7d6eae3da872717d1b63"}, + {file = "dash_html_components-2.0.0.tar.gz", hash = "sha256:8703a601080f02619a6390998e0b3da4a5daabe97a1fd7a9cebc09d015f26e50"}, +] + +[[package]] +name = "dash-table" +version = "5.0.0" +description = "Dash table" +optional = false +python-versions = "*" +files = [ + {file = "dash_table-5.0.0-py3-none-any.whl", hash = "sha256:19036fa352bb1c11baf38068ec62d172f0515f73ca3276c79dee49b95ddc16c9"}, + {file = "dash_table-5.0.0.tar.gz", hash = "sha256:18624d693d4c8ef2ddec99a6f167593437a7ea0bf153aa20f318c170c5bc7308"}, +] + +[[package]] +name = "dataclass-wizard" +version = "0.22.3" +description = "Marshal dataclasses to/from JSON. Use field properties with initial values. Construct a dataclass schema with JSON input." +optional = false +python-versions = "*" +files = [ + {file = "dataclass-wizard-0.22.3.tar.gz", hash = "sha256:4c46591782265058f1148cfd1f54a3a91221e63986fdd04c9d59f4ced61f4424"}, + {file = "dataclass_wizard-0.22.3-py2.py3-none-any.whl", hash = "sha256:63751203e54b9b9349212cc185331da73c1adc99c51312575eb73bb5c00c1962"}, +] + +[package.extras] +dev = ["Sphinx (==5.3.0)", "bump2version (==1.0.1)", "coverage (>=6.2)", "dataclass-factory (==2.12)", "dataclasses-json (==0.5.6)", "flake8 (>=3)", "jsons (==1.6.1)", "pip (>=21.3.1)", "pytest (==7.0.1)", "pytest-cov (==3.0.0)", "pytest-mock (>=3.6.1)", "pytimeparse (==1.1.8)", "sphinx-issues (==3.0.1)", "sphinx-issues (==4.0.0)", "tox (==3.24.5)", "twine (==3.8.0)", "watchdog[watchmedo] (==2.1.6)", "wheel (==0.37.1)", "wheel (==0.42.0)"] +timedelta = ["pytimeparse (>=1.1.7)"] +yaml = ["PyYAML (>=5.3)"] + +[[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]] +name = "dnspython" +version = "2.6.1" +description = "DNS toolkit" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, +] + +[package.extras] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] + +[[package]] +name = "editorconfig" +version = "0.12.4" +description = "EditorConfig File Locator and Interpreter for Python" +optional = false +python-versions = "*" +files = [ + {file = "EditorConfig-0.12.4.tar.gz", hash = "sha256:24857fa1793917dd9ccf0c7810a07e05404ce9b823521c7dce22a4fb5d125f80"}, +] + +[[package]] +name = "email-validator" +version = "2.2.0" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, + {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + +[[package]] +name = "fastapi" +version = "0.111.1" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi-0.111.1-py3-none-any.whl", hash = "sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf"}, + {file = "fastapi-0.111.1.tar.gz", hash = "sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413"}, +] + +[package.dependencies] +email_validator = ">=2.0.0" +fastapi-cli = ">=0.0.2" +httpx = ">=0.23.0" +jinja2 = ">=2.11.2" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +python-multipart = ">=0.0.7" +starlette = ">=0.37.2,<0.38.0" +typing-extensions = ">=4.8.0" +uvicorn = {version = ">=0.12.0", extras = ["standard"]} + +[package.extras] +all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "fastapi-cli" +version = "0.0.4" +description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, + {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, +] + +[package.dependencies] +typer = ">=0.12.3" + +[package.extras] +standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] + +[[package]] +name = "flask" +version = "3.0.3" +description = "A simple framework for building complex web applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, + {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, +] + +[package.dependencies] +blinker = ">=1.6.2" +click = ">=8.1.3" +itsdangerous = ">=2.1.2" +Jinja2 = ">=3.1.2" +Werkzeug = ">=3.0.0" + +[package.extras] +async = ["asgiref (>=3.2)"] +dotenv = ["python-dotenv"] + +[[package]] +name = "flask-caching" +version = "2.3.0" +description = "Adds caching support to Flask applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Flask_Caching-2.3.0-py3-none-any.whl", hash = "sha256:51771c75682e5abc1483b78b96d9131d7941dc669b073852edfa319dd4e29b6e"}, + {file = "flask_caching-2.3.0.tar.gz", hash = "sha256:d7e4ca64a33b49feb339fcdd17e6ba25f5e01168cf885e53790e885f83a4d2cf"}, +] + +[package.dependencies] +cachelib = ">=0.9.0,<0.10.0" +Flask = "*" + +[[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]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "h2" +version = "4.1.0" +description = "HTTP/2 State-Machine based protocol implementation" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, +] + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] + +[[package]] +name = "httpcore" +version = "1.0.5" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.26.0)"] + +[[package]] +name = "httptools" +version = "0.6.1" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, + {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, + {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, + {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, + {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, + {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, + {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, +] + +[package.extras] +test = ["Cython (>=0.29.24,<0.30.0)"] + +[[package]] +name = "httpx" +version = "0.27.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "hypercorn" +version = "0.17.3" +description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" +optional = false +python-versions = ">=3.8" +files = [ + {file = "hypercorn-0.17.3-py3-none-any.whl", hash = "sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"}, + {file = "hypercorn-0.17.3.tar.gz", hash = "sha256:1b37802ee3ac52d2d85270700d565787ab16cf19e1462ccfa9f089ca17574165"}, +] + +[package.dependencies] +h11 = "*" +h2 = ">=3.1.0" +priority = "*" +wsproto = ">=0.14.0" + +[package.extras] +docs = ["pydata_sphinx_theme", "sphinxcontrib_mermaid"] +h3 = ["aioquic (>=0.9.0,<1.0)"] +trio = ["trio (>=0.22.0)"] +uvloop = ["uvloop (>=0.18)"] + +[[package]] +name = "hyperframe" +version = "6.0.1" +description = "HTTP/2 framing layer for Python" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] + +[[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]] +name = "importlib-metadata" +version = "8.2.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, + {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "itsdangerous" +version = "2.2.0" +description = "Safely pass data to untrusted environments and back." +optional = false +python-versions = ">=3.8" +files = [ + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsbeautifier" +version = "1.15.1" +description = "JavaScript unobfuscator and beautifier." +optional = false +python-versions = "*" +files = [ + {file = "jsbeautifier-1.15.1.tar.gz", hash = "sha256:ebd733b560704c602d744eafc839db60a1ee9326e30a2a80c4adb8718adc1b24"}, +] + +[package.dependencies] +editorconfig = ">=0.12.2" +six = ">=1.13.0" + +[[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]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[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]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "more-itertools" +version = "10.3.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.8" +files = [ + {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, + {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, +] + +[[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]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + +[[package]] +name = "ocab-core" +version = "0.1.0" +description = "" +optional = false +python-versions = "~3.12" +files = [] +develop = true + +[package.dependencies] +aiogram = "^3.10.0" +dataclasses-json = "^0.6.7" +fastapi = {version = "^0.111.1", optional = true} +hypercorn = {version = "^0.17.3", optional = true} +restrictedpython = "^7.1" +semver = "^3.0.2" +setuptools = "^71.0.1" + +[package.extras] +webhook = ["fastapi (>=0.111.1,<0.112.0)", "hypercorn (>=0.17.3,<0.18.0)"] + +[package.source] +type = "directory" +url = "../ocab_core" + +[[package]] +name = "ocab-modules" +version = "0.1.0" +description = "" +optional = false +python-versions = "~3.12" +files = [] +develop = true + +[package.dependencies] +dash = "^2.17.1" +dash-bootstrap-components = "^1.6.0" +dash-extensions = "^1.0.18" +ocab-core = {path = "../ocab_core", develop = true} +peewee = "^3.17.6" +pyyaml = "^6.0.1" + +[package.source] +type = "directory" +url = "../ocab_modules" + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[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]] +name = "plotly" +version = "5.23.0" +description = "An open-source, interactive data visualization library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "plotly-5.23.0-py3-none-any.whl", hash = "sha256:76cbe78f75eddc10c56f5a4ee3e7ccaade7c0a57465546f02098c0caed6c2d1a"}, + {file = "plotly-5.23.0.tar.gz", hash = "sha256:89e57d003a116303a34de6700862391367dd564222ab71f8531df70279fc0193"}, +] + +[package.dependencies] +packaging = "*" +tenacity = ">=6.2.0" + +[[package]] +name = "priority" +version = "2.0.0" +description = "A pure-Python implementation of the HTTP/2 priority tree" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, + {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, +] + +[[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]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-multipart" +version = "0.0.9" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, + {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, +] + +[package.extras] +dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {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]] +name = "retrying" +version = "1.3.4" +description = "Retrying" +optional = false +python-versions = "*" +files = [ + {file = "retrying-1.3.4-py3-none-any.whl", hash = "sha256:8cc4d43cb8e1125e0ff3344e9de678fefd85db3b750b81b2240dc0183af37b35"}, + {file = "retrying-1.3.4.tar.gz", hash = "sha256:345da8c5765bd982b1d1915deb9102fd3d1f7ad16bd84a9700b85f64d24e8f3e"}, +] + +[package.dependencies] +six = ">=1.7.0" + +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "ruff" +version = "0.4.10" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac"}, + {file = "ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695"}, + {file = "ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca"}, + {file = "ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7"}, + {file = "ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0"}, + {file = "ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804"}, +] + +[[package]] +name = "semver" +version = "3.0.2" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4"}, + {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, +] + +[[package]] +name = "setuptools" +version = "71.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855"}, + {file = "setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936"}, +] + +[package.extras] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "starlette" +version = "0.37.2" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.8" +files = [ + {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, + {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] + +[[package]] +name = "tenacity" +version = "8.5.0" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"}, + {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"}, +] + +[package.extras] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] + +[[package]] +name = "typer" +version = "0.12.3" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.7" +files = [ + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + +[[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]] +name = "uvicorn" +version = "0.30.3" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.8" +files = [ + {file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"}, + {file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "uvloop" +version = "0.19.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, + {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, +] + +[package.extras] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + +[[package]] +name = "watchfiles" +version = "0.22.0" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchfiles-0.22.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538"}, + {file = "watchfiles-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71"}, + {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39"}, + {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848"}, + {file = "watchfiles-0.22.0-cp310-none-win32.whl", hash = "sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797"}, + {file = "watchfiles-0.22.0-cp310-none-win_amd64.whl", hash = "sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb"}, + {file = "watchfiles-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96"}, + {file = "watchfiles-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f"}, + {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d"}, + {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c"}, + {file = "watchfiles-0.22.0-cp311-none-win32.whl", hash = "sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67"}, + {file = "watchfiles-0.22.0-cp311-none-win_amd64.whl", hash = "sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1"}, + {file = "watchfiles-0.22.0-cp311-none-win_arm64.whl", hash = "sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84"}, + {file = "watchfiles-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a"}, + {file = "watchfiles-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27"}, + {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b"}, + {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35"}, + {file = "watchfiles-0.22.0-cp312-none-win32.whl", hash = "sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e"}, + {file = "watchfiles-0.22.0-cp312-none-win_amd64.whl", hash = "sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e"}, + {file = "watchfiles-0.22.0-cp312-none-win_arm64.whl", hash = "sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea"}, + {file = "watchfiles-0.22.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d47e9ef1a94cc7a536039e46738e17cce058ac1593b2eccdede8bf72e45f372a"}, + {file = "watchfiles-0.22.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28f393c1194b6eaadcdd8f941307fc9bbd7eb567995232c830f6aef38e8a6e88"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd64f3a4db121bc161644c9e10a9acdb836853155a108c2446db2f5ae1778c3d"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2abeb79209630da981f8ebca30a2c84b4c3516a214451bfc5f106723c5f45843"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cc382083afba7918e32d5ef12321421ef43d685b9a67cc452a6e6e18920890e"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d048ad5d25b363ba1d19f92dcf29023988524bee6f9d952130b316c5802069cb"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:103622865599f8082f03af4214eaff90e2426edff5e8522c8f9e93dc17caee13"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e1f3cf81f1f823e7874ae563457828e940d75573c8fbf0ee66818c8b6a9099"}, + {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8597b6f9dc410bdafc8bb362dac1cbc9b4684a8310e16b1ff5eee8725d13dcd6"}, + {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b04a2cbc30e110303baa6d3ddce8ca3664bc3403be0f0ad513d1843a41c97d1"}, + {file = "watchfiles-0.22.0-cp38-none-win32.whl", hash = "sha256:b610fb5e27825b570554d01cec427b6620ce9bd21ff8ab775fc3a32f28bba63e"}, + {file = "watchfiles-0.22.0-cp38-none-win_amd64.whl", hash = "sha256:fe82d13461418ca5e5a808a9e40f79c1879351fcaeddbede094028e74d836e86"}, + {file = "watchfiles-0.22.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3973145235a38f73c61474d56ad6199124e7488822f3a4fc97c72009751ae3b0"}, + {file = "watchfiles-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:280a4afbc607cdfc9571b9904b03a478fc9f08bbeec382d648181c695648202f"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a0d883351a34c01bd53cfa75cd0292e3f7e268bacf2f9e33af4ecede7e21d1d"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9165bcab15f2b6d90eedc5c20a7f8a03156b3773e5fb06a790b54ccecdb73385"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc1b9b56f051209be458b87edb6856a449ad3f803315d87b2da4c93b43a6fe72"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc1fc25a1dedf2dd952909c8e5cb210791e5f2d9bc5e0e8ebc28dd42fed7562"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc92d2d2706d2b862ce0568b24987eba51e17e14b79a1abcd2edc39e48e743c8"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97b94e14b88409c58cdf4a8eaf0e67dfd3ece7e9ce7140ea6ff48b0407a593ec"}, + {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96eec15e5ea7c0b6eb5bfffe990fc7c6bd833acf7e26704eb18387fb2f5fd087"}, + {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:28324d6b28bcb8d7c1041648d7b63be07a16db5510bea923fc80b91a2a6cbed6"}, + {file = "watchfiles-0.22.0-cp39-none-win32.whl", hash = "sha256:8c3e3675e6e39dc59b8fe5c914a19d30029e36e9f99468dddffd432d8a7b1c93"}, + {file = "watchfiles-0.22.0-cp39-none-win_amd64.whl", hash = "sha256:25c817ff2a86bc3de3ed2df1703e3d24ce03479b27bb4527c57e722f8554d971"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5834e1f8b71476a26df97d121c0c0ed3549d869124ed2433e02491553cb468c2"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:0bc3b2f93a140df6806c8467c7f51ed5e55a931b031b5c2d7ff6132292e803d6"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fdebb655bb1ba0122402352b0a4254812717a017d2dc49372a1d47e24073795"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c8e0aa0e8cc2a43561e0184c0513e291ca891db13a269d8d47cb9841ced7c71"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2f350cbaa4bb812314af5dab0eb8d538481e2e2279472890864547f3fe2281ed"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7a74436c415843af2a769b36bf043b6ccbc0f8d784814ba3d42fc961cdb0a9dc"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00ad0bcd399503a84cc688590cdffbe7a991691314dde5b57b3ed50a41319a31"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a44e9481afc7a5ee3291b09c419abab93b7e9c306c9ef9108cb76728ca58d2"}, + {file = "watchfiles-0.22.0.tar.gz", hash = "sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + +[[package]] +name = "websockets" +version = "12.0" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, + {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, + {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, + {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, + {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, + {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, + {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, + {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, + {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, + {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, + {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, + {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, + {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, + {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, + {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, + {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, + {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, + {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, + {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, + {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, + {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, + {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, + {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, + {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, + {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, +] + +[[package]] +name = "werkzeug" +version = "3.0.3" +description = "The comprehensive WSGI web application library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, + {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog (>=2.3)"] + +[[package]] +name = "wsproto" +version = "1.2.0" +description = "WebSockets state-machine based protocol implementation" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, + {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, +] + +[package.dependencies] +h11 = ">=0.9.0,<1" + +[[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" + +[[package]] +name = "zipp" +version = "3.19.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, +] + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[metadata] +lock-version = "2.0" +python-versions = "~3.12" +content-hash = "63f870b298f75049e8fb6fe1a5fa9482e4bfb2d624c8bc6bf3dfc6bafa1c05c3" diff --git a/src/altlinux/poetry.toml b/src/altlinux/poetry.toml new file mode 100644 index 0000000..ab1033b --- /dev/null +++ b/src/altlinux/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/src/altlinux/pyproject.toml b/src/altlinux/pyproject.toml new file mode 100644 index 0000000..38e816d --- /dev/null +++ b/src/altlinux/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "altlinux" +version = "0.1.0" +description = "" +authors = [ + "Максим Слипенко " +] +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" From 01912850e2fdb5f29ac5d68aefe060a31164a733 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Sun, 11 Aug 2024 09:47:38 +0300 Subject: [PATCH 02/38] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20standard.?= =?UTF-8?q?reports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - добавлен модуль standard.reports - убрана обязательная зависимость в других модулях - в config добавлен multiple --- src/altlinux/altlinux/__main__.py | 4 +- .../ocab_modules/standard/admin/info.json | 3 +- .../standard/command_helper/__init__.py | 2 +- .../standard/command_helper/info.json | 7 +- .../standard/command_helper/main.py | 70 ++----------------- .../standard/config/config_manager.py | 4 +- .../ocab_modules/standard/filters/__init__.py | 1 + .../ocab_modules/standard/filters/filters.py | 52 ++++++++++---- .../ocab_modules/standard/filters/info.json | 6 +- .../ocab_modules/standard/report/README.md | 18 +++++ .../ocab_modules/standard/report/__init__.py | 1 + .../ocab_modules/standard/report/info.json | 14 ++++ .../ocab_modules/standard/report/main.py | 69 ++++++++++++++++++ 13 files changed, 159 insertions(+), 92 deletions(-) create mode 100644 src/ocab_modules/ocab_modules/standard/report/README.md create mode 100644 src/ocab_modules/ocab_modules/standard/report/__init__.py create mode 100644 src/ocab_modules/ocab_modules/standard/report/info.json create mode 100644 src/ocab_modules/ocab_modules/standard/report/main.py diff --git a/src/altlinux/altlinux/__main__.py b/src/altlinux/altlinux/__main__.py index d99d89e..c99c3f4 100644 --- a/src/altlinux/altlinux/__main__.py +++ b/src/altlinux/altlinux/__main__.py @@ -10,7 +10,9 @@ async def main(): [ module_loader("standard", "config", safe=False), module_loader("standard", "command_helper"), - # module_loader("standard", "report"), + # safe=False из-за super().__init__() + module_loader("standard", "filters", safe=False), + module_loader("standard", "report"), ] ) await ocab.start() diff --git a/src/ocab_modules/ocab_modules/standard/admin/info.json b/src/ocab_modules/ocab_modules/standard/admin/info.json index b2d01d3..a3eae7a 100644 --- a/src/ocab_modules/ocab_modules/standard/admin/info.json +++ b/src/ocab_modules/ocab_modules/standard/admin/info.json @@ -7,7 +7,8 @@ "privileged": false, "dependencies": { "required": { - "standard.filters": "^1.0.0" + "standard.filters": "^1.0.0", + "standard.roles": "^1.0.0" } } } diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py b/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py index 9b3ee14..90596da 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py +++ b/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py @@ -1 +1 @@ -from .main import module_init, register_command +from .main import module_late_init, register_command diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/info.json b/src/ocab_modules/ocab_modules/standard/command_helper/info.json index dda6c9e..00a14dc 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/info.json +++ b/src/ocab_modules/ocab_modules/standard/command_helper/info.json @@ -5,10 +5,5 @@ "author": "OCAB Team", "version": "1.0.0", "privileged": false, - "dependencies": { - "required": { - "standard.roles": "^1.0.0", - "standard.database": "^1.0.0" - } - } + "dependencies": {} } diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/main.py b/src/ocab_modules/ocab_modules/standard/command_helper/main.py index 37f78e6..d33d1ba 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/main.py +++ b/src/ocab_modules/ocab_modules/standard/command_helper/main.py @@ -1,28 +1,11 @@ -from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict - -from aiogram import BaseMiddleware -from aiogram.types import BotCommand, TelegramObject +from aiogram.types import BotCommand from ocab_core.modules_system.public_api import ( - get_module, - register_outer_message_middleware, - set_my_commands, + set_my_commands, log ) -if TYPE_CHECKING: - from ocab_modules.standard.database import db_api as IDbApi - from ocab_modules.standard.roles import Roles as IRoles - commands = dict() -db_api: "IDbApi" = get_module( - "standard.database", - "db_api", -) - -Roles: "IRoles" = get_module("standard.roles", "Roles") - - def register_command(command, description, role="USER"): if role not in commands: commands[role] = dict() @@ -31,53 +14,6 @@ def register_command(command, description, role="USER"): } -class OuterMiddleware(BaseMiddleware): - async def __call__( - self, - handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]], - event: TelegramObject, - data: Dict[str, Any], - ): - - # if not isinstance(event, Message): - # return await handler(event, data) - # - # user = db_api.get_user(event.from_user.id) - # - # if user is None: - # return - # - # roles = Roles() - # role_name = await roles.get_role_name(role_id=user.user_role) - # - # if role_name not in commands: - # return await handler(event, data) - - # bot_commands = [] - - # for role_command in commands[role_name]: - # bot_commands.append( - # BotCommand( - # command=role_command, - # description=commands[role_name][role_command]["description"], - # ) - # ) - - # await event.bot.set_my_commands( - # bot_commands, - # BotCommandScopeChatMember( - # chat_id=event.chat.id, - # user_id=event.from_user.id, - # ), - # ) - - return await handler(event, data) - - -async def module_init(): - register_outer_message_middleware(OuterMiddleware()) - - async def set_user_commands(): bot_commands = [] if "USER" in commands: @@ -90,6 +26,8 @@ async def set_user_commands(): ) ) + log(bot_commands) + await set_my_commands( bot_commands, ) diff --git a/src/ocab_modules/ocab_modules/standard/config/config_manager.py b/src/ocab_modules/ocab_modules/standard/config/config_manager.py index b6b1a1c..adbcfe3 100644 --- a/src/ocab_modules/ocab_modules/standard/config/config_manager.py +++ b/src/ocab_modules/ocab_modules/standard/config/config_manager.py @@ -84,7 +84,8 @@ class ConfigManager: key: str, value_type: str, options: List[Any] = None, - default_value=None, + multiple: bool = False, + default_value = None, editable: bool = True, shared: bool = False, required: bool = False, @@ -101,6 +102,7 @@ class ConfigManager: self._metadata[key] = { "type": value_type, + "multiple": multiple, "options": options, "default_value": default_value, "visible": visible, diff --git a/src/ocab_modules/ocab_modules/standard/filters/__init__.py b/src/ocab_modules/ocab_modules/standard/filters/__init__.py index 7b423c4..ed9efdd 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/__init__.py +++ b/src/ocab_modules/ocab_modules/standard/filters/__init__.py @@ -1,6 +1,7 @@ from .filters import ( ChatModerOrAdminFilter, ChatNotInApproveFilter, + ChatIDFilter, chat_not_in_approve, module_init, ) diff --git a/src/ocab_modules/ocab_modules/standard/filters/filters.py b/src/ocab_modules/ocab_modules/standard/filters/filters.py index 6e71916..102bf42 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/filters.py +++ b/src/ocab_modules/ocab_modules/standard/filters/filters.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING +from typing_extensions import deprecated from aiogram import Bot from aiogram.filters import BaseFilter @@ -8,35 +9,63 @@ from ocab_core.modules_system.public_api import get_module, log if TYPE_CHECKING: from ocab_modules.standard.config import IConfig + from ocab_modules.standard.roles import Roles as IRoles + config: "IConfig" = get_module("standard.config", "config") -Roles = get_module("standard.roles", "Roles") +try: + Roles: "type[IRoles]" = get_module("standard.roles", "Roles") + ROLES_MODULE_LOADED = True +except Exception: + ROLES_MODULE_LOADED = False + pass def module_init(): - config.register("filters::approved_chat_id", "string", shared=True) + config.register("filters::approved_chat_id", "int", multiple=True, shared=True, default_value=[]) config.register("filters::default_chat_tag", "string", shared=True) def get_approved_chat_id() -> list: - # Возваращем сплитованный список id чатов в формате int - return [ - int(chat_id) for chat_id in config.get("filters::approved_chat_id").split(" | ") - ] + return config.get("filters::approved_chat_id") +@deprecated("Use ChatIDFilter or own implementation") def chat_not_in_approve(message: Message) -> bool: chat_id = message.chat.id if chat_id in get_approved_chat_id(): - log(f"Chat in approve list: {chat_id}") + # log(f"Chat in approve list: {chat_id}") return False else: - log(f"Chat not in approve list: {chat_id}") + # log(f"Chat not in approve list: {chat_id}") return True +class ChatIDFilter(BaseFilter): + def __init__(self, blacklist = False, approved_chats = None) -> None: + self.blacklist = blacklist + self.approved_chats = approved_chats + super().__init__() + + async def __call__(self, message: Message, bot: Bot) -> bool: + chat_id = message.chat.id + + approved_chats = self.approved_chats or get_approved_chat_id() + + print(approved_chats) + + res = chat_id in approved_chats + + return res ^ (self.blacklist) + +class ChatNotInApproveFilter(ChatIDFilter): + def __init__(self) -> None: + super().__init__(allow = False) class ChatModerOrAdminFilter(BaseFilter): async def __call__(self, message: Message, bot: Bot) -> bool: + if not ROLES_MODULE_LOADED: + raise Exception("Roles module not loaded") + user_id = message.from_user.id roles = Roles() admins = await bot.get_chat_administrators(message.chat.id) @@ -44,9 +73,4 @@ class ChatModerOrAdminFilter(BaseFilter): await roles.check_admin_permission(user_id) or await roles.check_moderator_permission(user_id) or any(user_id == admin.user.id for admin in admins) - ) - - -class ChatNotInApproveFilter(BaseFilter): - async def __call__(self, message: Message, bot: Bot) -> bool: - return chat_not_in_approve(message) + ) \ No newline at end of file diff --git a/src/ocab_modules/ocab_modules/standard/filters/info.json b/src/ocab_modules/ocab_modules/standard/filters/info.json index 205b829..9554bea 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/info.json +++ b/src/ocab_modules/ocab_modules/standard/filters/info.json @@ -4,11 +4,13 @@ "description": "Модуль с фильтрами", "author": "OCAB Team", "version": "1.0.0", - "privileged": false, + "privileged": true, "dependencies": { "required": { - "standard.roles": "^1.0.0", "standard.config": "^1.0.0" + }, + "optional": { + "standard.roles": "^1.0.0" } } } diff --git a/src/ocab_modules/ocab_modules/standard/report/README.md b/src/ocab_modules/ocab_modules/standard/report/README.md new file mode 100644 index 0000000..164d17d --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/report/README.md @@ -0,0 +1,18 @@ +# Модуль Report + +Модуль `report` позволяет пользователям сообщать о спам-сообщениях в чате. + +## Команды + +- `/report` - пожаловаться на сообщение как на спам. + +## Использование + +Чтобы сообщить о сообщении как о спаме, отправьте команду `/report`, ответив на сообщение, которое вы хотите отметить. Модуль уведомит администраторов, которые имеют права модерации. + +### Пример использования + +1. Найдите сообщение, которое вы хотите отметить как спам. +2. Ответьте на это сообщение командой `/report`. + +Примечание: Команда `/report` должна быть отправлена в ответ на сообщение, которое вы хотите отметить. diff --git a/src/ocab_modules/ocab_modules/standard/report/__init__.py b/src/ocab_modules/ocab_modules/standard/report/__init__.py new file mode 100644 index 0000000..729f10a --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/report/__init__.py @@ -0,0 +1 @@ +from .main import module_init \ No newline at end of file diff --git a/src/ocab_modules/ocab_modules/standard/report/info.json b/src/ocab_modules/ocab_modules/standard/report/info.json new file mode 100644 index 0000000..ac5e2f3 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/report/info.json @@ -0,0 +1,14 @@ +{ + "id": "standard.report", + "name": "Report", + "description": "Модуль для быстрой жалобы на спам", + "author": "OCAB Team", + "version": "1.0.0", + "privileged": false, + "dependencies": { + "optional": { + "standard.command_helper": "^1.0.0", + "standard.filters": "^1.0.0" + } + } +} diff --git a/src/ocab_modules/ocab_modules/standard/report/main.py b/src/ocab_modules/ocab_modules/standard/report/main.py new file mode 100644 index 0000000..aa744c8 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/report/main.py @@ -0,0 +1,69 @@ +from typing import TYPE_CHECKING +from aiogram import Router +from aiogram.filters import Command +from aiogram.types import Message, ChatMemberOwner, ChatMemberAdministrator + +from ocab_core.modules_system.public_api import get_module, register_router, log + +if TYPE_CHECKING: + from ocab_modules.standard.filters import ChatIDFilter as IChatIDFilter + +try: + ChatIDFilter: "type[IChatIDFilter]" = get_module("standard.filters", "ChatIDFilter") + FILTERS_MODULE_LOADED = True +except Exception as e: + FILTERS_MODULE_LOADED = False + pass + +try: + register_command = get_module("standard.command_helper", "register_command") + COMMAND_HELPER_MODULE_LOADED = True +except Exception as e: + COMMAND_HELPER_MODULE_LOADED = False + pass + +def can_moderate(admin: ChatMemberOwner | ChatMemberAdministrator) -> bool: + if isinstance(admin, ChatMemberOwner): + return True + + return ( + admin.user.is_bot == False and + ( + admin.can_delete_messages and + admin.can_restrict_members + ) + ) + +async def report(message: Message): + try: + if message.reply_to_message is None: + await message.reply("Пожалуйста, используйте команду /report в ответ на сообщение, которое вы хотите отметить как спам.") + return + + admins = await message.chat.get_administrators() + + admin_usernames = [ + admin.user.mention_html() + for admin in admins + if can_moderate(admin) + ] + if admin_usernames: + ping_message = "⚠️ Внимание, жалоба на спам! " + ", ".join(admin_usernames) + await message.reply_to_message.reply(ping_message, parse_mode="HTML") + except Exception as e: + log(e) + + +async def module_init(): + router = Router() + + if FILTERS_MODULE_LOADED: + router.message.register(report, ChatIDFilter(), Command("report")) + else: + router.message.register(report, Command("report")) + + register_router(router) + + if COMMAND_HELPER_MODULE_LOADED: + register_command = get_module("standard.command_helper", "register_command") + register_command("report", "Пожаловаться на спам") \ No newline at end of file From c746946d24d8d749d4750d3337c4fb4b7675d955 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Sun, 11 Aug 2024 09:50:03 +0300 Subject: [PATCH 03/38] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20config-example.yaml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/altlinux/config-example.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/altlinux/config-example.yaml b/src/altlinux/config-example.yaml index 6014227..1f4c864 100644 --- a/src/altlinux/config-example.yaml +++ b/src/altlinux/config-example.yaml @@ -2,6 +2,6 @@ core: mode: LONG_POLLING token: xxx -report: - allowed_groups: - - -1111111 \ No newline at end of file +filters: + approved_chat_id: + - -111111 \ No newline at end of file From 5732b1bcc3859494d1ef37405b656c488b9a2a68 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Sun, 11 Aug 2024 16:15:47 +0300 Subject: [PATCH 04/38] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20welcome?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/altlinux/altlinux/__main__.py | 1 + .../ocab_modules/standard/filters/filters.py | 25 ++-- .../ocab_modules/standard/welcome/README.md | 21 +++ .../ocab_modules/standard/welcome/__init__.py | 1 + .../ocab_modules/standard/welcome/info.json | 19 +++ .../ocab_modules/standard/welcome/main.py | 133 ++++++++++++++++++ .../welcome/verifications_methods/base.py | 21 +++ .../welcome/verifications_methods/iamhuman.py | 74 ++++++++++ .../welcome/verifications_methods/math.py | 111 +++++++++++++++ .../welcome/verifications_methods/question.py | 120 ++++++++++++++++ 10 files changed, 515 insertions(+), 11 deletions(-) create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/README.md create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/__init__.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/info.json create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/main.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py diff --git a/src/altlinux/altlinux/__main__.py b/src/altlinux/altlinux/__main__.py index c99c3f4..ffd1e3b 100644 --- a/src/altlinux/altlinux/__main__.py +++ b/src/altlinux/altlinux/__main__.py @@ -13,6 +13,7 @@ async def main(): # safe=False из-за super().__init__() module_loader("standard", "filters", safe=False), module_loader("standard", "report"), + module_loader("standard", "welcome", safe=False), ] ) await ocab.start() diff --git a/src/ocab_modules/ocab_modules/standard/filters/filters.py b/src/ocab_modules/ocab_modules/standard/filters/filters.py index 102bf42..3457048 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/filters.py +++ b/src/ocab_modules/ocab_modules/standard/filters/filters.py @@ -1,16 +1,16 @@ from typing import TYPE_CHECKING -from typing_extensions import deprecated from aiogram import Bot from aiogram.filters import BaseFilter from aiogram.types import Message +from typing_extensions import deprecated -from ocab_core.modules_system.public_api import get_module, log +from ocab_core.modules_system.public_api import get_module if TYPE_CHECKING: from ocab_modules.standard.config import IConfig from ocab_modules.standard.roles import Roles as IRoles - + config: "IConfig" = get_module("standard.config", "config") @@ -21,8 +21,11 @@ except Exception: ROLES_MODULE_LOADED = False pass + def module_init(): - config.register("filters::approved_chat_id", "int", multiple=True, shared=True, default_value=[]) + config.register( + "filters::approved_chat_id", "int", multiple=True, shared=True, default_value=[] + ) config.register("filters::default_chat_tag", "string", shared=True) @@ -40,8 +43,9 @@ def chat_not_in_approve(message: Message) -> bool: # log(f"Chat not in approve list: {chat_id}") return True + class ChatIDFilter(BaseFilter): - def __init__(self, blacklist = False, approved_chats = None) -> None: + def __init__(self, blacklist=False, approved_chats=None) -> None: self.blacklist = blacklist self.approved_chats = approved_chats super().__init__() @@ -50,22 +54,21 @@ class ChatIDFilter(BaseFilter): chat_id = message.chat.id approved_chats = self.approved_chats or get_approved_chat_id() - - print(approved_chats) - res = chat_id in approved_chats return res ^ (self.blacklist) + class ChatNotInApproveFilter(ChatIDFilter): def __init__(self) -> None: - super().__init__(allow = False) + super().__init__(allow=False) + class ChatModerOrAdminFilter(BaseFilter): async def __call__(self, message: Message, bot: Bot) -> bool: if not ROLES_MODULE_LOADED: raise Exception("Roles module not loaded") - + user_id = message.from_user.id roles = Roles() admins = await bot.get_chat_administrators(message.chat.id) @@ -73,4 +76,4 @@ class ChatModerOrAdminFilter(BaseFilter): await roles.check_admin_permission(user_id) or await roles.check_moderator_permission(user_id) or any(user_id == admin.user.id for admin in admins) - ) \ No newline at end of file + ) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/README.md b/src/ocab_modules/ocab_modules/standard/welcome/README.md new file mode 100644 index 0000000..612300c --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/README.md @@ -0,0 +1,21 @@ +## Модуль Welcome + +Модуль `welcome` отвечает за верификацию новых участников чата, используя различные методы проверки. Он помогает предотвратить спам и автоматические атаки на чат, обеспечивая, что новые участники подтверждают свою человеческую природу перед получением доступа. + +## Команды и Методы + +Модуль поддерживает несколько методов верификации, которые случайным образом применяются к новым участникам чата: + +- **IAmHumanButton** - Верификация с помощью кнопки. +- **IAmHumanInput** - Верификация с помощью ввода текста. +- **MathButtonsVerification** - Верификация решением математической задачи с помощью кнопок. +- **MathInputVerificationMethod** - Верификация решением математической задачи с помощью ввода. +- **QuestionButtonsVerification** - Верификация ответом на вопрос с помощью кнопок. +- **QuestionInputVerification** - Верификация ответом на вопрос с помощью ввода. + +## Как это работает + +1. **Обработка новых участников**: Когда новый участник присоединяется к чату, выбирается случайный метод верификации, и создается задача проверки. +2. **Тайм-аут проверки**: Если новый участник не проходит проверку в течение 30 секунд, его статус в чате меняется на "забанен". +3. **Верификация по кнопкам**: Если верификация осуществляется с помощью кнопок, обработчик будет ожидать нажатие кнопки от пользователя и проверит правильность ответа. +4. **Верификация по вводу**: Если верификация осуществляется путем ввода текста, обработчик будет проверять введенный текст и действовать в зависимости от результата проверки. diff --git a/src/ocab_modules/ocab_modules/standard/welcome/__init__.py b/src/ocab_modules/ocab_modules/standard/welcome/__init__.py new file mode 100644 index 0000000..c8fccb0 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/__init__.py @@ -0,0 +1 @@ +from .main import module_init diff --git a/src/ocab_modules/ocab_modules/standard/welcome/info.json b/src/ocab_modules/ocab_modules/standard/welcome/info.json new file mode 100644 index 0000000..356aa8f --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/info.json @@ -0,0 +1,19 @@ +{ + "id": "standard.welcome", + "name": "Welcome", + "description": "Модуль для проверки на бота", + "author": "OCAB Team", + "version": "1.0.0", + "privileged": true, + "dependencies": { + "optional": { + "standard.command_helper": "^1.0.0", + "standard.filters": "^1.0.0" + } + }, + "pythonDependencies": { + "required": { + "asyncio": "*" + } + } +} diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py new file mode 100644 index 0000000..1cbb27c --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -0,0 +1,133 @@ +import asyncio +import random + +from aiogram import Bot, Router, types +from aiogram.exceptions import TelegramBadRequest +from aiogram.filters import IS_MEMBER, IS_NOT_MEMBER, ChatMemberUpdatedFilter +from aiogram.types import ChatMemberUpdated + +from ocab_core.modules_system.public_api import log, register_router + +from .verifications_methods.base import VerificationCallback +from .verifications_methods.iamhuman import IAmHumanButton, IAmHumanInput +from .verifications_methods.math import ( + MathButtonsVerification, + MathInputVerificationMethod, +) +from .verifications_methods.question import ( + QuestionButtonsVerification, + QuestionInputVerification, +) + +verification_methods = [ + IAmHumanButton(), + IAmHumanInput(), + MathButtonsVerification(), + MathInputVerificationMethod(), + QuestionButtonsVerification(), + QuestionInputVerification(), +] + +verification_tasks = {} + + +async def new_member_handler(event: ChatMemberUpdated, bot: Bot): + if event.new_chat_member.status == "member": + user_id = event.from_user.id + chat_id = event.chat.id + + method = random.choice(verification_methods) # nosec + task_data = await method.create_task(event, bot) + + task_data["user_id"] = user_id + task_data["chat_id"] = chat_id + task_data["method"] = method + + task = asyncio.create_task(verify_timeout(bot, task_data)) + + verification_tasks[(user_id, chat_id)] = { + "task": task, + "task_data": task_data, + } + + +async def verify_timeout(bot: Bot, task_data: dict): + try: + chat_id = task_data["chat_id"] + user_id = task_data["user_id"] + + await asyncio.sleep(30) + try: + if "message_id" in task_data: + await bot.delete_message(chat_id, task_data["message_id"]) + except TelegramBadRequest: + return + + chat_member = await bot.get_chat_member(chat_id, user_id) + if chat_member.status == "member": + await bot.ban_chat_member(chat_id, user_id) + + except Exception as e: + log(f"Error in verify_timeout: {e}") + finally: + verification_tasks.pop((user_id, chat_id), None) + + +async def handle_inline_button_verification( + callback_query: types.CallbackQuery, callback_data: VerificationCallback, bot: Bot +): + user_id = callback_data.user_id + chat_id = callback_data.chat_id + + if callback_query.from_user.id == user_id: + if (user_id, chat_id) in verification_tasks: + task = verification_tasks[(user_id, chat_id)] + task_data = task["task_data"] + method = task_data["method"] + task_data["answer"] = callback_data.answer + + result = await method.verify(task_data) + + if result: + task["task"].cancel() + await bot.delete_message(chat_id, callback_query.message.message_id) + else: + await callback_query.answer("Неправильный ответ!", show_alert=True) + pass + else: + await callback_query.answer("Эта кнопка не для вас!", show_alert=True) + + +async def handle_input_verification(message: types.Message, bot: Bot): + user_id = message.from_user.id + chat_id = message.chat.id + + if (user_id, chat_id) in verification_tasks: + task = verification_tasks[(user_id, chat_id)] + task_data = task["task_data"] + method = task_data["method"] + task_data["answer"] = message.text + + result = await method.verify(task_data) + + if result: + task["task"].cancel() + await bot.delete_message(chat_id, task_data["message_id"]) + await bot.delete_message(chat_id, message.message_id) + + pass + + +async def module_init(): + router = Router() + + router.chat_member(ChatMemberUpdatedFilter(IS_NOT_MEMBER >> IS_MEMBER))( + new_member_handler + ) + + router.callback_query(VerificationCallback.filter())( + handle_inline_button_verification + ) + router.message()(handle_input_verification) + + register_router(router) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py new file mode 100644 index 0000000..aba1f27 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py @@ -0,0 +1,21 @@ +from aiogram.filters.callback_data import CallbackData + + +class VerificationMethod: + pass + + +class InputVerificationMethod(VerificationMethod): + def verify(input_value: str, task_data): + pass + + +class InlineButtonVerificationMethod(VerificationMethod): + def verify(input_value: str, task_data): + pass + + +class VerificationCallback(CallbackData, prefix="verify"): + user_id: int + chat_id: int + answer: str = None diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py new file mode 100644 index 0000000..acd50da --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py @@ -0,0 +1,74 @@ +import random + +from aiogram import Bot +from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup + +from .base import ( + InlineButtonVerificationMethod, + InputVerificationMethod, + VerificationCallback, +) + + +class IAmHumanButton(InlineButtonVerificationMethod): + def __init__(self): + pass + + def method_name(self): + return "i_am_human_button" + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + user_id = event.from_user.id + chat_id = event.chat.id + + keyboard = InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="Я человек!", + callback_data=VerificationCallback( + user_id=user_id, chat_id=chat_id, answer="OK" + ).pack(), + ) + ] + ] + ) + + message = await bot.send_message( + chat_id, + f"Привет, {event.from_user.first_name}! " + "Нажмите кнопку, чтобы подтвердить, что вы не робот.", + reply_markup=keyboard, + ) + + return {"message_id": message.message_id} + + async def verify(self, task_data): + return True + + +class IAmHumanInput(InputVerificationMethod): + def __init__(self): + pass + + def method_name(self): + return "i_am_human_input" + + def get_text(self): + return random.choice(["Я человек", "Я не робот"]) # nosec + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + chat_id = event.chat.id + text = self.get_text() + message = await bot.send_message( + chat_id, + f"Привет, {event.from_user.first_name}! " + f'Напишите "{text}", чтобы подтвердить, что вы не робот.', + ) + return {"message_id": message.message_id, "correct": text} + + async def verify(self, task_data): + correct: str = task_data["correct"] + answer: str = task_data["answer"] + + return answer.lower() == correct.lower() diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py new file mode 100644 index 0000000..97e01ed --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py @@ -0,0 +1,111 @@ +import random + +from aiogram import Bot +from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup + +from .base import ( + InlineButtonVerificationMethod, + InputVerificationMethod, + VerificationCallback, +) + + +class MathInputVerificationMethod(InputVerificationMethod): + def __init__(self): + pass + + def method_name(self): + return "math_input" + + def generate_math_problem(self): + a = random.randint(1, 10) # nosec + b = random.randint(1, 10) # nosec + operation = random.choice(["+", "-", "*"]) # nosec + if operation == "+": + answer = a + b + elif operation == "-": + answer = a - b + else: + answer = a * b + return f"{a} {operation} {b}", str(answer) + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + chat_id = event.chat.id + problem, answer = self.generate_math_problem() + message = await bot.send_message( + chat_id, + f"Привет, {event.from_user.first_name}! " + "Решите простую математическую задачу, " + f"чтобы подтвердить, что вы не робот: {problem} = ?", + ) + return {"message_id": message.message_id, "correct": answer} + + async def verify(self, task_data): + correct: str = task_data["correct"] + answer: str = task_data["answer"] + + return answer.strip() == correct + + +class MathButtonsVerification(InlineButtonVerificationMethod): + def __init__(self): + pass + + def method_name(self): + return "math_buttons" + + def generate_math_problem(self): + a = random.randint(1, 10) # nosec + b = random.randint(1, 10) # nosec + operation = random.choice(["+", "-", "*"]) # nosec + if operation == "+": + answer = a + b + elif operation == "-": + answer = a - b + else: + answer = a * b + return f"{a} {operation} {b}", answer + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + user_id = event.from_user.id + chat_id = event.chat.id + + problem, correct_answer = self.generate_math_problem() + options = [correct_answer] + while len(options) < 4: + wrong_answer = random.randint( + max(1, correct_answer - 5), correct_answer + 5 + ) # nosec + if wrong_answer not in options: + options.append(wrong_answer) + random.shuffle(options) # nosec + + keyboard = InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=str(option), + callback_data=VerificationCallback( + user_id=user_id, chat_id=chat_id, answer=str(option) + ).pack(), + ) + for option in options + ] + ] + ) + + message = await bot.send_message( + chat_id, + f"Привет, {event.from_user.first_name}! " + "Решите простую математическую задачу, " + f"чтобы подтвердить, что вы не робот: {problem} = ?", + reply_markup=keyboard, + ) + + return {"message_id": message.message_id, "correct": str(correct_answer)} + + async def verify(self, task_data): + correct: str = task_data["correct"] + answer: str = task_data["answer"] + + return answer == correct diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py new file mode 100644 index 0000000..a7b51ea --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py @@ -0,0 +1,120 @@ +import random + +from aiogram import Bot +from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup + +from .base import ( + InlineButtonVerificationMethod, + InputVerificationMethod, + VerificationCallback, +) + +QUESTIONS = [ + ( + "Какой город является столицей России?", + "Москва", + ["Санкт-Петербург", "Новосибирск", "Екатеринбург"], + ), + ( + "Какой город называют северной столицей России?", + "Санкт-Петербург", + ["Владивосток", "Новосибирск", "Екатеринбург"], + ), + ("Какая национальная валюта в России?", "Рубль", ["Евро", "Доллар", "Юань"]), + ("Год окончания Великой Отечественной войны?", "1945", ["2024", "862", "1721"]), + ( + "Самая БОЛЬШАЯ страна по площади?", + "Россия", + ["Люксембург", "Ватикан", "Лихтенштейн"], + ), + ("Сколько лап у кошки?", "4", ["10", "12", "14"]), + ("Сколько ног у осьминога?", "8", ["6", "10", "12"]), + ( + "Какой день недели идет после понедельника?", + "Вторник", + ["Среда", "Четверг", "Пятница"], + ), + ("Сколько часов в сутках?", "24", ["12", "48", "60"]), + ("Какой месяц самый короткий?", "Февраль", ["Март", "Апрель", "Май"]), +] + + +class QuestionInputVerification(InputVerificationMethod): + def __init__(self): + pass + + def method_name(self): + return "question_input" + + def get_random_question(self): + return random.choice(QUESTIONS) # nosec + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + chat_id = event.chat.id + question, answer, _ = self.get_random_question() + message = await bot.send_message( + chat_id, + f"Привет, {event.from_user.first_name}! " + "Пожалуйста, ответьте на следующий вопрос, " + f"чтобы подтвердить, что вы не робот: {question}", + ) + return {"message_id": message.message_id, "correct": answer.lower()} + + async def verify(self, task_data): + correct: str = task_data["correct"] + answer: str = task_data["answer"] + + return answer.lower().strip() == correct + + +class QuestionButtonsVerification(InlineButtonVerificationMethod): + def __init__(self): + pass + + def method_name(self): + return "question_inline" + + def get_random_question(self): + return random.choice(QUESTIONS) # nosec + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + user_id = event.from_user.id + chat_id = event.chat.id + + question, correct_answer, wrong_answers = self.get_random_question() + options = [correct_answer] + wrong_answers + random.shuffle(options) # nosec + + keyboard = InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=option, + callback_data=VerificationCallback( + user_id=user_id, chat_id=chat_id, answer=str(i) + ).pack(), + ) + for i, option in enumerate(options) + ] + ] + ) + + message = await bot.send_message( + chat_id, + f"Привет, {event.from_user.first_name}! " + "Пожалуйста, ответьте на следующий вопрос, " + f"чтобы подтвердить, что вы не робот: {question}", + reply_markup=keyboard, + ) + + return { + "message_id": message.message_id, + "correct": correct_answer, + "options": options, + } + + async def verify(self, task_data): + correct: str = task_data["correct"] + answer: str = task_data["answer"] + + return task_data["options"][int(answer)] == correct From 3ff4987badeb47fb6399e5125a687c8bdbe1cdc9 Mon Sep 17 00:00:00 2001 From: Armatik Date: Tue, 13 Aug 2024 00:28:31 +0300 Subject: [PATCH 05/38] add contributors list to lite --- CONTRIBUTORS | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 CONTRIBUTORS diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..9b94910 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,8 @@ +Руководитель проекта: + - Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru + +Ведущие разработчики: + - Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com + +Участники проекта: + - Илья Женецкий (@ilyazheprog) From a9f68005180c4dddd764d06588e03470edb49870 Mon Sep 17 00:00:00 2001 From: Armatik Date: Tue, 13 Aug 2024 00:37:50 +0300 Subject: [PATCH 06/38] Add info about ALTLinux OCAB Lite bot --- src/altlinux/README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/altlinux/README.md b/src/altlinux/README.md index c700e6b..97e7875 100644 --- a/src/altlinux/README.md +++ b/src/altlinux/README.md @@ -2,15 +2,14 @@ ## Описание - +Подготовленная версия OCAB Lite для интеграции в чат [Альт Линукс](https://t.me/alt_linux) ## Функционал +Список OCAB-модулей используемых в боте: - +* [report](src/ocab_modules/ocab_modules/standard/report/README.md) - Вызов администрации чата одной командой +* [welcome](src/ocab_modules/ocab_modules/standard/welcomereport/README.md) - Автоматическая вариативная проверка пользователей на признаки бота или другой автоматической рекламной системы +* help - Получение информации об OCAB Lite ## Запуск From 3076e1af132857bd16a9547c65e044b84de5163b Mon Sep 17 00:00:00 2001 From: Armatik Date: Tue, 13 Aug 2024 00:41:42 +0300 Subject: [PATCH 07/38] Delete path to more module info files --- src/altlinux/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/altlinux/README.md b/src/altlinux/README.md index 97e7875..6f6f5c7 100644 --- a/src/altlinux/README.md +++ b/src/altlinux/README.md @@ -7,8 +7,8 @@ ## Функционал Список OCAB-модулей используемых в боте: -* [report](src/ocab_modules/ocab_modules/standard/report/README.md) - Вызов администрации чата одной командой -* [welcome](src/ocab_modules/ocab_modules/standard/welcomereport/README.md) - Автоматическая вариативная проверка пользователей на признаки бота или другой автоматической рекламной системы +* report - Вызов администрации чата одной командой +* welcome - Автоматическая вариативная проверка пользователей на признаки бота или другой автоматической рекламной системы * help - Получение информации об OCAB Lite ## Запуск From 39500b77c2a14b4e02504589657a145c76be41cd Mon Sep 17 00:00:00 2001 From: Armatik Date: Tue, 13 Aug 2024 00:44:04 +0300 Subject: [PATCH 08/38] delete legacy modules for OCAB Lite --- .../legacy/moderation/__init__.py | 1 - .../ocab_modules/legacy/moderation/info.json | 6 -- .../legacy/moderation/moderation.py | 82 ------------------ .../ocab_modules/legacy/welcome/__init__.py | 0 .../ocab_modules/legacy/welcome/handlers.py | 84 ------------------- .../ocab_modules/legacy/welcome/info.json | 6 -- .../ocab_modules/legacy/welcome/routers.py | 12 --- .../ocab_modules/legacy/welcome/welcome.py | 0 8 files changed, 191 deletions(-) delete mode 100644 src/ocab_modules/ocab_modules/legacy/moderation/__init__.py delete mode 100644 src/ocab_modules/ocab_modules/legacy/moderation/info.json delete mode 100644 src/ocab_modules/ocab_modules/legacy/moderation/moderation.py delete mode 100644 src/ocab_modules/ocab_modules/legacy/welcome/__init__.py delete mode 100644 src/ocab_modules/ocab_modules/legacy/welcome/handlers.py delete mode 100644 src/ocab_modules/ocab_modules/legacy/welcome/info.json delete mode 100644 src/ocab_modules/ocab_modules/legacy/welcome/routers.py delete mode 100644 src/ocab_modules/ocab_modules/legacy/welcome/welcome.py diff --git a/src/ocab_modules/ocab_modules/legacy/moderation/__init__.py b/src/ocab_modules/ocab_modules/legacy/moderation/__init__.py deleted file mode 100644 index 780783a..0000000 --- a/src/ocab_modules/ocab_modules/legacy/moderation/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .moderation import ban_user, unmute_user diff --git a/src/ocab_modules/ocab_modules/legacy/moderation/info.json b/src/ocab_modules/ocab_modules/legacy/moderation/info.json deleted file mode 100644 index 619113e..0000000 --- a/src/ocab_modules/ocab_modules/legacy/moderation/info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Moderation", - "description": "Moderation commands for OCAB", - "author": "OCAB Team", - "version": "1.0" -} diff --git a/src/ocab_modules/ocab_modules/legacy/moderation/moderation.py b/src/ocab_modules/ocab_modules/legacy/moderation/moderation.py deleted file mode 100644 index d89101d..0000000 --- a/src/ocab_modules/ocab_modules/legacy/moderation/moderation.py +++ /dev/null @@ -1,82 +0,0 @@ -# flake8: noqa - -import asyncio -import time - -import aiogram -import aiohttp - -from ocab_modules.standard.config.config import * -from ocab_modules.standard.roles.roles import * - - -class Moderation: - def __init__(self): - access_rights = get_access_rights() - bot_check_message = bool(self.access_rights["BOT_CHECK_MESSAGE"]) - bot_ban_user = bool(self.access_rights["BOT_BAN_USER"]) - bot_mute_user = bool(self.access_rights["BOT_MUTE_USER"]) - moderator_rights = self.access_rights["MODERATOR_RIGHTS"] - ai_check_message = bool(self.access_rights["AI_CHECK_MESSAGE"]) - beta_ai_check_message = bool(self.access_rights["BETA_AI_CHECK_MESSAGE"]) - - async def time_to_seconds(time): - # Конвертация текстового указания времени по типу 3h, 5m, 10s в минуты - if time[-1] == "d": - return int(time[:-1]) * 86400 - elif time[-1] == "h": - return int(time[:-1]) * 3600 - elif time[-1] == "m": - return int(time[:-1]) * 60 - elif time[-1] == "s": - return int(time[:-1]) - - async def short_time_to_time(self, time): - # Конвертация времени в длинное название - if time[-1] == "d": - return str(f"{time[0:-1]} дней") - elif time[-1] == "h": - return str(f"{time[0:-1]} часов") - elif time[-1] == "m": - return str(f"{time[0:-1]} минут") - elif time[-1] == "s": - return str(f"{time[0:-1]} секунд") - - async def delete_message(self, chat_id, message_id, bot: aiogram.Bot): - await bot.delete_message(chat_id, message_id) - - async def ban_user(self, chat_id, user_id, bot: aiogram.Bot): - await bot.ban_chat_member(chat_id, user_id) - - -async def mute_user(chat_id, user_id, time, bot: aiogram.Bot): - mutePermissions = { - "can_send_messages": False, - "can_send_audios": False, - "can_send_documents": False, - "can_send_photos": False, - "can_send_videos": False, - "can_send_video_notes": False, - "can_send_voice_notes": False, - "can_send_polls": False, - "can_send_other_messages": False, - "can_add_web_page_previews": False, - "can_change_info": False, - "can_invite_users": False, - "can_pin_messages": False, - "can_manage_topics": False, - } - end_time = time + int(time.time()) - await bot.restrict_chat_member( - chat_id, user_id, until_date=end_time, **mutePermissions - ) - - -async def unmute_user(chat_id, user_id, bot: aiogram.Bot): - await bot.restrict_chat_member( - chat_id, user_id, use_independent_chat_permissions=True - ) - - -async def ban_user(chat_id, user_id, bot: aiogram.Bot): - await bot.ban_chat_member(chat_id, user_id) diff --git a/src/ocab_modules/ocab_modules/legacy/welcome/__init__.py b/src/ocab_modules/ocab_modules/legacy/welcome/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/ocab_modules/ocab_modules/legacy/welcome/handlers.py b/src/ocab_modules/ocab_modules/legacy/welcome/handlers.py deleted file mode 100644 index 8e65fc8..0000000 --- a/src/ocab_modules/ocab_modules/legacy/welcome/handlers.py +++ /dev/null @@ -1,84 +0,0 @@ -# flake8: noqa - -import asyncio -import random -from threading import Thread - -from aiogram import Bot -from aiogram.types import inline_keyboard_button as types -from aiogram.utils.keyboard import InlineKeyboardBuilder - -from ocab_modules.legacy.moderation import ban_user, unmute_user -from src.ocab_modules.standard.config.config import get_telegram_check_bot -from src.ocab_modules.standard.database.db_api import * - - -async def create_math_task(): - first_number = random.randint(1, 100) # nosec - second_number = random.randint(1, 100) # nosec - answer = first_number + second_number - fake_answers = [] - for i in range(3): - diff = random.randint(1, 10) # nosec - diff_sign = random.choice(["+", "-"]) # nosec - fake_answers.append(answer + diff if diff_sign == "+" else answer - diff) - fake_answers.append(answer) - random.shuffle(fake_answers) - return [answer, first_number, second_number, fake_answers] - - -async def ban_user_timer(chat_id: int, user_id: int, time: int, bot: Bot): - await asyncio.sleep(time) - if get_user(user_id) is not None: - pass - else: - await ban_user() - - -async def check_new_user(message: Message, bot: Bot): - print("check_new_user") - if get_telegram_check_bot(): - # Проверяем наличие пользователя в базе данных - - if get_user(message.from_user.id) is None: - # Выдаём пользователю ограничение на отправку сообщений на 3 минуты - ban_task = Thread( - target=ban_user_timer, - args=(message.chat.id, message.from_user.id, 180, bot), - ) - ban_task.start() - # Создаём задачу с отложенным выполнением на 3 минуты - - math_task = await create_math_task() - text = f"{math_task[1]} + {math_task[2]}" - builder = InlineKeyboardBuilder() - for answer in math_task[3]: - if answer == math_task[0]: - builder.add( - types.InlineKeyboardButton( - text=answer, callback_data=f"check_math_task_true" - ) - ) - else: - builder.add( - types.InlineKeyboardButton( - text=answer, callback_data=f"check_math_task_false" - ) - ) - await message.reply( - f"Приветствую, {message.from_user.first_name}!\n" - f"Для продолжения работы с ботом, пожалуйста, решите математический пример в течении 3х минут:\n" - f"*{text}*", - reply_markup=builder.as_markup(), - ) - - -async def math_task_true(message: Message, bot: Bot): - await message.reply(f"Верно! Добро пожаловать в чат {message.from_user.first_name}") - await unmute_user(message.chat.id, message.from_user.id, bot) - add_user( - message.from_user.id, - message.from_user.first_name + " " + message.from_user.last_name, - message.from_user.username, - ) - pass diff --git a/src/ocab_modules/ocab_modules/legacy/welcome/info.json b/src/ocab_modules/ocab_modules/legacy/welcome/info.json deleted file mode 100644 index fde1be0..0000000 --- a/src/ocab_modules/ocab_modules/legacy/welcome/info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Welcome", - "description": "Мо", - "author": "OCAB Team", - "version": "1.0" -} diff --git a/src/ocab_modules/ocab_modules/legacy/welcome/routers.py b/src/ocab_modules/ocab_modules/legacy/welcome/routers.py deleted file mode 100644 index 372d91b..0000000 --- a/src/ocab_modules/ocab_modules/legacy/welcome/routers.py +++ /dev/null @@ -1,12 +0,0 @@ -from aiogram import F, Router - -from .handlers import check_new_user - -router = Router() - -# Если в чат пришел новый пользователь -router.message.register(check_new_user, F.new_chat_members.exists()) -# Ловин колбеки от кнопок с callback_data=f"check_math_task_true" -router.callback_query.register( - check_new_user, F.callback_data == "check_math_task_true" -) diff --git a/src/ocab_modules/ocab_modules/legacy/welcome/welcome.py b/src/ocab_modules/ocab_modules/legacy/welcome/welcome.py deleted file mode 100644 index e69de29..0000000 From b185acd87133d9f5cd6ebac33ea4031f98018533 Mon Sep 17 00:00:00 2001 From: Armatik Date: Tue, 13 Aug 2024 00:44:50 +0300 Subject: [PATCH 09/38] Delete external modules for OCAB Lite --- .../ocab_modules/external/__init__.py | 1 - .../external/create_report_apps/README.md | 19 -- .../external/create_report_apps/__init__.py | 1 - .../create_report_apps/create_report.py | 136 -------- .../external/create_report_apps/info.json | 14 - .../external/create_report_apps/main.py | 115 ------- .../external/create_report_apps/report.py | 59 ---- .../ocab_modules/external/yandexgpt/README.md | 22 -- .../external/yandexgpt/__init__.py | 2 - .../external/yandexgpt/handlers.py | 47 --- .../ocab_modules/external/yandexgpt/info.json | 21 -- .../ocab_modules/external/yandexgpt/main.py | 50 --- .../external/yandexgpt/routers.py | 10 - .../external/yandexgpt/yandexgpt.py | 312 ------------------ 14 files changed, 809 deletions(-) delete mode 100644 src/ocab_modules/ocab_modules/external/__init__.py delete mode 100644 src/ocab_modules/ocab_modules/external/create_report_apps/README.md delete mode 100644 src/ocab_modules/ocab_modules/external/create_report_apps/__init__.py delete mode 100644 src/ocab_modules/ocab_modules/external/create_report_apps/create_report.py delete mode 100644 src/ocab_modules/ocab_modules/external/create_report_apps/info.json delete mode 100644 src/ocab_modules/ocab_modules/external/create_report_apps/main.py delete mode 100644 src/ocab_modules/ocab_modules/external/create_report_apps/report.py delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/README.md delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/__init__.py delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/handlers.py delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/info.json delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/main.py delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/routers.py delete mode 100644 src/ocab_modules/ocab_modules/external/yandexgpt/yandexgpt.py diff --git a/src/ocab_modules/ocab_modules/external/__init__.py b/src/ocab_modules/ocab_modules/external/__init__.py deleted file mode 100644 index 846ebe6..0000000 --- a/src/ocab_modules/ocab_modules/external/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import yandexgpt diff --git a/src/ocab_modules/ocab_modules/external/create_report_apps/README.md b/src/ocab_modules/ocab_modules/external/create_report_apps/README.md deleted file mode 100644 index 695b347..0000000 --- a/src/ocab_modules/ocab_modules/external/create_report_apps/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Модуль Create Report Apps - -Модуль `create_report_apps` предназначен для помощи пользователям в создании отчетов об ошибках в приложениях. - -## Функциональность - -- Задает пользователю ряд вопросов, необходимых для составления отчета. -- Собирает информацию о системе пользователя. -- Формирует отчет в текстовом формате. - -## Команды - -- `/create_report_apps` - запустить процесс создания отчета. - -## Использование - -1. Отправьте команду `/create_report_apps` боту в личных сообщениях или в групповом чате. -2. Ответьте на вопросы бота. -3. Бот сформирует отчет и отправит его вам. diff --git a/src/ocab_modules/ocab_modules/external/create_report_apps/__init__.py b/src/ocab_modules/ocab_modules/external/create_report_apps/__init__.py deleted file mode 100644 index c8fccb0..0000000 --- a/src/ocab_modules/ocab_modules/external/create_report_apps/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .main import module_init diff --git a/src/ocab_modules/ocab_modules/external/create_report_apps/create_report.py b/src/ocab_modules/ocab_modules/external/create_report_apps/create_report.py deleted file mode 100644 index 4e672b9..0000000 --- a/src/ocab_modules/ocab_modules/external/create_report_apps/create_report.py +++ /dev/null @@ -1,136 +0,0 @@ -from aiogram import Bot, Router -from aiogram.enums import ParseMode -from aiogram.fsm.context import FSMContext -from aiogram.fsm.state import State, StatesGroup -from aiogram.types import ( - BufferedInputFile, - KeyboardButton, - Message, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, -) - -from ocab_core.modules_system.public_api import Utils, get_fsm_context - -from .report import Report - -router = Router() - - -class ReportState(StatesGroup): - input_system_info = State() - input_app_name = State() - input_problem_step_by_step = State() - input_actual_result = State() - input_expected_result = State() - input_additional_info = State() - - -system_info_code = """echo "SESSION_TYPE: ${XDG_SESSION_TYPE:-Unknown}" -[ -f /etc/os-release ] && grep "^PRETTY_NAME=" /etc/os-release | cut -d= -f2 \ -| tr -d '"' | xargs echo "OS: " -echo "Kernel: $(uname -r)" -echo "DE: ${XDG_CURRENT_DESKTOP:-Unknown}" -grep "^model name" /proc/cpuinfo | head -n1 | cut -d: -f2 \ -| xargs echo "CPU: " -lspci | grep "VGA compatible controller" | cut -d: -f3 \ -| xargs -I{} echo "GPU: {}" -""" - - -system_info_message = """Укажите параметры свой системы. -Собрать информацию о системе можно с помощью данного скрипта: -""" + Utils.code_format( - system_info_code, - "shell", -) - - -async def start_report(chat_id: int, bot: Bot): - await bot.send_message( - chat_id=chat_id, - text=system_info_message, - parse_mode=ParseMode.HTML, - reply_markup=ReplyKeyboardRemove(), - ) - state = await get_fsm_context(chat_id, chat_id) - - await state.set_state(ReportState.input_system_info) - - -app_info_message = """Укажите название и версию приложения. -Узнать можно с помощью данной команды:""" + Utils.code_format( - "rpm -qa | grep -i НАЗВАНИЕ_ПРИЛОЖЕНИЯ", "shell" -) - - -@router.message(ReportState.input_system_info) -async def system_entered(message: Message, state: FSMContext): - await state.update_data(system=message.text) - await message.answer( - text=app_info_message, - parse_mode=ParseMode.HTML, - ) - await state.set_state(ReportState.input_app_name) - - -step_by_step_message = ( - """Опиши проблему пошагово, что ты делал, что происходило, что не так.""" -) - - -@router.message(ReportState.input_app_name) -async def app_name_entered(message: Message, state: FSMContext): - await state.update_data(app=message.text) - await message.answer(text=step_by_step_message) - await state.set_state(ReportState.input_problem_step_by_step) - - -@router.message(ReportState.input_problem_step_by_step) -async def problem_step_by_step_entered(message: Message, state: FSMContext): - await state.update_data(problem_step_by_step=message.text) - await message.answer(text="Опиши, что произошло (фактический результат).") - await state.set_state(ReportState.input_actual_result) - - -@router.message(ReportState.input_actual_result) -async def actual_result_entered(message: Message, state: FSMContext): - await state.update_data(actual=message.text) - await message.answer(text="Опиши ожидаемый результат.") - await state.set_state(ReportState.input_expected_result) - - -@router.message(ReportState.input_expected_result) -async def expected_result_entered(message: Message, state: FSMContext): - await state.update_data(expected=message.text) - await message.answer( - text="Если есть дополнительная информация, то напиши ее.", - reply_markup=ReplyKeyboardMarkup( - resize_keyboard=True, - keyboard=[ - [KeyboardButton(text="Дополнительной информации нет")], - ], - ), - ) - await state.set_state(ReportState.input_additional_info) - - -@router.message(ReportState.input_additional_info) -async def additional_info_entered(message: Message, state: FSMContext): - if message.text == "Дополнительной информации нет": - additional_info = "" - else: - additional_info = message.text - await state.update_data(additional=additional_info) - await message.answer( - text="Вот твой отчет сообщением, а также файлом:", - reply_markup=ReplyKeyboardRemove(), - ) - data = await state.get_data() - - report = Report(data) - file_report = report.export().encode() - - await message.answer(text=report.export()) - await message.answer_document(document=BufferedInputFile(file_report, "report.txt")) - await state.clear() diff --git a/src/ocab_modules/ocab_modules/external/create_report_apps/info.json b/src/ocab_modules/ocab_modules/external/create_report_apps/info.json deleted file mode 100644 index 79fbd03..0000000 --- a/src/ocab_modules/ocab_modules/external/create_report_apps/info.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "external.create_report_apps", - "name": "Create Report Apps", - "description": "Модуль для создания отчетов о ошибках в приложениях", - "author": [ - "OCAB Team", - "Maxim Slipenko" - ], - "version": "1.0.0", - "privileged": false, - "dependencies": { - "standard.command_helper": "^1.0.0" - } -} diff --git a/src/ocab_modules/ocab_modules/external/create_report_apps/main.py b/src/ocab_modules/ocab_modules/external/create_report_apps/main.py deleted file mode 100644 index 0e84bfb..0000000 --- a/src/ocab_modules/ocab_modules/external/create_report_apps/main.py +++ /dev/null @@ -1,115 +0,0 @@ -from typing import Union - -from aiogram import Bot, F, Router -from aiogram.exceptions import TelegramForbiddenError -from aiogram.filters import BaseFilter, Command, CommandStart -from aiogram.types import ( - CallbackQuery, - InlineKeyboardButton, - InlineKeyboardMarkup, - Message, -) - -from ocab_core.modules_system.public_api import get_module, register_router - -from .create_report import router as create_report_router -from .create_report import start_report - -register_command = get_module("standard.command_helper", "register_command") - -router = Router() - - -class ChatTypeFilter(BaseFilter): - def __init__(self, chat_type: Union[str, list]): - self.chat_type = chat_type - - async def __call__(self, message: Message) -> bool: - if isinstance(self.chat_type, str): - return message.chat.type == self.chat_type - return message.chat.type in self.chat_type - - -@router.message( - ChatTypeFilter(chat_type=["group", "supergroup"]), Command("create_report_apps") -) -async def create_report_apps_command_group(message: Message): - keyboard = InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text="Да", callback_data=f"create_report:{message.from_user.id}" - ), - InlineKeyboardButton( - text="Нет", callback_data=f"cancel_report:{message.from_user.id}" - ), - ] - ] - ) - await message.answer( - "Я могу отправить тебе пару вопросов " - "для помощи в составлении репорта личными " - "сообщениями.", - reply_markup=keyboard, - ) - - -@router.message( - ChatTypeFilter(chat_type=["private"]), - CommandStart(deep_link=True, magic=F.args == "create_report_apps"), -) -@router.message(ChatTypeFilter(chat_type=["private"]), Command("create_report_apps")) -async def create_report_apps_command(message: Message, bot: Bot): - await start_report(message.from_user.id, bot) - - -@router.callback_query(F.data.startswith("cancel_report")) -async def cancel_report_callback(callback_query: CallbackQuery): - callback_user_id = int(callback_query.data.split(":")[1]) - if callback_query.from_user.id != callback_user_id: - await callback_query.answer("Эта кнопка не для вас.", show_alert=True) - return - - await callback_query.message.delete() - - -@router.callback_query(F.data.startswith("create_report")) -async def create_report_callback(callback_query: CallbackQuery, bot: Bot): - callback_user_id = int(callback_query.data.split(":")[1]) - if callback_query.from_user.id != callback_user_id: - await callback_query.answer("Эта кнопка не для вас.", show_alert=True) - return - - user_id = callback_query.from_user.id - - async def on_chat_unavailable(): - await callback_query.message.edit_text( - "Я в личных сообщениях задам тебе вопросы " - "для помощи в составлении репорта. " - 'Но перед этим ты должен нажать кнопку "Запустить"' - ) - info = await bot.get_me() - await callback_query.answer( - url=f"https://t.me/{info.username}?start=create_report_apps" - ) - - try: - chat_member = await bot.get_chat_member(chat_id=user_id, user_id=user_id) - if chat_member.status != "left": - await start_report(user_id, bot) - await callback_query.message.edit_text( - "Я в личных сообщениях задам тебе " - "вопросы для помощи в составлении " - "репорта." - ) - else: - await on_chat_unavailable() - except TelegramForbiddenError: - await on_chat_unavailable() - - -async def module_init(): - router.include_router(create_report_router) - - register_router(router) - register_command("create_report_apps", "Написать репорт о приложении") diff --git a/src/ocab_modules/ocab_modules/external/create_report_apps/report.py b/src/ocab_modules/ocab_modules/external/create_report_apps/report.py deleted file mode 100644 index 6880108..0000000 --- a/src/ocab_modules/ocab_modules/external/create_report_apps/report.py +++ /dev/null @@ -1,59 +0,0 @@ -import aiogram - - -class ReportFormatter: - def __init__(self, html=True): - self.html = html - - def bold(self, string): - if self.html: - return f"{self.text(string)}" - return self.text(string) - - def text(self, string): - if self.html: - return aiogram.html.quote(string) - return string - - -class Report: - def __init__(self, data: dict): - self.data = data - - def export(self): - data = self.data - - report = f""" -Стенд с ошибкой: -============================== - -{data['system']} - -Пакет: -============================== - -{data['app']} - -Шаги, приводящие к ошибке: -============================== - -{data['problem_step_by_step']} - -Фактический результат: -============================== - -{data['actual']} - -Ожидаемый результат: -============================== - -{data['expected']} -""" - if data["additional"] != "": - report += f""" -Дополнительно: -============================== - -{data['additional']} -""" - return report diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/README.md b/src/ocab_modules/ocab_modules/external/yandexgpt/README.md deleted file mode 100644 index 8816567..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Модуль 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. diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/__init__.py b/src/ocab_modules/ocab_modules/external/yandexgpt/__init__.py deleted file mode 100644 index 7aecf7f..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .handlers import answer_to_message -from .main import module_init diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/handlers.py b/src/ocab_modules/ocab_modules/external/yandexgpt/handlers.py deleted file mode 100644 index 2d8540b..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/handlers.py +++ /dev/null @@ -1,47 +0,0 @@ -# flake8: noqa -from typing import TYPE_CHECKING - -from aiogram import Bot -from aiogram.types import Message - -from ocab_core.modules_system.public_api import get_module, log - -from .yandexgpt import YandexGPT - -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", -) - - -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): - # print("answer_to_message") - log("answer_to_message") - yagpt = YandexGPT(get_yandexgpt_token(), get_yandexgpt_catalog_id()) - text = message.text - prompt = get_yandexgpt_prompt() - # response = await yagpt.async_yandexgpt(system_prompt=prompt, input_messages=text) - response = await yagpt.yandexgpt_request( - chat_id=message.chat.id, message_id=message.message_id, type="yandexgpt" - ) - reply = await message.reply(response, parse_mode="Markdown") - add_message(reply, message_ai_model="yandexgpt") diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/info.json b/src/ocab_modules/ocab_modules/external/yandexgpt/info.json deleted file mode 100644 index 3cdf490..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/info.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "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": "*" - } - } -} diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/main.py b/src/ocab_modules/ocab_modules/external/yandexgpt/main.py deleted file mode 100644 index 2cc0bc2..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/main.py +++ /dev/null @@ -1,50 +0,0 @@ -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="помогите | не работает", - ) diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/routers.py b/src/ocab_modules/ocab_modules/external/yandexgpt/routers.py deleted file mode 100644 index 9f61d5f..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/routers.py +++ /dev/null @@ -1,10 +0,0 @@ -# flake8: noqa -from aiogram import F, Router - -from .handlers import answer_to_message - -router = Router() -# Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message -router.message.register( - answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик") -) diff --git a/src/ocab_modules/ocab_modules/external/yandexgpt/yandexgpt.py b/src/ocab_modules/ocab_modules/external/yandexgpt/yandexgpt.py deleted file mode 100644 index 051b926..0000000 --- a/src/ocab_modules/ocab_modules/external/yandexgpt/yandexgpt.py +++ /dev/null @@ -1,312 +0,0 @@ -# flake8: noqa -import json -from typing import TYPE_CHECKING - -import aiohttp -import requests - -from ocab_core.modules_system.public_api import get_module, log - -if TYPE_CHECKING: - 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: - token = None - catalog_id = None - languages = { - "ru": "русский язык", - "en": "английский язык", - "de": "немецкий язык", - "uk": "украинский язык", - "es": "испанский язык", - "be": "белорусский язык", - } - - def __init__(self, token, catalog_id): - self.token = token - self.catalog_id = catalog_id - - async def async_request(self, url, headers, prompt) -> dict: - async with aiohttp.ClientSession() as session: - async with session.post(url, headers=headers, json=prompt) as response: - return await response.json() - - async def async_token_check( - self, messages, gpt, max_tokens, stream, temperature, del_msg_id=1 - ): - url = "https://llm.api.cloud.yandex.net/foundationModels/v1/tokenizeCompletion" - headers = { - "Content-Type": "application/json", - "Authorization": f"Api-Key {self.token}", - } - answer_token = get_yandexgpt_token_for_answer() - while True: - try: - request = { - "modelUri": gpt, - "completionOptions": { - "stream": stream, - "temperature": temperature, - "maxTokens": max_tokens, - }, - "messages": messages, - } - response = await self.async_request( - url=url, headers=headers, prompt=request - ) - except Exception as e: # TODO: Переделать обработку ошибок - # print(e) - log(f"Error: {e}") - - continue - if int(len(response["tokens"])) < (max_tokens - answer_token): - break - else: - try: - messages.pop(del_msg_id) - except IndexError: - Exception("IndexError: list index out of range") - return messages - - async def async_yandexgpt_lite( - self, - system_prompt, - input_messages, - stream=False, - temperature=0.6, - max_tokens=8000, - ): - url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion" - gpt = f"gpt://{self.catalog_id}/yandexgpt-lite/latest" - headers = { - "Content-Type": "application/json", - "Authorization": f"Api-Key {self.token}", - } - - messages = [{"role": "system", "text": system_prompt}] - for message in input_messages: - messages.append(message) - messages = await self.async_token_check(messages, gpt, max_tokens) - - prompt = { - "modelUri": gpt, - "completionOptions": { - "stream": stream, - "temperature": temperature, - "maxTokens": max_tokens, - }, - "messages": messages, - } - - response = requests.post(url, headers=headers, json=prompt).text # nosec - return json.loads(response)["result"]["alternatives"][0]["message"]["text"] - - async def async_yandexgpt( - self, - system_prompt, - input_messages, - stream=False, - temperature=0.6, - 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" - gpt = f"gpt://{self.catalog_id}/yandexgpt/latest" - headers = { - "Content-Type": "application/json", - "Authorization": f"Api-Key {self.token}", - } - - messages = [] - messages.append({"role": "system", "text": system_prompt}) - for message in input_messages: - messages.append(message) - - messages = await self.async_token_check( - messages, gpt, max_tokens, stream, temperature - ) - - request = { - "modelUri": gpt, - "completionOptions": { - "stream": stream, - "temperature": temperature, - "maxTokens": max_tokens, - }, - "messages": messages, - } - response = await self.async_request( - url=url, headers=headers, prompt=request - ) # nosec - return response["result"]["alternatives"][0]["message"]["text"] - - async def async_yandexgpt_translate(self, input_language, output_language, text): - input_language = self.languages[input_language] - output_language = self.languages[output_language] - - return await self.async_yandexgpt( - f"Переведи на {output_language} сохранив оригинальный смысл текста. Верни только результат:", - [{"role": "user", "text": text}], - stream=False, - temperature=0.6, - max_tokens=8000, - ) - - async def async_yandexgpt_spelling_check(self, input_language, text): - input_language = self.languages[input_language] - - return await self.async_yandexgpt( - f"Проверьте орфографию и пунктуацию текста на {input_language}. Верни исправленный текст " - f"без смысловых искажений:", - [{"role": "user", "text": text}], - stream=False, - temperature=0.6, - max_tokens=8000, - ) - - async def async_yandexgpt_text_history( - self, input_messages, stream=False, temperature=0.6, max_tokens=8000 - ): - url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion" - gpt = f"gpt://{self.catalog_id}/summarization/latest" - headers = { - "Content-Type": "application/json", - "Authorization": f"Api-Key {self.token}", - } - - messages = [] - for message in input_messages: - messages.append(message) - messages = await self.async_token_check(messages, gpt, max_tokens, del_msg_id=0) - - prompt = { - "modelUri": gpt, - "completionOptions": { - "stream": stream, - "temperature": temperature, - "maxTokens": max_tokens, - }, - "messages": messages, - } - - response = requests.post(url, headers=headers, json=prompt).text # nosec - return json.loads(response)["result"]["alternatives"][0]["message"]["text"] - - async def async_yandex_cloud_text_to_speech( - self, text, voice, emotion, speed, format, quality - ): - tts = "tts.api.cloud.yandex.net/speech/v1/tts:synthesize" - # TODO: Сделать функцию TTS - return 0 - - async def async_yandex_cloud_vision(self, image, features, language): - # TODO: Сделать функцию Vision - return 0 - - async def collect_messages(self, message_id, chat_id): - messages = [] - # Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"}, - # {"role": "assistant", "text": "Привет!"}] - while True: - message = db_api.get_message_text(chat_id, message_id) - if db_api.get_message_ai_model(chat_id, message_id) != None: - messages.append({"role": "assistant", "text": message}) - else: - sender_name = db_api.get_user_name( - db_api.get_message_sender_id(chat_id, message_id) - ) - messages.append({"role": "user", "text": sender_name + ": " + message}) - message_id = db_api.get_answer_to_message_id(chat_id, message_id) - if message_id is None: - break - return list(reversed(messages)) - - async def collecting_messages_for_history( - self, start_message_id, end_message_id, chat_id - ): - messages = [] - # Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"}, - # {"role": "assistant", "text": "Привет!"}] - while True: - message = db_api.get_message_text(chat_id, start_message_id) - if db_api.get_message_ai_model(chat_id, start_message_id) != None: - messages.append({"role": "assistant", "text": message}) - else: - sender_name = db_api.get_user_name( - db_api.get_message_sender_id(chat_id, start_message_id) - ) - messages.append({"role": "user", "text": sender_name + ": " + message}) - start_message_id -= 1 - if start_message_id <= end_message_id: - break - return messages.reverse() - - async def yandexgpt_request( - self, - message_id=None, - type="yandexgpt-lite", - chat_id=None, - message_id_end=None, - input_language=None, - output_language=None, - text=None, - ): - if type == "yandexgpt-lite": - messages = await self.collect_messages(message_id, chat_id) - return await self.async_yandexgpt_lite( - system_prompt=get_yandexgpt_prompt(), - input_messages=messages, - stream=False, - temperature=0.6, - max_tokens=8000, - ) - elif type == "yandexgpt": - # print("yandexgpt_request") - log("yandexgpt_request") - messages = await self.collect_messages(message_id, chat_id) - return await self.async_yandexgpt( - system_prompt=get_yandexgpt_prompt(), - input_messages=messages, - stream=False, - temperature=0.6, - max_tokens=get_yandexgpt_token_for_request(), - ) - elif type == "yandexgpt-translate": - return await self.async_yandexgpt_translate( - input_language, - output_language, - text=db_api.get_message_text(chat_id, message_id), - ) - elif type == "yandexgpt-spelling-check": - return await self.async_yandexgpt_spelling_check( - input_language, text=db_api.get_message_text(chat_id, message_id) - ) - elif type == "yandexgpt-text-history": - messages = await self.collect_messages_for_history( - message_id, message_id_end, chat_id - ) - return await self.async_yandexgpt_text_history( - messages=messages, stream=False, temperature=0.6, max_tokens=8000 - ) - else: - return "Ошибка: Неизвестный тип запроса | Error: Unknown request type" From 984e4cf4e147233ff0f87fc452e449ffe51cfd45 Mon Sep 17 00:00:00 2001 From: Armatik Date: Tue, 13 Aug 2024 00:45:24 +0300 Subject: [PATCH 10/38] Delete gnomik bot from OCAB Lite --- src/gnomik/Dockerfile | 23 - src/gnomik/Dockerfile.dockerignore | 14 - src/gnomik/README.md | 55 - src/gnomik/config-example.yaml | 18 - src/gnomik/database/.gitkeep | 0 src/gnomik/docker-compose.yml | 12 - src/gnomik/docs/gnomik.jpg | Bin 62768 -> 0 bytes src/gnomik/gnomik/__init__.py | 0 src/gnomik/gnomik/__main__.py | 29 - src/gnomik/poetry.lock | 2162 ---------------------------- src/gnomik/poetry.toml | 2 - src/gnomik/pyproject.toml | 15 - 12 files changed, 2330 deletions(-) delete mode 100644 src/gnomik/Dockerfile delete mode 100644 src/gnomik/Dockerfile.dockerignore delete mode 100644 src/gnomik/README.md delete mode 100644 src/gnomik/config-example.yaml delete mode 100644 src/gnomik/database/.gitkeep delete mode 100644 src/gnomik/docker-compose.yml delete mode 100644 src/gnomik/docs/gnomik.jpg delete mode 100644 src/gnomik/gnomik/__init__.py delete mode 100644 src/gnomik/gnomik/__main__.py delete mode 100644 src/gnomik/poetry.lock delete mode 100644 src/gnomik/poetry.toml delete mode 100644 src/gnomik/pyproject.toml diff --git a/src/gnomik/Dockerfile b/src/gnomik/Dockerfile deleted file mode 100644 index a031138..0000000 --- a/src/gnomik/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -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"] diff --git a/src/gnomik/Dockerfile.dockerignore b/src/gnomik/Dockerfile.dockerignore deleted file mode 100644 index f9df4a3..0000000 --- a/src/gnomik/Dockerfile.dockerignore +++ /dev/null @@ -1,14 +0,0 @@ -**/Dockerfile -**/*.dockerignore -**/docker-compose.yml - -**/.git -**/.gitignore - -**/.venv - -**/.mypy_cache -**/__pycache__/ - -src/gnomik/config.yaml -src/gnomik/database/* diff --git a/src/gnomik/README.md b/src/gnomik/README.md deleted file mode 100644 index d3d784f..0000000 --- a/src/gnomik/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# 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. - -## Функционал - - - -## Запуск - -### 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`. diff --git a/src/gnomik/config-example.yaml b/src/gnomik/config-example.yaml deleted file mode 100644 index 8dce5ef..0000000 --- a/src/gnomik/config-example.yaml +++ /dev/null @@ -1,18 +0,0 @@ -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 diff --git a/src/gnomik/database/.gitkeep b/src/gnomik/database/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/gnomik/docker-compose.yml b/src/gnomik/docker-compose.yml deleted file mode 100644 index 1914a43..0000000 --- a/src/gnomik/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: '3' - -services: - app: - build: - context: ../.. - dockerfile: src/gnomik/Dockerfile - ports: - - 9000:9000 - volumes: - - ./config.yaml:/app/config.yaml - - ./database:/app/database diff --git a/src/gnomik/docs/gnomik.jpg b/src/gnomik/docs/gnomik.jpg deleted file mode 100644 index a0a834fb58e1edc4dc454d29bbbf2390453b5016..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62768 zcmb^Ybx>SS&_4<G_eQv$= zd+Pr4)~&j|J5!(OnKRwz>~znZncjaZ|F!|RYD%g~05~`}fXdqk@NXCHr>eZXwT_;) zlB$N{TLl0BHx76sco_h|-2>#Krz}TfVroVM_+MmW2lV=1#s4RK>*Ib2@RkDr^PIXM zWR(ABga1EeG@mztZ*8vL62XW6!ElKGVcY*3ll+JML0+IYT{-^4c3wXJVVO6K>0_WL z|AsZ*FwKYmg>C;Aws!#9y|rqGI4+U}9lo<6xs<;Nsz8=h9Mzr21)6Qh8F zUEhuY@XIwZiK2b#Ttw-&w>~M}x`0Rc-!c&p;gJAvZ!+I%W$^&;Zz2(pQ2vvPg!HD@ z+r7U@ql;bcT^zhV+W69hx0$f$SC+!kVI+A0buA zZe5-7t3npJz~N8&T%jOCTo3ud-IJ2n%Pde1fq2=iqVD^j=%6sC9KM2MV>N(ygm?wz zECH%01KCN)Nu_2_6^e!!L4W0zfrAElHqFVrqc=1GbU$|zZ2(YXt3aDb^;OEyB<+jw zmDPZinS%^f$g9+0C4&MkK~*0N;x4m%je7a`%CHugv2n|$M zufhg}f+5arhU7169Knmfpbm>4UzQXNeB`_Mml+>VSD60laSl4ZY~=oQtG*?%^yiEC9_PcBp!KJ7BL;TC4GVUh z3l;A3F%ghEYv^YJs z`cl6ZfeR`7uLJgIbm$<#sB%#G0RRH7 z6>iiPZc22^!5+zw!0Vo&kgFiuNG$@%^X@)ZuI-dy$f6(^?zEx_L>v>tFnAjHPP<}e zq{gl`KxRC4;0>u0pJzIG(4ukXs4`0iT!)%Pk5hp)Lx-|Mw$jz-4$X8?kJtmsbPTyo z-7EyobtbEy7*C~nKSA;%0(u$~fL_oK-|&ytSw)){K}_^88V6{RrLL6_diO0utj`nl zCek1yhTs4_54xX0Vj_EI(7m|7!cIiyFxBSZtnO3GTmq&aDHf|%ZBkeju!Pbn#deG~ z8P@rxa)rb?lX)Ut`gZGceTvF35`AW(`umww0Y7=K&}M`0L{RKF7Zi#4kgUe{m1($; zMngmcsqo&?YQ$~EBM|5I$u^{Tr-LQK=930cHE>6-D(wZxsy*lV)o zfj=ZUsfhv|{wylwmFscGF&L{r*2f9{2Ov8But0tp7CiL#Q}VC8ErY%axQS$6*~=(j zS>i=yDck7a!_lwv@Q12mrIzQ>zN(j{meM(-^DF1^kRmSoTxjq-Hstky?4)-x`La-< zuMBO$z7+b_FTpsplaSzPavnRc1S*p+XS&D?b6zw)bHF{BOw}s1|Ic7Xf%-jdnq>9j zRX|ag({#l#G+9_DTTtO#-?8eaFZzdhxm^C-G(}ZhU$j!=y3>M(!=j0!S+ftzUKJ3$ zUug5jb^iddmEBK&*$@|;ONy$PM?GP}o201K^S-)9A2~vYg<2N-N;Nez^66Y0mDpb9 zYoWI$^DgLtE#&@kpf9Z77~M6`Jqq28N_SyHxjKaoTDhm;Czwi_q~dI|n9!vMlYSR; z+H|x)J(Bo|;&gLYC~La#nQvTE(TYo)gKFyoYoH#fK3|kUuE$%E(uiy9%ctQIKCuLF zQw2Y1wm6$+n-X8C=AB7D^DHUFD;QkCOG+vLJc9{|PWBDi75oVm00A#H*xBsRl~hJk zQpSA~ho!!}=*~`-Xc_cZXg8VX&$=Z$*Fn)meK#mZ^}u2FqftFOxWnr#ttx7)U}u=+ zu&sTZns1d*uch3ly3?@PW?as(I&!8T?Z(Z&<(#tp4Zx~0KiGU;3H40gj}P}nrn=Hw z-xQTSsR@`yfI0~fqb`*-7nQqSj8{delo}jW2iCle`H5*6!0Ji^V6{Gvh9CGoRp91= zF?&R9`&HlYV!xOYgE;}iDNSO}mvo9V+VzWBJ(^Wu;Udq`aV_vq@%q~c^h4aYI(kv@ zSA{lCZ(yECoF|cl`)~(;#ykO_RjO7Te;6;n%#H_$VoPZTCr_s_S#v!XGi27z7qCU)= ziU}C4`rnwQzg4j`>){&Fb>IUPtBxyf zO&0V6OLq(Q8Oq_(CNfxS?Sp~Gja7%j@W+o8w=gXod9?je`b@c`M0ezBibQu#P%to< z1|FOTUtzDS?uFMlUY>^Nb1bMl$ep9+HB57o8V}wf82$~5PSoAfIv&~YHK-|3NptDFf_V7B7^Qqgg{!?8v@IhG@uxi|^Ir9s=tl9mX#=k#rFqZf| zufgI;ioWivv1&+fY~!!T3+-{jCy*xi@2^ZAs<*ibA_QT1=@^pP3$!T76lfCqZeQW(>JIttsc`6CLApA_wmI{f=O(KaVy6 zNk6=l8O?tF))p-E1)5(yG52#3yY0gp^5E<|u@`52G&_bmSA3FG(85kM*%&*-TOd%T zIo9`ZZ`K`i#f*hy_)((<6f+5{KeZ90@e@@#9nq|4On&)(9F+K1(HD`BqaeNBxhHOH z9fzn8Zi;}U2AdP~F8oT`G+G&_>9;?tZ9?4-+LZbu*DMUp2cmW>(`pmBu@kY-lAwC# z#ZNQk0efpoUPmWQ&eJzWqRX=a+KO5!7H^KUwkC(0ve~HpSl@oVq^blflX%^&hHKtI z&aLLO!l^T>d;)N5gzsRpP$QI~Ec*Er>~4V+Ire?@eV5tKRipj$8pHw^+m>bqqKeNw z5&G2`)}1Ciz?il%BHHZCMGNxXgG=XoifeU$^def(tgNQDwvgP%wGo;<(6%3xgv4SL zc?6^&WG$XfLglB8l5(h1P7$w=?$)~WT(ZiFXc39M%DHSH&#-jB$+GXr@MfF)rSv(k z2ADn;)+Jn`o~@(KGGd4Jcv_yt%7el(z9#2BXC-2yF!;1Q_u!BiM2&7D*kWEBKXz#7&4oi;p7^h4$e`ZB>fGO!>W~V5#Nr?)b zH$Il@;f*$^PQj@zsesPo?M6?FZBsR8CsMT;@=Dy_)%ed!EL#GGH>#pK4LTM2K3~=y zXJfaoT13o-`;Y&Y9SgBHPuh*lv^%YQv&wJ2x=k(@1o1!9sa`2dd?@1ixiXD`PJ|G1 zLyM;zi`Z0OMg6v%=6oUs=cb6?nj**0U5*@YR0tl+kxLdZvJ=Tz1f#g%!k1-MfgC>{ zBwkp|D*8H8A98#G=T^M|CA_C^~t7446w`Gc%*WUOjVXuG=|)2hBSX!DN9tC4-ZjV7seLX9*F)xvq#VVG_Eoa{VbEW{ z`6X&3jkh~x0|`8odVc&_H)*p^Jt{K{%a}B{EZOaGC{HO9%}T4IN|e}s%_}j5Jya_a zeo&Rq#0>e`25G{0kBF#m4ke7hpv$@Nz@t*j$sP@K2&e3qgJ+#0k{3A+VkzR8)-g`_ zaR$3Az%^18#`gLk0p3&ju3gmj+k)dy=fT1`{4Xw|8L?<4n;8+4L9L-ebJxc@`DRXk zP^Lw16f(Q?)#RLIiCemBVg{_ydz9cnwZjPLr;-mcf{-veOTJ?+X|ZW;VrWHUIhSi} zZmtVT2*c3aL5^3hsEI}1n1WLb3651xAv|b(34?7p%)Rh!yEAIxt7qL_@YX=`OU&G; z

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.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 = "anyio" -version = "4.4.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.8" -files = [ - {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, - {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] - -[[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]] -name = "blinker" -version = "1.8.2" -description = "Fast, simple object-to-object and broadcast signaling" -optional = false -python-versions = ">=3.8" -files = [ - {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, - {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, -] - -[[package]] -name = "cachelib" -version = "0.9.0" -description = "A collection of cache libraries in the same API interface." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachelib-0.9.0-py3-none-any.whl", hash = "sha256:811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3"}, - {file = "cachelib-0.9.0.tar.gz", hash = "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5"}, -] - -[[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]] -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]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "dash" -version = "2.17.1" -description = "A Python framework for building reactive web-apps. Developed by Plotly." -optional = false -python-versions = ">=3.8" -files = [ - {file = "dash-2.17.1-py3-none-any.whl", hash = "sha256:3eefc9ac67003f93a06bc3e500cae0a6787c48e6c81f6f61514239ae2da414e4"}, - {file = "dash-2.17.1.tar.gz", hash = "sha256:ee2d9c319de5dcc1314085710b72cd5fa63ff994d913bf72979b7130daeea28e"}, -] - -[package.dependencies] -dash-core-components = "2.0.0" -dash-html-components = "2.0.0" -dash-table = "5.0.0" -Flask = ">=1.0.4,<3.1" -importlib-metadata = "*" -nest-asyncio = "*" -plotly = ">=5.0.0" -requests = "*" -retrying = "*" -setuptools = "*" -typing-extensions = ">=4.1.1" -Werkzeug = "<3.1" - -[package.extras] -celery = ["celery[redis] (>=5.1.2)", "redis (>=3.5.3)"] -ci = ["black (==22.3.0)", "dash-dangerously-set-inner-html", "dash-flow-example (==0.0.5)", "flake8 (==7.0.0)", "flaky (==3.8.1)", "flask-talisman (==1.0.0)", "jupyterlab (<4.0.0)", "mimesis (<=11.1.0)", "mock (==4.0.3)", "numpy (<=1.26.3)", "openpyxl", "orjson (==3.10.3)", "pandas (>=1.4.0)", "pyarrow", "pylint (==3.0.3)", "pytest-mock", "pytest-rerunfailures", "pytest-sugar (==0.9.6)", "pyzmq (==25.1.2)", "xlrd (>=2.0.1)"] -compress = ["flask-compress"] -dev = ["PyYAML (>=5.4.1)", "coloredlogs (>=15.0.1)", "fire (>=0.4.0)"] -diskcache = ["diskcache (>=5.2.1)", "multiprocess (>=0.70.12)", "psutil (>=5.8.0)"] -testing = ["beautifulsoup4 (>=4.8.2)", "cryptography", "dash-testing-stub (>=0.0.2)", "lxml (>=4.6.2)", "multiprocess (>=0.70.12)", "percy (>=2.0.2)", "psutil (>=5.8.0)", "pytest (>=6.0.2)", "requests[security] (>=2.21.0)", "selenium (>=3.141.0,<=4.2.0)", "waitress (>=1.4.4)"] - -[[package]] -name = "dash-bootstrap-components" -version = "1.6.0" -description = "Bootstrap themed components for use in Plotly Dash" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "dash_bootstrap_components-1.6.0-py3-none-any.whl", hash = "sha256:97f0f47b38363f18863e1b247462229266ce12e1e171cfb34d3c9898e6e5cd1e"}, - {file = "dash_bootstrap_components-1.6.0.tar.gz", hash = "sha256:960a1ec9397574792f49a8241024fa3cecde0f5930c971a3fc81f016cbeb1095"}, -] - -[package.dependencies] -dash = ">=2.0.0" - -[package.extras] -pandas = ["numpy", "pandas"] - -[[package]] -name = "dash-core-components" -version = "2.0.0" -description = "Core component suite for Dash" -optional = false -python-versions = "*" -files = [ - {file = "dash_core_components-2.0.0-py3-none-any.whl", hash = "sha256:52b8e8cce13b18d0802ee3acbc5e888cb1248a04968f962d63d070400af2e346"}, - {file = "dash_core_components-2.0.0.tar.gz", hash = "sha256:c6733874af975e552f95a1398a16c2ee7df14ce43fa60bb3718a3c6e0b63ffee"}, -] - -[[package]] -name = "dash-extensions" -version = "1.0.18" -description = "Extensions for Plotly Dash." -optional = false -python-versions = "<4,>=3.9" -files = [ - {file = "dash_extensions-1.0.18-py3-none-any.whl", hash = "sha256:17f4469670bd70ce12fac1a05baaae119fb65eee7b012af47aff7377d0399eeb"}, - {file = "dash_extensions-1.0.18.tar.gz", hash = "sha256:a6b6c0952b3af7ae84c418fea4b43cbd0bd4e82f20d91f1573380b8a3d90df0a"}, -] - -[package.dependencies] -dash = ">=2.17.0" -dataclass-wizard = ">=0.22.2,<0.23.0" -Flask-Caching = ">=2.1.0,<3.0.0" -jsbeautifier = ">=1.14.3,<2.0.0" -more-itertools = ">=10.2.0,<11.0.0" -pydantic = ">=2.7.1,<3.0.0" -ruff = ">=0.4.5,<0.5.0" - -[package.extras] -mantine = ["dash-mantine-components (>=0.14.3,<0.15.0)"] - -[[package]] -name = "dash-html-components" -version = "2.0.0" -description = "Vanilla HTML components for Dash" -optional = false -python-versions = "*" -files = [ - {file = "dash_html_components-2.0.0-py3-none-any.whl", hash = "sha256:b42cc903713c9706af03b3f2548bda4be7307a7cf89b7d6eae3da872717d1b63"}, - {file = "dash_html_components-2.0.0.tar.gz", hash = "sha256:8703a601080f02619a6390998e0b3da4a5daabe97a1fd7a9cebc09d015f26e50"}, -] - -[[package]] -name = "dash-table" -version = "5.0.0" -description = "Dash table" -optional = false -python-versions = "*" -files = [ - {file = "dash_table-5.0.0-py3-none-any.whl", hash = "sha256:19036fa352bb1c11baf38068ec62d172f0515f73ca3276c79dee49b95ddc16c9"}, - {file = "dash_table-5.0.0.tar.gz", hash = "sha256:18624d693d4c8ef2ddec99a6f167593437a7ea0bf153aa20f318c170c5bc7308"}, -] - -[[package]] -name = "dataclass-wizard" -version = "0.22.3" -description = "Marshal dataclasses to/from JSON. Use field properties with initial values. Construct a dataclass schema with JSON input." -optional = false -python-versions = "*" -files = [ - {file = "dataclass-wizard-0.22.3.tar.gz", hash = "sha256:4c46591782265058f1148cfd1f54a3a91221e63986fdd04c9d59f4ced61f4424"}, - {file = "dataclass_wizard-0.22.3-py2.py3-none-any.whl", hash = "sha256:63751203e54b9b9349212cc185331da73c1adc99c51312575eb73bb5c00c1962"}, -] - -[package.extras] -dev = ["Sphinx (==5.3.0)", "bump2version (==1.0.1)", "coverage (>=6.2)", "dataclass-factory (==2.12)", "dataclasses-json (==0.5.6)", "flake8 (>=3)", "jsons (==1.6.1)", "pip (>=21.3.1)", "pytest (==7.0.1)", "pytest-cov (==3.0.0)", "pytest-mock (>=3.6.1)", "pytimeparse (==1.1.8)", "sphinx-issues (==3.0.1)", "sphinx-issues (==4.0.0)", "tox (==3.24.5)", "twine (==3.8.0)", "watchdog[watchmedo] (==2.1.6)", "wheel (==0.37.1)", "wheel (==0.42.0)"] -timedelta = ["pytimeparse (>=1.1.7)"] -yaml = ["PyYAML (>=5.3)"] - -[[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]] -name = "dnspython" -version = "2.6.1" -description = "DNS toolkit" -optional = false -python-versions = ">=3.8" -files = [ - {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, - {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, -] - -[package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=41)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=0.9.25)"] -idna = ["idna (>=3.6)"] -trio = ["trio (>=0.23)"] -wmi = ["wmi (>=1.5.1)"] - -[[package]] -name = "editorconfig" -version = "0.12.4" -description = "EditorConfig File Locator and Interpreter for Python" -optional = false -python-versions = "*" -files = [ - {file = "EditorConfig-0.12.4.tar.gz", hash = "sha256:24857fa1793917dd9ccf0c7810a07e05404ce9b823521c7dce22a4fb5d125f80"}, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -description = "A robust email address syntax and deliverability validation library." -optional = false -python-versions = ">=3.8" -files = [ - {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, - {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, -] - -[package.dependencies] -dnspython = ">=2.0.0" -idna = ">=2.0.0" - -[[package]] -name = "fastapi" -version = "0.111.1" -description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fastapi-0.111.1-py3-none-any.whl", hash = "sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf"}, - {file = "fastapi-0.111.1.tar.gz", hash = "sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413"}, -] - -[package.dependencies] -email_validator = ">=2.0.0" -fastapi-cli = ">=0.0.2" -httpx = ">=0.23.0" -jinja2 = ">=2.11.2" -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -python-multipart = ">=0.0.7" -starlette = ">=0.37.2,<0.38.0" -typing-extensions = ">=4.8.0" -uvicorn = {version = ">=0.12.0", extras = ["standard"]} - -[package.extras] -all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] - -[[package]] -name = "fastapi-cli" -version = "0.0.4" -description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, - {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, -] - -[package.dependencies] -typer = ">=0.12.3" - -[package.extras] -standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] - -[[package]] -name = "flask" -version = "3.0.3" -description = "A simple framework for building complex web applications." -optional = false -python-versions = ">=3.8" -files = [ - {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, - {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, -] - -[package.dependencies] -blinker = ">=1.6.2" -click = ">=8.1.3" -itsdangerous = ">=2.1.2" -Jinja2 = ">=3.1.2" -Werkzeug = ">=3.0.0" - -[package.extras] -async = ["asgiref (>=3.2)"] -dotenv = ["python-dotenv"] - -[[package]] -name = "flask-caching" -version = "2.3.0" -description = "Adds caching support to Flask applications." -optional = false -python-versions = ">=3.8" -files = [ - {file = "Flask_Caching-2.3.0-py3-none-any.whl", hash = "sha256:51771c75682e5abc1483b78b96d9131d7941dc669b073852edfa319dd4e29b6e"}, - {file = "flask_caching-2.3.0.tar.gz", hash = "sha256:d7e4ca64a33b49feb339fcdd17e6ba25f5e01168cf885e53790e885f83a4d2cf"}, -] - -[package.dependencies] -cachelib = ">=0.9.0,<0.10.0" -Flask = "*" - -[[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]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "h2" -version = "4.1.0" -description = "HTTP/2 State-Machine based protocol implementation" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, - {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, -] - -[package.dependencies] -hpack = ">=4.0,<5" -hyperframe = ">=6.0,<7" - -[[package]] -name = "hpack" -version = "4.0.0" -description = "Pure-Python HPACK header compression" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, - {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, -] - -[[package]] -name = "httpcore" -version = "1.0.5" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, - {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] - -[[package]] -name = "httptools" -version = "0.6.1" -description = "A collection of framework independent HTTP protocol utils." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, - {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, - {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, - {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, - {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, - {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, - {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, -] - -[package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] - -[[package]] -name = "httpx" -version = "0.27.0" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, - {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] - -[[package]] -name = "hypercorn" -version = "0.17.3" -description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" -optional = false -python-versions = ">=3.8" -files = [ - {file = "hypercorn-0.17.3-py3-none-any.whl", hash = "sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"}, - {file = "hypercorn-0.17.3.tar.gz", hash = "sha256:1b37802ee3ac52d2d85270700d565787ab16cf19e1462ccfa9f089ca17574165"}, -] - -[package.dependencies] -h11 = "*" -h2 = ">=3.1.0" -priority = "*" -wsproto = ">=0.14.0" - -[package.extras] -docs = ["pydata_sphinx_theme", "sphinxcontrib_mermaid"] -h3 = ["aioquic (>=0.9.0,<1.0)"] -trio = ["trio (>=0.22.0)"] -uvloop = ["uvloop (>=0.18)"] - -[[package]] -name = "hyperframe" -version = "6.0.1" -description = "HTTP/2 framing layer for Python" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, - {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, -] - -[[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]] -name = "importlib-metadata" -version = "8.2.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, - {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, -] - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -description = "Safely pass data to untrusted environments and back." -optional = false -python-versions = ">=3.8" -files = [ - {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, - {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, -] - -[[package]] -name = "jinja2" -version = "3.1.4" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "jsbeautifier" -version = "1.15.1" -description = "JavaScript unobfuscator and beautifier." -optional = false -python-versions = "*" -files = [ - {file = "jsbeautifier-1.15.1.tar.gz", hash = "sha256:ebd733b560704c602d744eafc839db60a1ee9326e30a2a80c4adb8718adc1b24"}, -] - -[package.dependencies] -editorconfig = ">=0.12.2" -six = ">=1.13.0" - -[[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]] -name = "markdown-it-py" -version = "3.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" -optional = false -python-versions = ">=3.8" -files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - -[[package]] -name = "markupsafe" -version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.7" -files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, -] - -[[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]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "more-itertools" -version = "10.3.0" -description = "More routines for operating on iterables, beyond itertools" -optional = false -python-versions = ">=3.8" -files = [ - {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, - {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, -] - -[[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]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -description = "Patch asyncio to allow nested event loops" -optional = false -python-versions = ">=3.5" -files = [ - {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, - {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, -] - -[[package]] -name = "ocab-core" -version = "0.1.0" -description = "" -optional = false -python-versions = "~3.12" -files = [] -develop = true - -[package.dependencies] -aiogram = "^3.10.0" -dataclasses-json = "^0.6.7" -fastapi = {version = "^0.111.1", optional = true} -hypercorn = {version = "^0.17.3", optional = true} -restrictedpython = "^7.1" -semver = "^3.0.2" -setuptools = "^71.0.1" - -[package.extras] -webhook = ["fastapi (>=0.111.1,<0.112.0)", "hypercorn (>=0.17.3,<0.18.0)"] - -[package.source] -type = "directory" -url = "../ocab_core" - -[[package]] -name = "ocab-modules" -version = "0.1.0" -description = "" -optional = false -python-versions = "~3.12" -files = [] -develop = true - -[package.dependencies] -dash = "^2.17.1" -dash-bootstrap-components = "^1.6.0" -dash-extensions = "^1.0.18" -ocab-core = {path = "../ocab_core", develop = true} -peewee = "^3.17.6" -pyyaml = "^6.0.1" - -[package.source] -type = "directory" -url = "../ocab_modules" - -[[package]] -name = "packaging" -version = "24.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, -] - -[[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]] -name = "plotly" -version = "5.23.0" -description = "An open-source, interactive data visualization library for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "plotly-5.23.0-py3-none-any.whl", hash = "sha256:76cbe78f75eddc10c56f5a4ee3e7ccaade7c0a57465546f02098c0caed6c2d1a"}, - {file = "plotly-5.23.0.tar.gz", hash = "sha256:89e57d003a116303a34de6700862391367dd564222ab71f8531df70279fc0193"}, -] - -[package.dependencies] -packaging = "*" -tenacity = ">=6.2.0" - -[[package]] -name = "priority" -version = "2.0.0" -description = "A pure-Python implementation of the HTTP/2 priority tree" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, - {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, -] - -[[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]] -name = "pygments" -version = "2.18.0" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "python-dotenv" -version = "1.0.1" -description = "Read key-value pairs from a .env file and set them as environment variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, -] - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "python-multipart" -version = "0.0.9" -description = "A streaming multipart parser for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, - {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, -] - -[package.extras] -dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] - -[[package]] -name = "pyyaml" -version = "6.0.1" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {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]] -name = "retrying" -version = "1.3.4" -description = "Retrying" -optional = false -python-versions = "*" -files = [ - {file = "retrying-1.3.4-py3-none-any.whl", hash = "sha256:8cc4d43cb8e1125e0ff3344e9de678fefd85db3b750b81b2240dc0183af37b35"}, - {file = "retrying-1.3.4.tar.gz", hash = "sha256:345da8c5765bd982b1d1915deb9102fd3d1f7ad16bd84a9700b85f64d24e8f3e"}, -] - -[package.dependencies] -six = ">=1.7.0" - -[[package]] -name = "rich" -version = "13.7.1" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, -] - -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - -[[package]] -name = "ruff" -version = "0.4.10" -description = "An extremely fast Python linter and code formatter, written in Rust." -optional = false -python-versions = ">=3.7" -files = [ - {file = "ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac"}, - {file = "ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e"}, - {file = "ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815"}, - {file = "ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695"}, - {file = "ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca"}, - {file = "ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7"}, - {file = "ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0"}, - {file = "ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804"}, -] - -[[package]] -name = "semver" -version = "3.0.2" -description = "Python helper for Semantic Versioning (https://semver.org)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4"}, - {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, -] - -[[package]] -name = "setuptools" -version = "71.1.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855"}, - {file = "setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936"}, -] - -[package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "starlette" -version = "0.37.2" -description = "The little ASGI library that shines." -optional = false -python-versions = ">=3.8" -files = [ - {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, - {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, -] - -[package.dependencies] -anyio = ">=3.4.0,<5" - -[package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] - -[[package]] -name = "tenacity" -version = "8.5.0" -description = "Retry code until it succeeds" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"}, - {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"}, -] - -[package.extras] -doc = ["reno", "sphinx"] -test = ["pytest", "tornado (>=4.5)", "typeguard"] - -[[package]] -name = "typer" -version = "0.12.3" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -optional = false -python-versions = ">=3.7" -files = [ - {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, - {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, -] - -[package.dependencies] -click = ">=8.0.0" -rich = ">=10.11.0" -shellingham = ">=1.3.0" -typing-extensions = ">=3.7.4.3" - -[[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]] -name = "uvicorn" -version = "0.30.3" -description = "The lightning-fast ASGI server." -optional = false -python-versions = ">=3.8" -files = [ - {file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"}, - {file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} -h11 = ">=0.8" -httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} -python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} - -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "uvloop" -version = "0.19.0" -description = "Fast implementation of asyncio event loop on top of libuv" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, - {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, -] - -[package.extras] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] - -[[package]] -name = "watchfiles" -version = "0.22.0" -description = "Simple, modern and high performance file watching and code reload in python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "watchfiles-0.22.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538"}, - {file = "watchfiles-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e"}, - {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1"}, - {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a"}, - {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd"}, - {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb"}, - {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171"}, - {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71"}, - {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39"}, - {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848"}, - {file = "watchfiles-0.22.0-cp310-none-win32.whl", hash = "sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797"}, - {file = "watchfiles-0.22.0-cp310-none-win_amd64.whl", hash = "sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb"}, - {file = "watchfiles-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96"}, - {file = "watchfiles-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696"}, - {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249"}, - {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550"}, - {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c"}, - {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da"}, - {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1"}, - {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f"}, - {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d"}, - {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c"}, - {file = "watchfiles-0.22.0-cp311-none-win32.whl", hash = "sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67"}, - {file = "watchfiles-0.22.0-cp311-none-win_amd64.whl", hash = "sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1"}, - {file = "watchfiles-0.22.0-cp311-none-win_arm64.whl", hash = "sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84"}, - {file = "watchfiles-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a"}, - {file = "watchfiles-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be"}, - {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2"}, - {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c"}, - {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232"}, - {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1"}, - {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6"}, - {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27"}, - {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b"}, - {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35"}, - {file = "watchfiles-0.22.0-cp312-none-win32.whl", hash = "sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e"}, - {file = "watchfiles-0.22.0-cp312-none-win_amd64.whl", hash = "sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e"}, - {file = "watchfiles-0.22.0-cp312-none-win_arm64.whl", hash = "sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea"}, - {file = "watchfiles-0.22.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d47e9ef1a94cc7a536039e46738e17cce058ac1593b2eccdede8bf72e45f372a"}, - {file = "watchfiles-0.22.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28f393c1194b6eaadcdd8f941307fc9bbd7eb567995232c830f6aef38e8a6e88"}, - {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd64f3a4db121bc161644c9e10a9acdb836853155a108c2446db2f5ae1778c3d"}, - {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2abeb79209630da981f8ebca30a2c84b4c3516a214451bfc5f106723c5f45843"}, - {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cc382083afba7918e32d5ef12321421ef43d685b9a67cc452a6e6e18920890e"}, - {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d048ad5d25b363ba1d19f92dcf29023988524bee6f9d952130b316c5802069cb"}, - {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:103622865599f8082f03af4214eaff90e2426edff5e8522c8f9e93dc17caee13"}, - {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e1f3cf81f1f823e7874ae563457828e940d75573c8fbf0ee66818c8b6a9099"}, - {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8597b6f9dc410bdafc8bb362dac1cbc9b4684a8310e16b1ff5eee8725d13dcd6"}, - {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b04a2cbc30e110303baa6d3ddce8ca3664bc3403be0f0ad513d1843a41c97d1"}, - {file = "watchfiles-0.22.0-cp38-none-win32.whl", hash = "sha256:b610fb5e27825b570554d01cec427b6620ce9bd21ff8ab775fc3a32f28bba63e"}, - {file = "watchfiles-0.22.0-cp38-none-win_amd64.whl", hash = "sha256:fe82d13461418ca5e5a808a9e40f79c1879351fcaeddbede094028e74d836e86"}, - {file = "watchfiles-0.22.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3973145235a38f73c61474d56ad6199124e7488822f3a4fc97c72009751ae3b0"}, - {file = "watchfiles-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:280a4afbc607cdfc9571b9904b03a478fc9f08bbeec382d648181c695648202f"}, - {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a0d883351a34c01bd53cfa75cd0292e3f7e268bacf2f9e33af4ecede7e21d1d"}, - {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9165bcab15f2b6d90eedc5c20a7f8a03156b3773e5fb06a790b54ccecdb73385"}, - {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc1b9b56f051209be458b87edb6856a449ad3f803315d87b2da4c93b43a6fe72"}, - {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc1fc25a1dedf2dd952909c8e5cb210791e5f2d9bc5e0e8ebc28dd42fed7562"}, - {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc92d2d2706d2b862ce0568b24987eba51e17e14b79a1abcd2edc39e48e743c8"}, - {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97b94e14b88409c58cdf4a8eaf0e67dfd3ece7e9ce7140ea6ff48b0407a593ec"}, - {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96eec15e5ea7c0b6eb5bfffe990fc7c6bd833acf7e26704eb18387fb2f5fd087"}, - {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:28324d6b28bcb8d7c1041648d7b63be07a16db5510bea923fc80b91a2a6cbed6"}, - {file = "watchfiles-0.22.0-cp39-none-win32.whl", hash = "sha256:8c3e3675e6e39dc59b8fe5c914a19d30029e36e9f99468dddffd432d8a7b1c93"}, - {file = "watchfiles-0.22.0-cp39-none-win_amd64.whl", hash = "sha256:25c817ff2a86bc3de3ed2df1703e3d24ce03479b27bb4527c57e722f8554d971"}, - {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68"}, - {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c"}, - {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab"}, - {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2"}, - {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5834e1f8b71476a26df97d121c0c0ed3549d869124ed2433e02491553cb468c2"}, - {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:0bc3b2f93a140df6806c8467c7f51ed5e55a931b031b5c2d7ff6132292e803d6"}, - {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fdebb655bb1ba0122402352b0a4254812717a017d2dc49372a1d47e24073795"}, - {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c8e0aa0e8cc2a43561e0184c0513e291ca891db13a269d8d47cb9841ced7c71"}, - {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2f350cbaa4bb812314af5dab0eb8d538481e2e2279472890864547f3fe2281ed"}, - {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7a74436c415843af2a769b36bf043b6ccbc0f8d784814ba3d42fc961cdb0a9dc"}, - {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00ad0bcd399503a84cc688590cdffbe7a991691314dde5b57b3ed50a41319a31"}, - {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a44e9481afc7a5ee3291b09c419abab93b7e9c306c9ef9108cb76728ca58d2"}, - {file = "watchfiles-0.22.0.tar.gz", hash = "sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb"}, -] - -[package.dependencies] -anyio = ">=3.0.0" - -[[package]] -name = "websockets" -version = "12.0" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, - {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, - {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, - {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, - {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, - {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, - {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, - {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, - {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, - {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, - {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, - {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, - {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, - {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, - {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, - {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, - {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, - {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, - {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, - {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, - {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, - {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, - {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, - {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, - {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, -] - -[[package]] -name = "werkzeug" -version = "3.0.3" -description = "The comprehensive WSGI web application library." -optional = false -python-versions = ">=3.8" -files = [ - {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, - {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, -] - -[package.dependencies] -MarkupSafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog (>=2.3)"] - -[[package]] -name = "wsproto" -version = "1.2.0" -description = "WebSockets state-machine based protocol implementation" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, - {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, -] - -[package.dependencies] -h11 = ">=0.9.0,<1" - -[[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" - -[[package]] -name = "zipp" -version = "3.19.2" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, -] - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[metadata] -lock-version = "2.0" -python-versions = "~3.12" -content-hash = "63f870b298f75049e8fb6fe1a5fa9482e4bfb2d624c8bc6bf3dfc6bafa1c05c3" diff --git a/src/gnomik/poetry.toml b/src/gnomik/poetry.toml deleted file mode 100644 index ab1033b..0000000 --- a/src/gnomik/poetry.toml +++ /dev/null @@ -1,2 +0,0 @@ -[virtualenvs] -in-project = true diff --git a/src/gnomik/pyproject.toml b/src/gnomik/pyproject.toml deleted file mode 100644 index 5bb5a75..0000000 --- a/src/gnomik/pyproject.toml +++ /dev/null @@ -1,15 +0,0 @@ -[tool.poetry] -name = "gnomik" -version = "0.1.0" -description = "" -authors = ["Максим Слипенко "] -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" From 81ddb8509fe16f06d84bb96e8bdba67d1694b75f Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 01:11:20 +0300 Subject: [PATCH 11/38] =?UTF-8?q?wip:=20=D0=9F=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=BE=20standard.welcome?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../standard/command_helper/main.py | 7 +- .../ocab_modules/standard/welcome/main.py | 157 ++++++++++++------ .../ocab_modules/standard/welcome/utils.py | 9 + .../welcome/verifications_methods/base.py | 125 +++++++++++++- .../welcome/verifications_methods/iamhuman.py | 8 +- .../welcome/verifications_methods/math.py | 22 ++- .../welcome/verifications_methods/question.py | 12 +- .../welcome/verifications_methods/utils.py | 11 ++ 8 files changed, 276 insertions(+), 75 deletions(-) create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/utils.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/main.py b/src/ocab_modules/ocab_modules/standard/command_helper/main.py index d33d1ba..f7c417e 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/main.py +++ b/src/ocab_modules/ocab_modules/standard/command_helper/main.py @@ -1,11 +1,10 @@ from aiogram.types import BotCommand -from ocab_core.modules_system.public_api import ( - set_my_commands, log -) +from ocab_core.modules_system.public_api import set_my_commands commands = dict() + def register_command(command, description, role="USER"): if role not in commands: commands[role] = dict() @@ -26,7 +25,7 @@ async def set_user_commands(): ) ) - log(bot_commands) + # log(bot_commands) await set_my_commands( bot_commands, diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py index 1cbb27c..8df6a5d 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/main.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -2,46 +2,51 @@ import asyncio import random from aiogram import Bot, Router, types -from aiogram.exceptions import TelegramBadRequest -from aiogram.filters import IS_MEMBER, IS_NOT_MEMBER, ChatMemberUpdatedFilter +from aiogram.enums import ChatMemberStatus +from aiogram.filters import JOIN_TRANSITION, LEAVE_TRANSITION, ChatMemberUpdatedFilter from aiogram.types import ChatMemberUpdated from ocab_core.modules_system.public_api import log, register_router -from .verifications_methods.base import VerificationCallback -from .verifications_methods.iamhuman import IAmHumanButton, IAmHumanInput -from .verifications_methods.math import ( - MathButtonsVerification, - MathInputVerificationMethod, -) -from .verifications_methods.question import ( - QuestionButtonsVerification, - QuestionInputVerification, -) +from .utils import get_plural_form +from .verifications_methods.base import VerificationCallback, VerificationMethod +from .verifications_methods.iamhuman import IAmHumanButton +from .verifications_methods.math import MathButtonsVerification +from .verifications_methods.question import QuestionButtonsVerification +# По хорошему, надо вынести в конфиг, но пока оставим так. verification_methods = [ IAmHumanButton(), - IAmHumanInput(), + # IAmHumanInput(), MathButtonsVerification(), - MathInputVerificationMethod(), + # MathInputVerificationMethod(), QuestionButtonsVerification(), - QuestionInputVerification(), + # QuestionInputVerification(), ] verification_tasks = {} async def new_member_handler(event: ChatMemberUpdated, bot: Bot): - if event.new_chat_member.status == "member": + # НЕ СРАБОТАЕТ, ЕСЛИ ЧЕЛОВЕК УЖЕ ОГРАНИЧЕН В ПРАВАХ (RESTRICTED) + if event.new_chat_member.status == ChatMemberStatus.MEMBER: user_id = event.from_user.id chat_id = event.chat.id - method = random.choice(verification_methods) # nosec + method: VerificationMethod = random.choice(verification_methods) # nosec + + await method.pre_task( + chat_id, + user_id, + bot, + ) + task_data = await method.create_task(event, bot) task_data["user_id"] = user_id task_data["chat_id"] = chat_id task_data["method"] = method + task_data["timeout"] = method.timeout(task_data) task = asyncio.create_task(verify_timeout(bot, task_data)) @@ -51,20 +56,33 @@ async def new_member_handler(event: ChatMemberUpdated, bot: Bot): } +async def left_member_handler(event: ChatMemberUpdated, bot: Bot): + user_id = event.from_user.id + chat_id = event.chat.id + + if (user_id, chat_id) not in verification_tasks: + return + + task = verification_tasks[(user_id, chat_id)] + task["task"].cancel() + verification_tasks.pop((user_id, chat_id), None) + task_data = task["task_data"] + method: VerificationMethod = task_data["method"] + await method.post_task(task_data, bot, success=False) + + async def verify_timeout(bot: Bot, task_data: dict): try: chat_id = task_data["chat_id"] user_id = task_data["user_id"] + method: VerificationMethod = task_data["method"] - await asyncio.sleep(30) - try: - if "message_id" in task_data: - await bot.delete_message(chat_id, task_data["message_id"]) - except TelegramBadRequest: - return + await asyncio.sleep(task_data["timeout"]) + + await method.post_task(task_data, success=False) chat_member = await bot.get_chat_member(chat_id, user_id) - if chat_member.status == "member": + if chat_member.status in [ChatMemberStatus.MEMBER, ChatMemberStatus.RESTRICTED]: await bot.ban_chat_member(chat_id, user_id) except Exception as e: @@ -79,51 +97,80 @@ async def handle_inline_button_verification( user_id = callback_data.user_id chat_id = callback_data.chat_id - if callback_query.from_user.id == user_id: - if (user_id, chat_id) in verification_tasks: - task = verification_tasks[(user_id, chat_id)] - task_data = task["task_data"] - method = task_data["method"] - task_data["answer"] = callback_data.answer - - result = await method.verify(task_data) - - if result: - task["task"].cancel() - await bot.delete_message(chat_id, callback_query.message.message_id) - else: - await callback_query.answer("Неправильный ответ!", show_alert=True) - pass - else: + if callback_query.from_user.id != user_id: await callback_query.answer("Эта кнопка не для вас!", show_alert=True) + return + + if (user_id, chat_id) not in verification_tasks: + await callback_query.answer() + return + + verification_task = verification_tasks[(user_id, chat_id)] + task_data = verification_task["task_data"] + method: VerificationMethod = task_data["method"] + task_data["answer"] = callback_data.answer + + result = await method.verify(task_data) + + if result: + verification_task["task"].cancel() + await method.post_task(task_data, bot) + return + + if "attempts_count" not in task_data: + await callback_query.answer("Неправильный ответ!", show_alert=True) + return + + attempts_count = task_data["attempts_count"] + + verification_task["task"].cancel() + attempts_count = attempts_count - 1 + + if attempts_count > 0: + await callback_query.answer( + "Неправильный ответ! " + + "У вас еще " + + get_plural_form(attempts_count, "попытка", "попытки", "попыток"), + show_alert=True, + ) + task_data["timeout"] = method.timeout(task_data) + task_data["attempts_count"] = attempts_count + else: + task_data["timeout"] = 0 + await callback_query.answer() + + task = asyncio.create_task(verify_timeout(bot, task_data)) + verification_task["task"] = task + + # Эта строчка нужна, т.к. во время cancel происходит pop + verification_tasks[(user_id, chat_id)] = verification_task async def handle_input_verification(message: types.Message, bot: Bot): user_id = message.from_user.id chat_id = message.chat.id - if (user_id, chat_id) in verification_tasks: - task = verification_tasks[(user_id, chat_id)] - task_data = task["task_data"] - method = task_data["method"] - task_data["answer"] = message.text + if (user_id, chat_id) not in verification_tasks: + return + task = verification_tasks[(user_id, chat_id)] + task_data = task["task_data"] + method: VerificationMethod = task_data["method"] + task_data["answer"] = message.text + task_data["answer_message_id"] = message.message_id - result = await method.verify(task_data) + result = await method.verify(task_data) - if result: - task["task"].cancel() - await bot.delete_message(chat_id, task_data["message_id"]) - await bot.delete_message(chat_id, message.message_id) - - pass + if result: + task["task"].cancel() + await method.post_task(task_data, bot) async def module_init(): router = Router() - router.chat_member(ChatMemberUpdatedFilter(IS_NOT_MEMBER >> IS_MEMBER))( - new_member_handler - ) + router.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION))(new_member_handler) + + router.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION))(left_member_handler) router.callback_query(VerificationCallback.filter())( handle_inline_button_verification diff --git a/src/ocab_modules/ocab_modules/standard/welcome/utils.py b/src/ocab_modules/ocab_modules/standard/welcome/utils.py new file mode 100644 index 0000000..b3288b4 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/utils.py @@ -0,0 +1,9 @@ +def get_plural_form(number, singular, genitive_singular, plural): + if 11 <= number % 100 <= 19: + return f"{number} {plural}" + elif number % 10 == 1: + return f"{number} {singular}" + elif 2 <= number % 10 <= 4: + return f"{number} {genitive_singular}" + else: + return f"{number} {plural}" diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py index aba1f27..99b7f35 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py @@ -1,18 +1,133 @@ +import time + +from aiogram import Bot +from aiogram.exceptions import TelegramBadRequest from aiogram.filters.callback_data import CallbackData +from aiogram.types import ChatMemberUpdated, ChatPermissions + +from .utils import user_mention + + +async def mute_user(chat_id, user_id, until, bot: Bot): + end_time = until + int(time.time()) + await bot.restrict_chat_member( + chat_id, + user_id, + until_date=end_time, + use_independent_chat_permissions=True, + permissions=ChatPermissions( + can_send_messages=False, + can_send_audios=False, + can_send_documents=False, + can_send_photos=False, + can_send_videos=False, + can_send_video_notes=False, + can_send_voice_notes=False, + can_send_polls=False, + can_send_other_messages=False, + can_add_web_page_previews=False, + can_change_info=False, + can_invite_users=False, + can_pin_messages=False, + can_manage_topics=False, + ), + ) + + +async def unmute_user(chat_id, user_id, bot: Bot): + await bot.restrict_chat_member( + chat_id, + user_id, + use_independent_chat_permissions=True, + permissions=ChatPermissions( + can_send_messages=True, + can_send_audios=True, + can_send_documents=True, + can_send_photos=True, + can_send_videos=True, + can_send_video_notes=True, + can_send_voice_notes=True, + can_send_polls=True, + can_send_other_messages=True, + can_add_web_page_previews=True, + can_change_info=True, + can_invite_users=True, + can_pin_messages=True, + can_manage_topics=True, + ), + ) class VerificationMethod: - pass + + def timeout(self, task_data=None) -> int: + """ + Время ожидания + """ + return 30 + + def method_name(self): + pass + + async def pre_task(self, chat_id, user_id, bot: Bot): + pass + + async def create_task(self, event: ChatMemberUpdated, bot: Bot): + pass + + async def post_task(self, task_data, bot: Bot, success=True): + pass + + async def verify(self, task_data): + pass class InputVerificationMethod(VerificationMethod): - def verify(input_value: str, task_data): - pass + async def post_task(self, task_data, bot: Bot, success=True, user=None): + chat_id = task_data["chat_id"] + message_id = task_data["message_id"] + answer_message_id = task_data["answer_message_id"] + + await bot.delete_message(chat_id, message_id) + await bot.delete_message(chat_id, answer_message_id) + + if not success or user is None: + return + + await bot.send_message( + chat_id, + f"{user_mention(user)}, успешно прошли проверку! " + "Пожалуйста, соблюдайте правила группы.", + ) class InlineButtonVerificationMethod(VerificationMethod): - def verify(input_value: str, task_data): - pass + async def pre_task(self, chat_id, user_id, bot: Bot): + try: + await mute_user(chat_id, user_id, 0, bot) + except TelegramBadRequest: + pass + + async def post_task(self, task_data, bot: Bot, success=True, user=None): + user_id = task_data["user_id"] + chat_id = task_data["chat_id"] + message_id = task_data["message_id"] + + await bot.delete_message(chat_id, message_id) + + try: + await unmute_user(chat_id, user_id, bot) + except TelegramBadRequest: + pass + + if not success or user is None: + return + + await bot.send_message( + chat_id, + f"{user_mention(user)}, успешно прошли проверку! " + "Пожалуйста, соблюдайте правила группы.", + ) class VerificationCallback(CallbackData, prefix="verify"): diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py index acd50da..d6c3420 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py @@ -1,6 +1,7 @@ import random from aiogram import Bot +from aiogram.enums import ParseMode from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup from .base import ( @@ -8,6 +9,7 @@ from .base import ( InputVerificationMethod, VerificationCallback, ) +from .utils import user_mention class IAmHumanButton(InlineButtonVerificationMethod): @@ -36,9 +38,10 @@ class IAmHumanButton(InlineButtonVerificationMethod): message = await bot.send_message( chat_id, - f"Привет, {event.from_user.first_name}! " + f"Привет, {user_mention(event.from_user)}! ", "Нажмите кнопку, чтобы подтвердить, что вы не робот.", reply_markup=keyboard, + parse_mode=ParseMode.HTML, ) return {"message_id": message.message_id} @@ -62,8 +65,9 @@ class IAmHumanInput(InputVerificationMethod): text = self.get_text() message = await bot.send_message( chat_id, - f"Привет, {event.from_user.first_name}! " + f"Привет, {user_mention(event.from_user)}! " f'Напишите "{text}", чтобы подтвердить, что вы не робот.', + parse_mode=ParseMode.HTML, ) return {"message_id": message.message_id, "correct": text} diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py index 97e01ed..b2b812b 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py @@ -1,6 +1,7 @@ import random from aiogram import Bot +from aiogram.enums import ParseMode from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup from .base import ( @@ -8,6 +9,7 @@ from .base import ( InputVerificationMethod, VerificationCallback, ) +from .utils import user_mention class MathInputVerificationMethod(InputVerificationMethod): @@ -34,9 +36,11 @@ class MathInputVerificationMethod(InputVerificationMethod): problem, answer = self.generate_math_problem() message = await bot.send_message( chat_id, - f"Привет, {event.from_user.first_name}! " + f"Привет, {user_mention(event.from_user)}! " "Решите простую математическую задачу, " - f"чтобы подтвердить, что вы не робот: {problem} = ?", + "чтобы подтвердить, что вы не робот:\\n" + f"{problem} = ?", + parse_mode=ParseMode.HTML, ) return {"message_id": message.message_id, "correct": answer} @@ -74,7 +78,7 @@ class MathButtonsVerification(InlineButtonVerificationMethod): options = [correct_answer] while len(options) < 4: wrong_answer = random.randint( - max(1, correct_answer - 5), correct_answer + 5 + correct_answer - 5, correct_answer + 5 ) # nosec if wrong_answer not in options: options.append(wrong_answer) @@ -96,13 +100,19 @@ class MathButtonsVerification(InlineButtonVerificationMethod): message = await bot.send_message( chat_id, - f"Привет, {event.from_user.first_name}! " + f"Привет, {user_mention(event.from_user)}! " "Решите простую математическую задачу, " - f"чтобы подтвердить, что вы не робот: {problem} = ?", + "чтобы подтвердить, что вы не робот:\\n" + f"{problem} = ?", reply_markup=keyboard, + parse_mode=ParseMode.HTML, ) - return {"message_id": message.message_id, "correct": str(correct_answer)} + return { + "message_id": message.message_id, + "correct": str(correct_answer), + "attempts_count": 2, + } async def verify(self, task_data): correct: str = task_data["correct"] diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py index a7b51ea..785af3f 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py @@ -1,8 +1,11 @@ import random from aiogram import Bot +from aiogram.enums import ParseMode from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup +from ocab_modules.standard.welcome.verifications_methods.utils import user_mention + from .base import ( InlineButtonVerificationMethod, InputVerificationMethod, @@ -54,9 +57,10 @@ class QuestionInputVerification(InputVerificationMethod): question, answer, _ = self.get_random_question() message = await bot.send_message( chat_id, - f"Привет, {event.from_user.first_name}! " + f"Привет, {user_mention(event.from_user)}! " "Пожалуйста, ответьте на следующий вопрос, " f"чтобы подтвердить, что вы не робот: {question}", + parse_mode=ParseMode.HTML, ) return {"message_id": message.message_id, "correct": answer.lower()} @@ -94,23 +98,25 @@ class QuestionButtonsVerification(InlineButtonVerificationMethod): user_id=user_id, chat_id=chat_id, answer=str(i) ).pack(), ) - for i, option in enumerate(options) ] + for i, option in enumerate(options) ] ) message = await bot.send_message( chat_id, - f"Привет, {event.from_user.first_name}! " + f"Привет, {user_mention(event.from_user)}! " "Пожалуйста, ответьте на следующий вопрос, " f"чтобы подтвердить, что вы не робот: {question}", reply_markup=keyboard, + parse_mode=ParseMode.HTML, ) return { "message_id": message.message_id, "correct": correct_answer, "options": options, + "attempts_count": 2, } async def verify(self, task_data): diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py new file mode 100644 index 0000000..41e9a61 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py @@ -0,0 +1,11 @@ +from aiogram.enums import ParseMode +from aiogram.types import User + + +def user_mention(user: User, mode=ParseMode.HTML): + if mode == ParseMode.HTML: + return f"{user.first_name}" + elif mode == ParseMode.MARKDOWN: + return f"[{user.first_name}](tg://user?id={user.id})" + else: + raise ValueError(f"Unknown parse mode {mode}") From 15cb6afb34895a7857279eef50146bdd7c2142ad Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 21:24:40 +0300 Subject: [PATCH 12/38] =?UTF-8?q?wip:=20=D0=9F=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=BE=20standard.welcome?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ocab_modules/standard/welcome/__init__.py | 2 +- .../ocab_modules/standard/welcome/info.json | 3 + .../ocab_modules/standard/welcome/main.py | 371 +++++++++++++----- .../ocab_modules/standard/welcome/utils.py | 36 ++ .../welcome/verifications_methods/base.py | 199 ++++------ .../welcome/verifications_methods/iamhuman.py | 78 ---- .../welcome/verifications_methods/math.py | 124 ++---- .../welcome/verifications_methods/question.py | 109 ++--- .../welcome/verifications_methods/simple.py | 178 +++++++++ .../welcome/verifications_methods/utils.py | 55 ++- 10 files changed, 679 insertions(+), 476 deletions(-) delete mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py create mode 100644 src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/simple.py diff --git a/src/ocab_modules/ocab_modules/standard/welcome/__init__.py b/src/ocab_modules/ocab_modules/standard/welcome/__init__.py index c8fccb0..91f142d 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/__init__.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/__init__.py @@ -1 +1 @@ -from .main import module_init +from .main import module_init, module_late_init diff --git a/src/ocab_modules/ocab_modules/standard/welcome/info.json b/src/ocab_modules/ocab_modules/standard/welcome/info.json index 356aa8f..bf99dba 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/info.json +++ b/src/ocab_modules/ocab_modules/standard/welcome/info.json @@ -6,6 +6,9 @@ "version": "1.0.0", "privileged": true, "dependencies": { + "required": { + "standard.config": "^1.0.0" + }, "optional": { "standard.command_helper": "^1.0.0", "standard.filters": "^1.0.0" diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py index 8df6a5d..258b529 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/main.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -1,94 +1,165 @@ import asyncio import random +from string import Template +from typing import TYPE_CHECKING from aiogram import Bot, Router, types -from aiogram.enums import ChatMemberStatus +from aiogram.enums import ChatMemberStatus, ParseMode from aiogram.filters import JOIN_TRANSITION, LEAVE_TRANSITION, ChatMemberUpdatedFilter -from aiogram.types import ChatMemberUpdated +from aiogram.types import ChatMemberUpdated, PollAnswer -from ocab_core.modules_system.public_api import log, register_router +from ocab_core.modules_system.public_api import get_module, log, register_router -from .utils import get_plural_form -from .verifications_methods.base import VerificationCallback, VerificationMethod -from .verifications_methods.iamhuman import IAmHumanButton -from .verifications_methods.math import MathButtonsVerification -from .verifications_methods.question import QuestionButtonsVerification +from .utils import MultiKeyDict, get_plural_form, key_from_poll, key_from_user_chat +from .verifications_methods.base import BaseTask, VerificationCallback -# По хорошему, надо вынести в конфиг, но пока оставим так. -verification_methods = [ - IAmHumanButton(), - # IAmHumanInput(), - MathButtonsVerification(), - # MathInputVerificationMethod(), - QuestionButtonsVerification(), - # QuestionInputVerification(), +# from .verifications_methods.simple import SimpleInlineButtonsMethod +# from .verifications_methods.iamhuman import IAmHumanButton +from .verifications_methods.math import MathInlineButtonsTask, MathPollTask +from .verifications_methods.question import QuestionInlineButtonsTask, QuestionPollTask +from .verifications_methods.simple import ( + SimpleVariantsBaseTask, + SimpleVariantsBaseTaskConfig, +) +from .verifications_methods.utils import user_mention + +# from .verifications_methods.question import QuestionButtonsVerification + +all_tasks = [ + MathInlineButtonsTask, + MathPollTask, + QuestionInlineButtonsTask, + QuestionPollTask, ] -verification_tasks = {} + +class TaskManager: + def __init__(self, config: "IConfig"): + self.config = config + self.available_tasks = [] + self.max_attempts = 1 + + def init(self): + for cls in all_tasks: + type_name = cls.type_name() + if self.config.get(f"welcome::tasks::{type_name}::enabled"): + self.available_tasks.append(cls) + + self.max_attempts = self.config.get("welcome::max_attempts") + + def build_random_task(self, event, bot, attempt_number=1) -> BaseTask: + cls = random.choice(self.available_tasks) # nosec + obj = cls( + event, + bot, + timeout_func=verify_timeout, + attempt_number=attempt_number, + max_attempts=self.max_attempts, + ) + + if isinstance(obj, SimpleVariantsBaseTask): + cfg = SimpleVariantsBaseTaskConfig(obj.type_name(), self.config) + obj.set_config(cfg) + + return obj + + +verification_tasks = MultiKeyDict() + +if TYPE_CHECKING: + from ocab_modules.standard.config import IConfig async def new_member_handler(event: ChatMemberUpdated, bot: Bot): # НЕ СРАБОТАЕТ, ЕСЛИ ЧЕЛОВЕК УЖЕ ОГРАНИЧЕН В ПРАВАХ (RESTRICTED) if event.new_chat_member.status == ChatMemberStatus.MEMBER: - user_id = event.from_user.id - chat_id = event.chat.id + task = task_manager.build_random_task(event, bot) + keys = await task.run() - method: VerificationMethod = random.choice(verification_methods) # nosec - - await method.pre_task( - chat_id, - user_id, - bot, - ) - - task_data = await method.create_task(event, bot) - - task_data["user_id"] = user_id - task_data["chat_id"] = chat_id - task_data["method"] = method - task_data["timeout"] = method.timeout(task_data) - - task = asyncio.create_task(verify_timeout(bot, task_data)) - - verification_tasks[(user_id, chat_id)] = { - "task": task, - "task_data": task_data, - } + verification_tasks.add(task, keys) async def left_member_handler(event: ChatMemberUpdated, bot: Bot): user_id = event.from_user.id chat_id = event.chat.id - if (user_id, chat_id) not in verification_tasks: + key = key_from_user_chat(user_id, chat_id) + + if not verification_tasks.exists(key): return - task = verification_tasks[(user_id, chat_id)] - task["task"].cancel() + task = verification_tasks.get(key) + await task.end(success=False) + verification_tasks.pop((user_id, chat_id), None) - task_data = task["task_data"] - method: VerificationMethod = task_data["method"] - await method.post_task(task_data, bot, success=False) -async def verify_timeout(bot: Bot, task_data: dict): +async def verify_timeout(task: BaseTask): + user_id = task.from_user_id + chat_id = task.from_chat_id + try: - chat_id = task_data["chat_id"] - user_id = task_data["user_id"] - method: VerificationMethod = task_data["method"] + timeout = task.get_timeout() + # log(f"Start timeout {timeout}") + await asyncio.sleep(timeout) - await asyncio.sleep(task_data["timeout"]) - - await method.post_task(task_data, success=False) - - chat_member = await bot.get_chat_member(chat_id, user_id) - if chat_member.status in [ChatMemberStatus.MEMBER, ChatMemberStatus.RESTRICTED]: - await bot.ban_chat_member(chat_id, user_id) + await task.end(success=False) + await task.bot.ban_chat_member(chat_id, user_id) except Exception as e: log(f"Error in verify_timeout: {e}") finally: - verification_tasks.pop((user_id, chat_id), None) + verification_tasks.remove(key_from_user_chat(user_id, chat_id)) + + +async def success_end(task: BaseTask): + await task.end() + + await asyncio.sleep(3) + + if config.get("welcome::show_success_message"): + await task.bot.send_message( + task.from_chat_id, + Template(config.get("welcome::success_message")).substitute( + mention=user_mention(task.from_user) + ), + parse_mode=ParseMode.HTML, + ) + + +async def handle_poll_verification(answer: PollAnswer, bot: Bot): + key = key_from_poll(answer.poll_id) + if not verification_tasks.exists(key): + return + + task: BaseTask = verification_tasks.get(key) + + if task.from_user_id != answer.user.id: + return + + result = await task.verify(answer.option_ids[0]) + + if result: + await success_end(task) + return + + await task.end(success=False) + + current_attempt = task.attempt_number + + if current_attempt >= task_manager.max_attempts: + await task.bot.ban_chat_member(task.from_chat_id, task.from_user_id) + return + + await asyncio.sleep(5) + + current_attempt = current_attempt + 1 + new_task = task_manager.build_random_task( + task.event, task.bot, attempt_number=current_attempt + ) + keys = await new_task.run() + log(keys) + verification_tasks.add(new_task, keys) async def handle_inline_button_verification( @@ -101,71 +172,152 @@ async def handle_inline_button_verification( await callback_query.answer("Эта кнопка не для вас!", show_alert=True) return - if (user_id, chat_id) not in verification_tasks: + key = key_from_user_chat(user_id, chat_id) + + if not verification_tasks.exists(key): await callback_query.answer() return - verification_task = verification_tasks[(user_id, chat_id)] - task_data = verification_task["task_data"] - method: VerificationMethod = task_data["method"] - task_data["answer"] = callback_data.answer + task: BaseTask = verification_tasks.get(key) - result = await method.verify(task_data) + result = await task.verify(callback_data.answer) if result: - verification_task["task"].cancel() - await method.post_task(task_data, bot) + await success_end(task) return - if "attempts_count" not in task_data: - await callback_query.answer("Неправильный ответ!", show_alert=True) - return + await task.end(success=False) - attempts_count = task_data["attempts_count"] + current_attempt = task.attempt_number - verification_task["task"].cancel() - attempts_count = attempts_count - 1 - - if attempts_count > 0: - await callback_query.answer( - "Неправильный ответ! " - + "У вас еще " - + get_plural_form(attempts_count, "попытка", "попытки", "попыток"), - show_alert=True, - ) - task_data["timeout"] = method.timeout(task_data) - task_data["attempts_count"] = attempts_count - else: - task_data["timeout"] = 0 + if current_attempt >= task_manager.max_attempts: await callback_query.answer() - - task = asyncio.create_task(verify_timeout(bot, task_data)) - verification_task["task"] = task - - # Эта строчка нужна, т.к. во время cancel происходит pop - verification_tasks[(user_id, chat_id)] = verification_task - - -async def handle_input_verification(message: types.Message, bot: Bot): - user_id = message.from_user.id - chat_id = message.chat.id - - if (user_id, chat_id) not in verification_tasks: + await task.bot.ban_chat_member(chat_id, user_id) return - task = verification_tasks[(user_id, chat_id)] - task_data = task["task_data"] - method: VerificationMethod = task_data["method"] - task_data["answer"] = message.text - task_data["answer_message_id"] = message.message_id - result = await method.verify(task_data) + await callback_query.answer( + Template(config.get("welcome::retry_message")).substitute( + attempts=get_plural_form( + task_manager.max_attempts - current_attempt, + "попытка", + "попытки", + "попыток", + ) + ), + show_alert=True, + ) + current_attempt = current_attempt + 1 + new_task = task_manager.build_random_task( + task.event, task.bot, attempt_number=current_attempt + ) + keys = await new_task.run() + verification_tasks.add(new_task, keys) - if result: - task["task"].cancel() - await method.post_task(task_data, bot) + +config: "IConfig" = get_module("standard.config", "config") + +task_manager = TaskManager(config) async def module_init(): + config.register("welcome::timeout", "int", default_value=45) + config.register("welcome::max_attempts", "int", default_value=2) + config.register( + "welcome::retry_message", + "string", + default_value="Неправильный ответ! У вас еще $attempts", + ) + config.register("welcome::show_success_message", "boolean", default_value=True) + config.register( + "welcome::success_message", + "string", + default_value="$mention, вы успешно прошли проверку!", + ) + + # MATH BUTTONS + + config.register( + "welcome::tasks::math_buttons::enabled", "boolean", default_value=True + ) + config.register( + "welcome::tasks::math_buttons::message_text", + "int", + default_value="Привет, $mention!\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register( + "welcome::tasks::math_buttons::retry_message_text", + "int", + default_value="$mention, неправильный ответ! У вас еще $attempts\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register("welcome::tasks::math_buttons::timeout", "int", default_value=None) + + # MATH POLL + + config.register("welcome::tasks::math_poll::enabled", "boolean", default_value=True) + config.register( + "welcome::tasks::math_poll::message_text", + "string", + default_value="Привет, $mention!\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register( + "welcome::tasks::math_poll::retry_message_text", + "string", + default_value="$mention, неправильный ответ! У вас еще $attempts\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register("welcome::tasks::math_poll::timeout", "int", default_value=None) + + # QUESTION BUTTONS + + config.register( + "welcome::tasks::question_buttons::enabled", "boolean", default_value=True + ) + config.register( + "welcome::tasks::question_buttons::message_text", + "string", + default_value="Привет, $mention!\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register( + "welcome::tasks::question_buttons::retry_message_text", + "string", + default_value="$mention, неправильный ответ! У вас еще $attempts\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register( + "welcome::tasks::question_buttons::timeout", "int", default_value=None + ) + + # QUESTION POLL + + config.register( + "welcome::tasks::question_poll::enabled", "boolean", default_value=True + ) + config.register( + "welcome::tasks::question_poll::message_text", + "string", + default_value="Привет, $mention!\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register( + "welcome::tasks::question_poll::retry_message_text", + "string", + default_value="$mention, неправильный ответ! У вас еще $attempts\n" + "Решите простую математическую задачу," + "чтобы подтвердить, что вы не робот:\n\n$task", + ) + config.register("welcome::tasks::question_poll::timeout", "int", default_value=None) + router = Router() router.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION))(new_member_handler) @@ -175,6 +327,11 @@ async def module_init(): router.callback_query(VerificationCallback.filter())( handle_inline_button_verification ) - router.message()(handle_input_verification) + router.poll_answer()(handle_poll_verification) + # router.message()(handle_input_verification) register_router(router) + + +async def module_late_init(): + task_manager.init() diff --git a/src/ocab_modules/ocab_modules/standard/welcome/utils.py b/src/ocab_modules/ocab_modules/standard/welcome/utils.py index b3288b4..86ec5e9 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/utils.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/utils.py @@ -7,3 +7,39 @@ def get_plural_form(number, singular, genitive_singular, plural): return f"{number} {genitive_singular}" else: return f"{number} {plural}" + + +class MultiKeyDict: + def __init__(self): + self.value_to_keys = {} # Словарь значений и связанных с ними ключей + self.key_to_value = {} # Словарь ключей и связанных с ними значений + + def add(self, value, keys): + # Добавляем значение в словарь с множеством ключей + self.value_to_keys[value] = set(keys) + + # Для каждого ключа создаем запись в словаре key_to_value + for key in keys: + self.key_to_value[key] = value + + def get(self, key): + return self.key_to_value.get(key) + + def exists(self, key): + return key in self.key_to_value + + def remove(self, key): + if key in self.key_to_value: + value = self.key_to_value.pop(key) + self.value_to_keys[value].remove(key) + + for k in self.value_to_keys[value]: + del self.key_to_value[k] + + +def key_from_user_chat(user_id, chat_id): + return f"uc:{user_id}_{chat_id}" + + +def key_from_poll(poll_id): + return f"p:{poll_id}" diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py index 99b7f35..8172900 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/base.py @@ -1,133 +1,102 @@ -import time +import asyncio +from functools import wraps from aiogram import Bot from aiogram.exceptions import TelegramBadRequest from aiogram.filters.callback_data import CallbackData -from aiogram.types import ChatMemberUpdated, ChatPermissions +from aiogram.types import ChatMemberUpdated -from .utils import user_mention +from ocab_core.modules_system.public_api import log + +from .utils import mute_user, unmute_user -async def mute_user(chat_id, user_id, until, bot: Bot): - end_time = until + int(time.time()) - await bot.restrict_chat_member( - chat_id, - user_id, - until_date=end_time, - use_independent_chat_permissions=True, - permissions=ChatPermissions( - can_send_messages=False, - can_send_audios=False, - can_send_documents=False, - can_send_photos=False, - can_send_videos=False, - can_send_video_notes=False, - can_send_voice_notes=False, - can_send_polls=False, - can_send_other_messages=False, - can_add_web_page_previews=False, - can_change_info=False, - can_invite_users=False, - can_pin_messages=False, - can_manage_topics=False, - ), - ) +class BaseTask: + def __init__( + self, + event: ChatMemberUpdated, + bot: Bot, + timeout_func=None, + attempt_number=1, + max_attempts=1, + ): + self.bot = bot + self.event = event + self.timeout_func = timeout_func + self.attempt_number = attempt_number + self.max_attempts = max_attempts + self.timeout_func_task = None + + @property + def from_chat_id(self): + return self.event.chat.id + + @property + def from_user_id(self): + return self.event.from_user.id + + @property + def from_user(self): + return self.event.from_user + + @property + def attemps_left(self): + return self.max_attempts - self.attempt_number + 1 + + async def start_timeout_func(self): + if self.timeout_func: + self.timeout_func_task = asyncio.create_task(self.timeout_func(self)) + + @staticmethod + def type_name(): + raise NotImplementedError() + + async def run(self): + raise NotImplementedError() + + async def verify(self, data): + raise NotImplementedError() + + async def end(self, success=True): + raise NotImplementedError() + + async def get_timeout(): + raise NotImplementedError() -async def unmute_user(chat_id, user_id, bot: Bot): - await bot.restrict_chat_member( - chat_id, - user_id, - use_independent_chat_permissions=True, - permissions=ChatPermissions( - can_send_messages=True, - can_send_audios=True, - can_send_documents=True, - can_send_photos=True, - can_send_videos=True, - can_send_video_notes=True, - can_send_voice_notes=True, - can_send_polls=True, - can_send_other_messages=True, - can_add_web_page_previews=True, - can_change_info=True, - can_invite_users=True, - can_pin_messages=True, - can_manage_topics=True, - ), - ) +def mute_while_task(cls): + original_run = getattr(cls, "run", None) + original_end = getattr(cls, "end", None) + if not original_run and not original_end: + return cls -class VerificationMethod: - - def timeout(self, task_data=None) -> int: - """ - Время ожидания - """ - return 30 - - def method_name(self): - pass - - async def pre_task(self, chat_id, user_id, bot: Bot): - pass - - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - pass - - async def post_task(self, task_data, bot: Bot, success=True): - pass - - async def verify(self, task_data): - pass - - -class InputVerificationMethod(VerificationMethod): - async def post_task(self, task_data, bot: Bot, success=True, user=None): - chat_id = task_data["chat_id"] - message_id = task_data["message_id"] - answer_message_id = task_data["answer_message_id"] - - await bot.delete_message(chat_id, message_id) - await bot.delete_message(chat_id, answer_message_id) - - if not success or user is None: - return - - await bot.send_message( - chat_id, - f"{user_mention(user)}, успешно прошли проверку! " - "Пожалуйста, соблюдайте правила группы.", - ) - - -class InlineButtonVerificationMethod(VerificationMethod): - async def pre_task(self, chat_id, user_id, bot: Bot): + @wraps(original_run) + async def wrapped_run(self: BaseTask): + chat_id = self.from_chat_id + user_id = self.from_user_id try: - await mute_user(chat_id, user_id, 0, bot) - except TelegramBadRequest: + await mute_user(chat_id, user_id, 0, self.bot) + except TelegramBadRequest as e: + log(e) pass + return await original_run(self) - async def post_task(self, task_data, bot: Bot, success=True, user=None): - user_id = task_data["user_id"] - chat_id = task_data["chat_id"] - message_id = task_data["message_id"] + @wraps(original_end) + async def wrapped_end(self: BaseTask, success=True): + await original_end(self, success) + if success: + chat_id = self.from_chat_id + user_id = self.from_user_id + try: + await unmute_user(chat_id, user_id, self.bot) + except TelegramBadRequest as e: + log(e) + pass - await bot.delete_message(chat_id, message_id) - - try: - await unmute_user(chat_id, user_id, bot) - except TelegramBadRequest: - pass - - if not success or user is None: - return - - await bot.send_message( - chat_id, - f"{user_mention(user)}, успешно прошли проверку! " - "Пожалуйста, соблюдайте правила группы.", - ) + cls.run = wrapped_run + cls.end = wrapped_end + return cls class VerificationCallback(CallbackData, prefix="verify"): diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py deleted file mode 100644 index d6c3420..0000000 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/iamhuman.py +++ /dev/null @@ -1,78 +0,0 @@ -import random - -from aiogram import Bot -from aiogram.enums import ParseMode -from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup - -from .base import ( - InlineButtonVerificationMethod, - InputVerificationMethod, - VerificationCallback, -) -from .utils import user_mention - - -class IAmHumanButton(InlineButtonVerificationMethod): - def __init__(self): - pass - - def method_name(self): - return "i_am_human_button" - - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - user_id = event.from_user.id - chat_id = event.chat.id - - keyboard = InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text="Я человек!", - callback_data=VerificationCallback( - user_id=user_id, chat_id=chat_id, answer="OK" - ).pack(), - ) - ] - ] - ) - - message = await bot.send_message( - chat_id, - f"Привет, {user_mention(event.from_user)}! ", - "Нажмите кнопку, чтобы подтвердить, что вы не робот.", - reply_markup=keyboard, - parse_mode=ParseMode.HTML, - ) - - return {"message_id": message.message_id} - - async def verify(self, task_data): - return True - - -class IAmHumanInput(InputVerificationMethod): - def __init__(self): - pass - - def method_name(self): - return "i_am_human_input" - - def get_text(self): - return random.choice(["Я человек", "Я не робот"]) # nosec - - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - chat_id = event.chat.id - text = self.get_text() - message = await bot.send_message( - chat_id, - f"Привет, {user_mention(event.from_user)}! " - f'Напишите "{text}", чтобы подтвердить, что вы не робот.', - parse_mode=ParseMode.HTML, - ) - return {"message_id": message.message_id, "correct": text} - - async def verify(self, task_data): - correct: str = task_data["correct"] - answer: str = task_data["answer"] - - return answer.lower() == correct.lower() diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py index b2b812b..301459b 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/math.py @@ -1,63 +1,9 @@ import random -from aiogram import Bot -from aiogram.enums import ParseMode -from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup - -from .base import ( - InlineButtonVerificationMethod, - InputVerificationMethod, - VerificationCallback, -) -from .utils import user_mention +from .simple import SimpleInlineButtonsTask, SimplePollTask, SimpleVariantsBaseTask -class MathInputVerificationMethod(InputVerificationMethod): - def __init__(self): - pass - - def method_name(self): - return "math_input" - - def generate_math_problem(self): - a = random.randint(1, 10) # nosec - b = random.randint(1, 10) # nosec - operation = random.choice(["+", "-", "*"]) # nosec - if operation == "+": - answer = a + b - elif operation == "-": - answer = a - b - else: - answer = a * b - return f"{a} {operation} {b}", str(answer) - - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - chat_id = event.chat.id - problem, answer = self.generate_math_problem() - message = await bot.send_message( - chat_id, - f"Привет, {user_mention(event.from_user)}! " - "Решите простую математическую задачу, " - "чтобы подтвердить, что вы не робот:\\n" - f"{problem} = ?", - parse_mode=ParseMode.HTML, - ) - return {"message_id": message.message_id, "correct": answer} - - async def verify(self, task_data): - correct: str = task_data["correct"] - answer: str = task_data["answer"] - - return answer.strip() == correct - - -class MathButtonsVerification(InlineButtonVerificationMethod): - def __init__(self): - pass - - def method_name(self): - return "math_buttons" - +class BaseMathTask(SimpleVariantsBaseTask): def generate_math_problem(self): a = random.randint(1, 10) # nosec b = random.randint(1, 10) # nosec @@ -70,52 +16,38 @@ class MathButtonsVerification(InlineButtonVerificationMethod): answer = a * b return f"{a} {operation} {b}", answer - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - user_id = event.from_user.id - chat_id = event.chat.id - + async def init(self): problem, correct_answer = self.generate_math_problem() - options = [correct_answer] - while len(options) < 4: + self.variants = [correct_answer] + while len(self.variants) < 4: wrong_answer = random.randint( correct_answer - 5, correct_answer + 5 ) # nosec - if wrong_answer not in options: - options.append(wrong_answer) - random.shuffle(options) # nosec + if wrong_answer not in self.variants: + self.variants.append(wrong_answer) + random.shuffle(self.variants) # nosec - keyboard = InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=str(option), - callback_data=VerificationCallback( - user_id=user_id, chat_id=chat_id, answer=str(option) - ).pack(), - ) - for option in options - ] - ] - ) + self.variants = [str(x) for x in self.variants] - message = await bot.send_message( - chat_id, - f"Привет, {user_mention(event.from_user)}! " - "Решите простую математическую задачу, " - "чтобы подтвердить, что вы не робот:\\n" - f"{problem} = ?", - reply_markup=keyboard, - parse_mode=ParseMode.HTML, - ) + self.task = f"{problem} = ?" + self.correct = str(correct_answer) - return { - "message_id": message.message_id, - "correct": str(correct_answer), - "attempts_count": 2, - } - async def verify(self, task_data): - correct: str = task_data["correct"] - answer: str = task_data["answer"] +class MathInlineButtonsTask(BaseMathTask, SimpleInlineButtonsTask): + """ + Математическая задача с выбором через inline-кнопки + """ - return answer == correct + @staticmethod + def type_name(): + return "math_buttons" + + +class MathPollTask(BaseMathTask, SimplePollTask): + """ + Математическая задача с выбором через Poll + """ + + @staticmethod + def type_name(): + return "math_poll" diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py index 785af3f..eb25afc 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py @@ -1,16 +1,9 @@ import random -from aiogram import Bot -from aiogram.enums import ParseMode -from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup +from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup -from ocab_modules.standard.welcome.verifications_methods.utils import user_mention - -from .base import ( - InlineButtonVerificationMethod, - InputVerificationMethod, - VerificationCallback, -) +from .base import VerificationCallback +from .simple import SimpleInlineButtonsTask, SimplePollTask, SimpleVariantsBaseTask QUESTIONS = [ ( @@ -42,85 +35,45 @@ QUESTIONS = [ ] -class QuestionInputVerification(InputVerificationMethod): - def __init__(self): - pass - - def method_name(self): - return "question_input" - - def get_random_question(self): - return random.choice(QUESTIONS) # nosec - - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - chat_id = event.chat.id - question, answer, _ = self.get_random_question() - message = await bot.send_message( - chat_id, - f"Привет, {user_mention(event.from_user)}! " - "Пожалуйста, ответьте на следующий вопрос, " - f"чтобы подтвердить, что вы не робот: {question}", - parse_mode=ParseMode.HTML, - ) - return {"message_id": message.message_id, "correct": answer.lower()} - - async def verify(self, task_data): - correct: str = task_data["correct"] - answer: str = task_data["answer"] - - return answer.lower().strip() == correct - - -class QuestionButtonsVerification(InlineButtonVerificationMethod): - def __init__(self): - pass - - def method_name(self): - return "question_inline" - - def get_random_question(self): - return random.choice(QUESTIONS) # nosec - - async def create_task(self, event: ChatMemberUpdated, bot: Bot): - user_id = event.from_user.id - chat_id = event.chat.id - - question, correct_answer, wrong_answers = self.get_random_question() +class BaseQuestionsTask(SimpleVariantsBaseTask): + async def init(self): + question, correct_answer, wrong_answers = random.choice(QUESTIONS) # nosec options = [correct_answer] + wrong_answers random.shuffle(options) # nosec - keyboard = InlineKeyboardMarkup( + self.variants = [str(x) for x in options] + + self.task = question + self.correct = correct_answer + + async def verify(self, data): + return self.variants[data] == self.correct + + +class QuestionInlineButtonsTask(BaseQuestionsTask, SimpleInlineButtonsTask): + @staticmethod + def type_name(): + return "question_buttons" + + def build_keyboard(self): + return InlineKeyboardMarkup( inline_keyboard=[ [ InlineKeyboardButton( - text=option, + text=str(option), callback_data=VerificationCallback( - user_id=user_id, chat_id=chat_id, answer=str(i) + user_id=self.from_user_id, + chat_id=self.from_chat_id, + answer=str(i), ).pack(), ) + for i, option in enumerate(self.variants) ] - for i, option in enumerate(options) ] ) - message = await bot.send_message( - chat_id, - f"Привет, {user_mention(event.from_user)}! " - "Пожалуйста, ответьте на следующий вопрос, " - f"чтобы подтвердить, что вы не робот: {question}", - reply_markup=keyboard, - parse_mode=ParseMode.HTML, - ) - return { - "message_id": message.message_id, - "correct": correct_answer, - "options": options, - "attempts_count": 2, - } - - async def verify(self, task_data): - correct: str = task_data["correct"] - answer: str = task_data["answer"] - - return task_data["options"][int(answer)] == correct +class QuestionPollTask(BaseQuestionsTask, SimplePollTask): + @staticmethod + def type_name(): + return "question_poll" diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/simple.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/simple.py new file mode 100644 index 0000000..f396822 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/simple.py @@ -0,0 +1,178 @@ +from string import Template + +from aiogram import Bot +from aiogram.enums import ParseMode, PollType +from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup + +from ..utils import get_plural_form, key_from_poll, key_from_user_chat +from .base import BaseTask, VerificationCallback, mute_while_task +from .utils import user_mention + + +class SimpleBaseTask(BaseTask): + pass + + +class SimpleVariantsBaseTaskConfig: + def __init__(self, task_type, config: dict): + self.config = config + self.task_type = task_type + + @property + def timeout(self): + timeout = self.config.get(f"welcome::tasks::{self.task_type}::timeout") + + if timeout is None: + return self.config.get("welcome::timeout") + + return timeout + + @property + def task_message_text(self): + return self.config.get(f"welcome::tasks::{self.task_type}::message_text") + + @property + def task_retry_message_text(self): + return self.config.get(f"welcome::tasks::{self.task_type}::retry_message_text") + + +class SimpleVariantsBaseTask(SimpleBaseTask): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.config = None + + self.variants = [] + self.task = "" + self.correct = None + + self.task_message_id = None + + def set_config(self, cfg: SimpleVariantsBaseTaskConfig): + self.config = cfg + + def get_timeout(self): + return self.config.timeout + + +@mute_while_task +class SimpleInlineButtonsTask(SimpleVariantsBaseTask): + async def init(self): + raise NotImplementedError() + + def build_keyboard(self): + return InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=str(option), + callback_data=VerificationCallback( + user_id=self.from_user_id, + chat_id=self.from_chat_id, + answer=str(option), + ).pack(), + ) + for option in self.variants + ] + ] + ) + + async def run(self): + await self.init() + + message_template = Template( + self.config.task_message_text + if self.attempt_number == 1 + else self.config.task_retry_message_text + ) + + chat_id = self.from_chat_id + message = await self.bot.send_message( + chat_id, + text=message_template.substitute( + mention=user_mention(self.from_user), + task=self.task, + attempts=get_plural_form( + self.attemps_left, "попытка", "попытки", "попыток" + ), + ), + reply_markup=self.build_keyboard(), + parse_mode=ParseMode.HTML, + ) + + self.task_message_id = message.message_id + + await self.start_timeout_func() + + return [key_from_user_chat(self.from_user_id, self.from_chat_id)] + + async def verify(self, data): + return self.correct == data + + async def end(self, success=True): + await self.bot.delete_message(self.from_chat_id, self.task_message_id) + if self.timeout_func_task: + self.timeout_func_task.cancel() + + +@mute_while_task +class SimplePollTask(SimpleVariantsBaseTask): + def __init__( + self, + event: ChatMemberUpdated, + bot: Bot, + timeout_func=None, + attempt_number=1, + max_attempts=1, + ): + super().__init__(event, bot, timeout_func, attempt_number, max_attempts) + self.correct_index = None + + async def init(self): + raise NotImplementedError() + + async def run(self): + await self.init() + + self.correct_index = self.variants.index(self.correct) + + message_template = Template( + self.config.task_message_text + if self.attempt_number == 1 + else self.config.task_retry_message_text + ) + + chat_id = self.from_chat_id + message = await self.bot.send_poll( + chat_id, + question=message_template.substitute( + mention=self.from_user.first_name, + task=self.task, + attempts=get_plural_form( + self.attemps_left, "попытка", "попытки", "попыток" + ), + ), + options=self.variants, + type=PollType.QUIZ, + correct_option_id=self.correct_index, + allows_multiple_answers=False, + is_anonymous=False, + # parse_mode=ParseMode.HTML + ) + + self.task_message_id = message.message_id + + await self.start_timeout_func() + + return [ + key_from_poll(message.poll.id), + key_from_user_chat(self.from_user_id, self.from_chat_id), + ] + + async def verify(self, data): + return self.correct_index == data + + async def end(self, success=True): + await self.bot.delete_message(self.from_chat_id, self.task_message_id) + if self.timeout_func_task: + self.timeout_func_task.cancel() diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py index 41e9a61..f544735 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/utils.py @@ -1,5 +1,8 @@ +import time + +from aiogram import Bot from aiogram.enums import ParseMode -from aiogram.types import User +from aiogram.types import ChatPermissions, User def user_mention(user: User, mode=ParseMode.HTML): @@ -9,3 +12,53 @@ def user_mention(user: User, mode=ParseMode.HTML): return f"[{user.first_name}](tg://user?id={user.id})" else: raise ValueError(f"Unknown parse mode {mode}") + + +async def mute_user(chat_id, user_id, until, bot: Bot): + end_time = until + int(time.time()) + await bot.restrict_chat_member( + chat_id, + user_id, + until_date=end_time, + use_independent_chat_permissions=True, + permissions=ChatPermissions( + can_send_messages=False, + can_send_audios=False, + can_send_documents=False, + can_send_photos=False, + can_send_videos=False, + can_send_video_notes=False, + can_send_voice_notes=False, + can_send_polls=False, + can_send_other_messages=False, + can_add_web_page_previews=False, + can_change_info=False, + can_invite_users=False, + can_pin_messages=False, + can_manage_topics=False, + ), + ) + + +async def unmute_user(chat_id, user_id, bot: Bot): + await bot.restrict_chat_member( + chat_id, + user_id, + use_independent_chat_permissions=True, + permissions=ChatPermissions( + can_send_messages=True, + can_send_audios=True, + can_send_documents=True, + can_send_photos=True, + can_send_videos=True, + can_send_video_notes=True, + can_send_voice_notes=True, + can_send_polls=True, + can_send_other_messages=True, + can_add_web_page_previews=True, + can_change_info=True, + can_invite_users=True, + can_pin_messages=True, + can_manage_topics=True, + ), + ) From afbd2774285d593a25dbd94e312e2fbb22aadada Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 21:54:58 +0300 Subject: [PATCH 13/38] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=81=D1=82=D0=B0=D1=80=D1=8B=D1=85=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BE=D0=B1=20?= =?UTF-8?q?=D1=83=D1=81=D0=BF=D0=B5=D1=85=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ocab_modules/standard/welcome/main.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py index 258b529..92210b1 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/main.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING from aiogram import Bot, Router, types from aiogram.enums import ChatMemberStatus, ParseMode +from aiogram.exceptions import TelegramBadRequest from aiogram.filters import JOIN_TRANSITION, LEAVE_TRANSITION, ChatMemberUpdatedFilter from aiogram.types import ChatMemberUpdated, PollAnswer @@ -43,6 +44,7 @@ class TaskManager: for cls in all_tasks: type_name = cls.type_name() if self.config.get(f"welcome::tasks::{type_name}::enabled"): + log(f"Task {cls.type_name()} enabled") self.available_tasks.append(cls) self.max_attempts = self.config.get("welcome::max_attempts") @@ -65,6 +67,7 @@ class TaskManager: verification_tasks = MultiKeyDict() +last_success = {} if TYPE_CHECKING: from ocab_modules.standard.config import IConfig @@ -117,8 +120,15 @@ async def success_end(task: BaseTask): await asyncio.sleep(3) + if task.from_chat_id in last_success: + message_id = last_success.pop(task.from_chat_id) + try: + await task.bot.delete_message(task.from_chat_id, message_id) + except TelegramBadRequest: + pass + if config.get("welcome::show_success_message"): - await task.bot.send_message( + message = await task.bot.send_message( task.from_chat_id, Template(config.get("welcome::success_message")).substitute( mention=user_mention(task.from_user) @@ -126,6 +136,8 @@ async def success_end(task: BaseTask): parse_mode=ParseMode.HTML, ) + last_success[task.from_chat_id] = message.message_id + async def handle_poll_verification(answer: PollAnswer, bot: Bot): key = key_from_poll(answer.poll_id) From b7cba315d79d0bbf0416c1d0bcf7171211a7cafb Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 22:03:36 +0300 Subject: [PATCH 14/38] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=B2=20BaseQ?= =?UTF-8?q?uestionsTask?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../standard/welcome/verifications_methods/question.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py index eb25afc..6e9bca0 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py @@ -47,7 +47,7 @@ class BaseQuestionsTask(SimpleVariantsBaseTask): self.correct = correct_answer async def verify(self, data): - return self.variants[data] == self.correct + return self.variants[int(data)] == self.correct class QuestionInlineButtonsTask(BaseQuestionsTask, SimpleInlineButtonsTask): From 58281f25802c2e77150354a51c9283972a9482ae Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 22:08:14 +0300 Subject: [PATCH 15/38] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=B0=D1=82=D1=83=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../standard/welcome/verifications_methods/question.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py index 6e9bca0..4e28139 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/verifications_methods/question.py @@ -67,8 +67,8 @@ class QuestionInlineButtonsTask(BaseQuestionsTask, SimpleInlineButtonsTask): answer=str(i), ).pack(), ) - for i, option in enumerate(self.variants) ] + for i, option in enumerate(self.variants) ] ) From f6f0f8c02bb6233ef4d194b9263ea50d4299e296 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 22:43:10 +0300 Subject: [PATCH 16/38] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B4=D0=B5=D1=84=D0=BE=D1=82=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ocab_modules/standard/welcome/main.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py index 92210b1..1f5c068 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/main.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -232,12 +232,12 @@ task_manager = TaskManager(config) async def module_init(): - config.register("welcome::timeout", "int", default_value=45) - config.register("welcome::max_attempts", "int", default_value=2) + config.register("welcome::timeout", "int", default_value=60) + config.register("welcome::max_attempts", "int", default_value=5) config.register( "welcome::retry_message", "string", - default_value="Неправильный ответ! У вас еще $attempts", + default_value="Неправильный ответ! У вас еще $attempts.", ) config.register("welcome::show_success_message", "boolean", default_value=True) config.register( @@ -255,14 +255,14 @@ async def module_init(): "welcome::tasks::math_buttons::message_text", "int", default_value="Привет, $mention!\n" - "Решите простую математическую задачу," + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register( "welcome::tasks::math_buttons::retry_message_text", "int", default_value="$mention, неправильный ответ! У вас еще $attempts\n" - "Решите простую математическую задачу," + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register("welcome::tasks::math_buttons::timeout", "int", default_value=None) @@ -274,14 +274,14 @@ async def module_init(): "welcome::tasks::math_poll::message_text", "string", default_value="Привет, $mention!\n" - "Решите простую математическую задачу," + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register( "welcome::tasks::math_poll::retry_message_text", "string", default_value="$mention, неправильный ответ! У вас еще $attempts\n" - "Решите простую математическую задачу," + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register("welcome::tasks::math_poll::timeout", "int", default_value=None) @@ -295,14 +295,14 @@ async def module_init(): "welcome::tasks::question_buttons::message_text", "string", default_value="Привет, $mention!\n" - "Решите простую математическую задачу," + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register( "welcome::tasks::question_buttons::retry_message_text", "string", - default_value="$mention, неправильный ответ! У вас еще $attempts\n" - "Решите простую математическую задачу," + default_value="$mention, неправильный ответ! У вас еще $attempts.\n" + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register( @@ -318,14 +318,14 @@ async def module_init(): "welcome::tasks::question_poll::message_text", "string", default_value="Привет, $mention!\n" - "Решите простую математическую задачу," + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register( "welcome::tasks::question_poll::retry_message_text", "string", - default_value="$mention, неправильный ответ! У вас еще $attempts\n" - "Решите простую математическую задачу," + default_value="$mention, неправильный ответ! У вас еще $attempts.\n" + "Ответьте на вопрос, " "чтобы подтвердить, что вы не робот:\n\n$task", ) config.register("welcome::tasks::question_poll::timeout", "int", default_value=None) From 9ca32cfa28337b68d71d8ffba7c73f030be6bfe9 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 23:16:31 +0300 Subject: [PATCH 17/38] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B8=D0=BB=20inline=20=D1=82=D0=B0=D1=81=D0=BA=D0=B8=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D0=B4=D0=B5=D1=84=D0=BE=D0=BB=D1=82=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ocab_modules/ocab_modules/standard/welcome/main.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py index 1f5c068..1fe147d 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/main.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -249,7 +249,7 @@ async def module_init(): # MATH BUTTONS config.register( - "welcome::tasks::math_buttons::enabled", "boolean", default_value=True + "welcome::tasks::math_buttons::enabled", "boolean", default_value=False ) config.register( "welcome::tasks::math_buttons::message_text", @@ -289,7 +289,7 @@ async def module_init(): # QUESTION BUTTONS config.register( - "welcome::tasks::question_buttons::enabled", "boolean", default_value=True + "welcome::tasks::question_buttons::enabled", "boolean", default_value=False ) config.register( "welcome::tasks::question_buttons::message_text", @@ -333,13 +333,12 @@ async def module_init(): router = Router() router.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION))(new_member_handler) - router.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION))(left_member_handler) - router.callback_query(VerificationCallback.filter())( handle_inline_button_verification ) router.poll_answer()(handle_poll_verification) + # router.message()(handle_input_verification) register_router(router) From c01dbcbe6b5ae339144dc2a592702ea2233cf531 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 23:37:34 +0300 Subject: [PATCH 18/38] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BF=D0=BE=20=D1=87=D0=B0=D1=82=D0=B0?= =?UTF-8?q?=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ocab_modules/standard/welcome/main.py | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/ocab_modules/ocab_modules/standard/welcome/main.py b/src/ocab_modules/ocab_modules/standard/welcome/main.py index 1fe147d..0d7de71 100644 --- a/src/ocab_modules/ocab_modules/standard/welcome/main.py +++ b/src/ocab_modules/ocab_modules/standard/welcome/main.py @@ -13,9 +13,6 @@ from ocab_core.modules_system.public_api import get_module, log, register_router from .utils import MultiKeyDict, get_plural_form, key_from_poll, key_from_user_chat from .verifications_methods.base import BaseTask, VerificationCallback - -# from .verifications_methods.simple import SimpleInlineButtonsMethod -# from .verifications_methods.iamhuman import IAmHumanButton from .verifications_methods.math import MathInlineButtonsTask, MathPollTask from .verifications_methods.question import QuestionInlineButtonsTask, QuestionPollTask from .verifications_methods.simple import ( @@ -24,7 +21,18 @@ from .verifications_methods.simple import ( ) from .verifications_methods.utils import user_mention -# from .verifications_methods.question import QuestionButtonsVerification +if TYPE_CHECKING: + from ocab_modules.standard.config import IConfig + from ocab_modules.standard.filters import ChatIDFilter as IChatIDFilter + +config: "IConfig" = get_module("standard.config", "config") + +try: + ChatIDFilter: "type[IChatIDFilter]" = get_module("standard.filters", "ChatIDFilter") + FILTERS_MODULE_LOADED = True +except Exception: + FILTERS_MODULE_LOADED = False + pass all_tasks = [ MathInlineButtonsTask, @@ -69,9 +77,6 @@ class TaskManager: verification_tasks = MultiKeyDict() last_success = {} -if TYPE_CHECKING: - from ocab_modules.standard.config import IConfig - async def new_member_handler(event: ChatMemberUpdated, bot: Bot): # НЕ СРАБОТАЕТ, ЕСЛИ ЧЕЛОВЕК УЖЕ ОГРАНИЧЕН В ПРАВАХ (RESTRICTED) @@ -332,14 +337,23 @@ async def module_init(): router = Router() - router.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION))(new_member_handler) - router.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION))(left_member_handler) - router.callback_query(VerificationCallback.filter())( + common_filters_pre = [] + + if FILTERS_MODULE_LOADED: + common_filters_pre.append(ChatIDFilter()) + + router.chat_member(*common_filters_pre, ChatMemberUpdatedFilter(JOIN_TRANSITION))( + new_member_handler + ) + router.chat_member(*common_filters_pre, ChatMemberUpdatedFilter(LEAVE_TRANSITION))( + left_member_handler + ) + router.callback_query(*common_filters_pre, VerificationCallback.filter())( handle_inline_button_verification ) - router.poll_answer()(handle_poll_verification) - # router.message()(handle_input_verification) + # Нельзя применить ChatIDFilter из-за отстутсвия id чата + router.poll_answer()(handle_poll_verification) register_router(router) From 2c06017cc3d630d235669ed5be3f66db9ddcc8fd Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 13 Aug 2024 23:48:40 +0300 Subject: [PATCH 19/38] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D1=87=D0=B0=D1=82=D1=8B,=20=D0=B5?= =?UTF-8?q?=D1=81=D0=BB=D0=B8=20=D0=BE=D0=BD=D0=B8=20=D0=BD=D0=B5=20=D1=83?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ocab_modules/ocab_modules/standard/filters/filters.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ocab_modules/ocab_modules/standard/filters/filters.py b/src/ocab_modules/ocab_modules/standard/filters/filters.py index 3457048..4370baf 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/filters.py +++ b/src/ocab_modules/ocab_modules/standard/filters/filters.py @@ -54,6 +54,11 @@ class ChatIDFilter(BaseFilter): chat_id = message.chat.id approved_chats = self.approved_chats or get_approved_chat_id() + + # Если список для фильтрации пуст - разрешаем всем. + if len(approved_chats) == 0: + return True + res = chat_id in approved_chats return res ^ (self.blacklist) From ac72ec7fa4880b8b64608f466c1a474a7cfdf0fc Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Thu, 15 Aug 2024 19:26:47 +0300 Subject: [PATCH 20/38] =?UTF-8?q?ci:=20=D1=82=D0=B5=D1=81=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D1=8B=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gitflic-ci.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 gitflic-ci.yaml diff --git a/gitflic-ci.yaml b/gitflic-ci.yaml new file mode 100644 index 0000000..c6a98ab --- /dev/null +++ b/gitflic-ci.yaml @@ -0,0 +1,14 @@ +stages: + - lint + +lint-pre-commit: + stage: lint + image: python:3.12-bullseye + before_script: + - pip install pre-commit + scripts: + - pre-commit run --all-files + cache: + paths: + - .cache/pip + - .cache/pre-commit From 913d84fb8193d4e8868f9504b70b8f66334711ce Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Thu, 15 Aug 2024 19:33:04 +0300 Subject: [PATCH 21/38] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B1?= =?UTF-8?q?=D0=BB=D0=B5=D0=BC=20=D0=BB=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 4 +-- src/altlinux/README.md | 2 +- src/altlinux/config-example.yaml | 2 +- .../standard/config/config_manager.py | 2 +- .../ocab_modules/standard/filters/__init__.py | 2 +- .../ocab_modules/standard/report/__init__.py | 2 +- .../ocab_modules/standard/report/main.py | 34 +++++++++---------- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9b94910..39b759d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,8 +1,8 @@ Руководитель проекта: - Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru - + Ведущие разработчики: - Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com - + Участники проекта: - Илья Женецкий (@ilyazheprog) diff --git a/src/altlinux/README.md b/src/altlinux/README.md index 6f6f5c7..ec07657 100644 --- a/src/altlinux/README.md +++ b/src/altlinux/README.md @@ -2,7 +2,7 @@ ## Описание -Подготовленная версия OCAB Lite для интеграции в чат [Альт Линукс](https://t.me/alt_linux) +Подготовленная версия OCAB Lite для интеграции в чат [Альт Линукс](https://t.me/alt_linux) ## Функционал Список OCAB-модулей используемых в боте: diff --git a/src/altlinux/config-example.yaml b/src/altlinux/config-example.yaml index 1f4c864..a294ec7 100644 --- a/src/altlinux/config-example.yaml +++ b/src/altlinux/config-example.yaml @@ -4,4 +4,4 @@ core: filters: approved_chat_id: - - -111111 \ No newline at end of file + - -111111 diff --git a/src/ocab_modules/ocab_modules/standard/config/config_manager.py b/src/ocab_modules/ocab_modules/standard/config/config_manager.py index adbcfe3..1c61a39 100644 --- a/src/ocab_modules/ocab_modules/standard/config/config_manager.py +++ b/src/ocab_modules/ocab_modules/standard/config/config_manager.py @@ -85,7 +85,7 @@ class ConfigManager: value_type: str, options: List[Any] = None, multiple: bool = False, - default_value = None, + default_value=None, editable: bool = True, shared: bool = False, required: bool = False, diff --git a/src/ocab_modules/ocab_modules/standard/filters/__init__.py b/src/ocab_modules/ocab_modules/standard/filters/__init__.py index ed9efdd..254b877 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/__init__.py +++ b/src/ocab_modules/ocab_modules/standard/filters/__init__.py @@ -1,7 +1,7 @@ from .filters import ( + ChatIDFilter, ChatModerOrAdminFilter, ChatNotInApproveFilter, - ChatIDFilter, chat_not_in_approve, module_init, ) diff --git a/src/ocab_modules/ocab_modules/standard/report/__init__.py b/src/ocab_modules/ocab_modules/standard/report/__init__.py index 729f10a..c8fccb0 100644 --- a/src/ocab_modules/ocab_modules/standard/report/__init__.py +++ b/src/ocab_modules/ocab_modules/standard/report/__init__.py @@ -1 +1 @@ -from .main import module_init \ No newline at end of file +from .main import module_init diff --git a/src/ocab_modules/ocab_modules/standard/report/main.py b/src/ocab_modules/ocab_modules/standard/report/main.py index aa744c8..7d6ea10 100644 --- a/src/ocab_modules/ocab_modules/standard/report/main.py +++ b/src/ocab_modules/ocab_modules/standard/report/main.py @@ -1,9 +1,10 @@ from typing import TYPE_CHECKING + from aiogram import Router from aiogram.filters import Command -from aiogram.types import Message, ChatMemberOwner, ChatMemberAdministrator +from aiogram.types import ChatMemberAdministrator, ChatMemberOwner, Message -from ocab_core.modules_system.public_api import get_module, register_router, log +from ocab_core.modules_system.public_api import get_module, log, register_router if TYPE_CHECKING: from ocab_modules.standard.filters import ChatIDFilter as IChatIDFilter @@ -11,41 +12,40 @@ if TYPE_CHECKING: try: ChatIDFilter: "type[IChatIDFilter]" = get_module("standard.filters", "ChatIDFilter") FILTERS_MODULE_LOADED = True -except Exception as e: +except Exception: FILTERS_MODULE_LOADED = False pass try: register_command = get_module("standard.command_helper", "register_command") COMMAND_HELPER_MODULE_LOADED = True -except Exception as e: +except Exception: COMMAND_HELPER_MODULE_LOADED = False pass + def can_moderate(admin: ChatMemberOwner | ChatMemberAdministrator) -> bool: if isinstance(admin, ChatMemberOwner): return True - return ( - admin.user.is_bot == False and - ( - admin.can_delete_messages and - admin.can_restrict_members - ) + return admin.user.is_bot is False and ( + admin.can_delete_messages and admin.can_restrict_members ) + async def report(message: Message): try: if message.reply_to_message is None: - await message.reply("Пожалуйста, используйте команду /report в ответ на сообщение, которое вы хотите отметить как спам.") - return + await message.reply( + "Пожалуйста, используйте команду /report в ответ на сообщение" + ", которое вы хотите отметить как спам." + ) + return admins = await message.chat.get_administrators() - + admin_usernames = [ - admin.user.mention_html() - for admin in admins - if can_moderate(admin) + admin.user.mention_html() for admin in admins if can_moderate(admin) ] if admin_usernames: ping_message = "⚠️ Внимание, жалоба на спам! " + ", ".join(admin_usernames) @@ -66,4 +66,4 @@ async def module_init(): if COMMAND_HELPER_MODULE_LOADED: register_command = get_module("standard.command_helper", "register_command") - register_command("report", "Пожаловаться на спам") \ No newline at end of file + register_command("report", "Пожаловаться на спам") From 79298e544191f8e456d8a32ad508c88005e93d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BB=D0=B8?= =?UTF-8?q?=D0=BF=D0=B5=D0=BD=D0=BA=D0=BE?= Date: Fri, 16 Aug 2024 16:23:57 +0300 Subject: [PATCH 22/38] Merged with fix/add-limits-to-report --- gitflic-ci.yaml | 19 +++++++ .../ocab_modules/standard/report/info.json | 9 ++++ .../ocab_modules/standard/report/main.py | 53 ++++++++++++++----- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/gitflic-ci.yaml b/gitflic-ci.yaml index c6a98ab..8cc9912 100644 --- a/gitflic-ci.yaml +++ b/gitflic-ci.yaml @@ -1,5 +1,6 @@ stages: - lint + - build lint-pre-commit: stage: lint @@ -12,3 +13,21 @@ lint-pre-commit: paths: - .cache/pip - .cache/pre-commit + +build-altlinux: + stage: build + image: docker:27.1.2 + variables: + CI_REGISTRY: registry.gitflic.ru + IMAGE_NAME: registry.gitflic.ru/project/alt-gnome/karkas/altlinux + before_script: + - docker info + - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY} + scripts: + - | + cd ./src/altlinux + export IMAGE_COMMIT=${IMAGE_NAME}:${CI_COMMIT_SHA} + export IMAGE_BRANCH=${IMAGE_NAME}:$(echo $CI_COMMIT_REF_NAME | sed 's/[^a-zA-Z0-9]/-/g') + docker build -t ${IMAGE_COMMIT} -t ${IMAGE_BRANCH} -f Dockerfile ../.. + docker push ${IMAGE_COMMIT} + docker push ${IMAGE_BRANCH} diff --git a/src/ocab_modules/ocab_modules/standard/report/info.json b/src/ocab_modules/ocab_modules/standard/report/info.json index ac5e2f3..27f7d0e 100644 --- a/src/ocab_modules/ocab_modules/standard/report/info.json +++ b/src/ocab_modules/ocab_modules/standard/report/info.json @@ -6,9 +6,18 @@ "version": "1.0.0", "privileged": false, "dependencies": { + "required": { + "standard.config": "^1.0.0" + }, "optional": { "standard.command_helper": "^1.0.0", "standard.filters": "^1.0.0" } + }, + "pythonDependencies": { + "required": { + "random": "*", + "string": "*" + } } } diff --git a/src/ocab_modules/ocab_modules/standard/report/main.py b/src/ocab_modules/ocab_modules/standard/report/main.py index 7d6ea10..43837fa 100644 --- a/src/ocab_modules/ocab_modules/standard/report/main.py +++ b/src/ocab_modules/ocab_modules/standard/report/main.py @@ -1,3 +1,5 @@ +import random +from string import Template from typing import TYPE_CHECKING from aiogram import Router @@ -7,8 +9,11 @@ from aiogram.types import ChatMemberAdministrator, ChatMemberOwner, Message from ocab_core.modules_system.public_api import get_module, log, register_router if TYPE_CHECKING: + from ocab_modules.standard.config import IConfig from ocab_modules.standard.filters import ChatIDFilter as IChatIDFilter +config: "IConfig" = get_module("standard.config", "config") + try: ChatIDFilter: "type[IChatIDFilter]" = get_module("standard.filters", "ChatIDFilter") FILTERS_MODULE_LOADED = True @@ -36,25 +41,50 @@ def can_moderate(admin: ChatMemberOwner | ChatMemberAdministrator) -> bool: async def report(message: Message): try: if message.reply_to_message is None: - await message.reply( - "Пожалуйста, используйте команду /report в ответ на сообщение" - ", которое вы хотите отметить как спам." - ) + await message.reply(config.get("report::errors::no_reply_message")) return - admins = await message.chat.get_administrators() + mention_list = config.get("report::mention::list") - admin_usernames = [ - admin.user.mention_html() for admin in admins if can_moderate(admin) - ] - if admin_usernames: - ping_message = "⚠️ Внимание, жалоба на спам! " + ", ".join(admin_usernames) - await message.reply_to_message.reply(ping_message, parse_mode="HTML") + if mention_list is None: + admins = await message.chat.get_administrators() + mention_list = [ + admin.user.mention_html() for admin in admins if can_moderate(admin) + ] + + random.shuffle(mention_list) + + limit = config.get("report::mention::limit") + if limit != -1: + mention_list = mention_list[:limit] + + if mention_list: + await message.reply_to_message.reply( + Template(config.get("report::mention::text")).substitute( + mention=", ".join(mention_list) + ), + parse_mode="HTML", + ) except Exception as e: log(e) async def module_init(): + config.register("report::mention::limit", "int", default_value=5) + config.register( + "report::mention::list", "string", multiple=True, default_value=None + ) + config.register( + "report::mention::text", + "string", + default_value="⚠️ Внимание, жалоба на спам! $mention", + ) + config.register( + "report::errors::no_reply_message", + "string", + default_value="Пожалуйста, используйте команду в ответ на сообщение", + ) + router = Router() if FILTERS_MODULE_LOADED: @@ -65,5 +95,4 @@ async def module_init(): register_router(router) if COMMAND_HELPER_MODULE_LOADED: - register_command = get_module("standard.command_helper", "register_command") register_command("report", "Пожаловаться на спам") From df1fed10c2d45cd9fd1446f7c2c8f2cc4a07ddd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BB=D0=B8?= =?UTF-8?q?=D0=BF=D0=B5=D0=BD=D0=BA=D0=BE?= Date: Fri, 16 Aug 2024 16:25:42 +0300 Subject: [PATCH 23/38] Merged with feat/add-standard-help --- src/altlinux/altlinux/__main__.py | 5 +- src/ocab_core/ocab_core/main.py | 4 +- .../modules_system/public_api/__init__.py | 1 + .../modules_system/public_api/public_api.py | 5 ++ .../ocab_core/modules_system/safe/policy.py | 2 + .../standard/command_helper/__init__.py | 2 +- .../standard/command_helper/main.py | 6 ++ .../ocab_modules/standard/help/__init__.py | 1 + .../ocab_modules/standard/help/info.json | 21 +++++ .../ocab_modules/standard/help/main.py | 81 +++++++++++++++++++ 10 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 src/ocab_modules/ocab_modules/standard/help/__init__.py create mode 100644 src/ocab_modules/ocab_modules/standard/help/info.json create mode 100644 src/ocab_modules/ocab_modules/standard/help/main.py diff --git a/src/altlinux/altlinux/__main__.py b/src/altlinux/altlinux/__main__.py index ffd1e3b..d49b85a 100644 --- a/src/altlinux/altlinux/__main__.py +++ b/src/altlinux/altlinux/__main__.py @@ -1,4 +1,5 @@ import asyncio +from importlib.metadata import version from ocab_core import OCAB from ocab_modules import module_loader @@ -14,7 +15,9 @@ async def main(): module_loader("standard", "filters", safe=False), module_loader("standard", "report"), module_loader("standard", "welcome", safe=False), - ] + module_loader("standard", "help"), + ], + metainfo={"app_version": version("altlinux")}, ) await ocab.start() diff --git a/src/ocab_core/ocab_core/main.py b/src/ocab_core/ocab_core/main.py index 83a0b5c..fb91365 100644 --- a/src/ocab_core/ocab_core/main.py +++ b/src/ocab_core/ocab_core/main.py @@ -17,9 +17,11 @@ class OCAB: def __init__(self) -> None: pass - async def init_app(self, bot_modules): + async def init_app(self, bot_modules, metainfo=None): setup_logger() singleton = Singleton() + if isinstance(metainfo, dict): + singleton.storage["metainfo"] = metainfo try: singleton.modules_manager = ModulesManager() diff --git a/src/ocab_core/ocab_core/modules_system/public_api/__init__.py b/src/ocab_core/ocab_core/modules_system/public_api/__init__.py index 1a1cadb..866f4d6 100644 --- a/src/ocab_core/ocab_core/modules_system/public_api/__init__.py +++ b/src/ocab_core/ocab_core/modules_system/public_api/__init__.py @@ -3,6 +3,7 @@ from ocab_core.logger import log from .public_api import ( Storage, get_fsm_context, + get_metainfo, get_module, register_outer_message_middleware, register_router, diff --git a/src/ocab_core/ocab_core/modules_system/public_api/public_api.py b/src/ocab_core/ocab_core/modules_system/public_api/public_api.py index d7598ec..e9ce931 100644 --- a/src/ocab_core/ocab_core/modules_system/public_api/public_api.py +++ b/src/ocab_core/ocab_core/modules_system/public_api/public_api.py @@ -26,6 +26,11 @@ def register_outer_message_middleware(middleware: BaseMiddleware): app.storage["_outer_message_middlewares"].append(middleware) +def get_metainfo(): + app = Singleton() + return app.storage["metainfo"].copy() + + async def set_my_commands(commands): app = Singleton() await app.bot.set_my_commands(commands) diff --git a/src/ocab_core/ocab_core/modules_system/safe/policy.py b/src/ocab_core/ocab_core/modules_system/safe/policy.py index 08810c9..d74fe6f 100644 --- a/src/ocab_core/ocab_core/modules_system/safe/policy.py +++ b/src/ocab_core/ocab_core/modules_system/safe/policy.py @@ -12,6 +12,7 @@ from RestrictedPython import ( from RestrictedPython.Eval import default_guarded_getitem, default_guarded_getiter from RestrictedPython.Guards import ( # guarded_setattr,; full_write_guard, _write_wrapper, + guarded_iter_unpack_sequence, guarded_unpack_sequence, safer_getattr, ) @@ -138,6 +139,7 @@ BUILTINS["_getitem_"] = default_guarded_getitem BUILTINS["_getattr_"] = safes_getattr BUILTINS["_getiter_"] = default_guarded_getiter BUILTINS["_write_"] = write_guard() +BUILTINS["_iter_unpack_sequence_"] = guarded_iter_unpack_sequence BUILTINS["_unpack_sequence_"] = guarded_unpack_sequence BUILTINS["staticmethod"] = staticmethod BUILTINS["tuple"] = tuple diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py b/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py index 90596da..3461e7b 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py +++ b/src/ocab_modules/ocab_modules/standard/command_helper/__init__.py @@ -1 +1 @@ -from .main import module_late_init, register_command +from .main import get_user_commands, module_late_init, register_command diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/main.py b/src/ocab_modules/ocab_modules/standard/command_helper/main.py index f7c417e..9fcb5f9 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/main.py +++ b/src/ocab_modules/ocab_modules/standard/command_helper/main.py @@ -32,5 +32,11 @@ async def set_user_commands(): ) +def get_user_commands(): + if "USER" in commands: + return commands["USER"].copy() + return {} + + async def module_late_init(): await set_user_commands() diff --git a/src/ocab_modules/ocab_modules/standard/help/__init__.py b/src/ocab_modules/ocab_modules/standard/help/__init__.py new file mode 100644 index 0000000..c8fccb0 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/help/__init__.py @@ -0,0 +1 @@ +from .main import module_init diff --git a/src/ocab_modules/ocab_modules/standard/help/info.json b/src/ocab_modules/ocab_modules/standard/help/info.json new file mode 100644 index 0000000..30cbbe6 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/help/info.json @@ -0,0 +1,21 @@ +{ + "id": "standard.help", + "name": "Help", + "description": "Модуль для вывода /help сообщения", + "author": "OCAB Team", + "version": "1.0.0", + "privileged": false, + "dependencies": { + "required": { + "standard.config": "^1.0.0" + }, + "optional": { + "standard.command_helper": "^1.0.0" + } + }, + "pythonDependencies": { + "required": { + "string": "*" + } + } +} diff --git a/src/ocab_modules/ocab_modules/standard/help/main.py b/src/ocab_modules/ocab_modules/standard/help/main.py new file mode 100644 index 0000000..6dedb83 --- /dev/null +++ b/src/ocab_modules/ocab_modules/standard/help/main.py @@ -0,0 +1,81 @@ +import string +from typing import TYPE_CHECKING + +from aiogram import Router +from aiogram.filters import Command +from aiogram.types import Message + +from ocab_core.modules_system.public_api import ( + get_metainfo, + get_module, + register_router, +) + +if TYPE_CHECKING: + from ocab_modules.standard.config import IConfig + +config: "IConfig" = get_module("standard.config", "config") + +try: + (register_command, get_user_commands) = get_module( + "standard.command_helper", ["register_command", "get_user_commands"] + ) + COMMAND_HELPER_MODULE_LOADED = True +except Exception: + COMMAND_HELPER_MODULE_LOADED = False + pass + +FOOTER = """=== + +Разработано командой ALT Gnome Infrastructure в рамках проекта Каркас. + +Исходный код: https://gitflic.ru/project/alt-gnome/karkas +Оставить репорт: https://gitflic.ru/project/alt-gnome/karkas/issue/create + +Руководитель проекта: Семен Фомченков +Ведущий разработчик: Максим Слипенко + +Версия: $version +""" + + +def format_commands(commands_dict): + formatted_commands = [] + for command, details in commands_dict.items(): + formatted_commands.append(f"/{command} - {details['description']}") + return "\n".join(formatted_commands) + + +async def help(message: Message): + commands = "" + version = "" + + if COMMAND_HELPER_MODULE_LOADED: + commands = format_commands(get_user_commands()) + + metainfo = get_metainfo() + if "app_version" in metainfo: + version = metainfo["app_version"] + + await message.reply( + string.Template(config.get("help::message") + "\n\n" + FOOTER).substitute( + commands=commands, version=version or "не указана" + ) + ) + + +async def module_init(): + config.register( + "help::message", + "string", + default_value="$commands", + ) + + router = Router() + + router.message.register(help, Command("help")) + + register_router(router) + + if COMMAND_HELPER_MODULE_LOADED: + register_command("help", "Cправка") From 9fa5776fdac93fc0da8a42b4615e50bf5da72ea9 Mon Sep 17 00:00:00 2001 From: Armatik Date: Fri, 16 Aug 2024 22:40:33 +0300 Subject: [PATCH 24/38] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20=D1=84=D0=B0=D0=B9=D0=BB?= =?UTF-8?q?=20=D1=81=D0=BE=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE=D0=BC=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..39b759d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +Руководитель проекта: + - Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru + +Ведущие разработчики: + - Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com + +Участники проекта: + - Илья Женецкий (@ilyazheprog) From 5b3963e87c0485b759ca196b8d3fa25c0d54995a Mon Sep 17 00:00:00 2001 From: Armatik Date: Fri, 16 Aug 2024 22:41:08 +0300 Subject: [PATCH 25/38] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B0=D0=BD=D0=B3=D0=BB=D0=B8=D0=B9=D1=81=D0=BA=D1=83?= =?UTF-8?q?=D1=8E=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8E=20=D1=81=D0=BE=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE=D0=BC=20=D0=B0=D0=B2=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=BE=D0=B2=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS_EN | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 AUTHORS_EN diff --git a/AUTHORS_EN b/AUTHORS_EN new file mode 100644 index 0000000..3db4115 --- /dev/null +++ b/AUTHORS_EN @@ -0,0 +1,8 @@ +Project manager: + - Semen Fomchenkov (@Armatik), e-mail: armatik@alt-gnome.ru + +Leading developers: + - Maxim Slipenko (@Maks1m_S), e-mail: maxim@slipenko.com + +Project participants: + - Ilya Zhenetsky (@ilyazheprog) From 3c7dffc06dea501e312b73c559c4af24c8d740df Mon Sep 17 00:00:00 2001 From: Armatik Date: Fri, 16 Aug 2024 22:42:02 +0300 Subject: [PATCH 26/38] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20c=20OCAB=20=D0=B2=20Karkas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- CONTRIBUTORS | 8 ---- README.md | 46 +++++++++---------- docs/DEV.md | 12 ++--- docs/MODULES-SPEC.md | 8 ++-- ocab.code-workspace | 10 ++-- pyproject.toml | 8 ++-- scripts/init.py | 6 +-- scripts/module.py | 4 +- src/altlinux/Dockerfile | 6 +-- src/altlinux/README.md | 4 +- src/altlinux/altlinux/__main__.py | 22 ++++----- src/altlinux/poetry.lock | 10 ++-- src/altlinux/pyproject.toml | 4 +- src/ocab_core/README.md | 4 +- src/ocab_core/ocab_core/__init__.py | 2 +- src/ocab_core/ocab_core/logger.py | 2 +- src/ocab_core/ocab_core/main.py | 20 ++++---- .../loaders/fs_loader/FSLoader.py | 12 ++--- .../unsafe_fs_loader/UnsafeFSLoader.py | 2 +- .../modules_system/modules_manager.py | 2 +- .../modules_system/public_api/__init__.py | 2 +- .../modules_system/public_api/public_api.py | 10 ++-- .../ocab_core/modules_system/safe/policy.py | 4 +- .../modules_system/safe/zope_guards.py | 2 +- src/ocab_core/ocab_core/singleton.py | 2 +- src/ocab_core/poetry.lock | 6 +-- src/ocab_core/pyproject.toml | 4 +- src/ocab_modules/README.md | 8 ++-- src/ocab_modules/ocab_modules/__init__.py | 2 +- src/ocab_modules/ocab_modules/lib.py | 12 ++--- .../ocab_modules/standard/admin/handlers.py | 4 +- .../ocab_modules/standard/admin/info.json | 2 +- .../ocab_modules/standard/admin/main.py | 2 +- .../ocab_modules/standard/admin/routers.py | 2 +- .../standard/command_helper/README.md | 2 +- .../standard/command_helper/info.json | 2 +- .../standard/command_helper/main.py | 2 +- .../ocab_modules/standard/config/README.md | 2 +- .../standard/config/config_manager.py | 2 +- .../ocab_modules/standard/config/info.json | 2 +- .../ocab_modules/standard/config/main.py | 2 +- .../standard/config/miniapp_ui.py | 4 +- .../standard/config/tests/test_config.py | 2 +- .../ocab_modules/standard/database/README.md | 2 +- .../ocab_modules/standard/database/db_api.py | 4 +- .../ocab_modules/standard/database/info.json | 2 +- .../ocab_modules/standard/filters/README.md | 2 +- .../ocab_modules/standard/filters/filters.py | 6 +-- .../ocab_modules/standard/filters/info.json | 2 +- .../standard/fsm_database_storage/fsm.py | 6 +-- .../standard/fsm_database_storage/info.json | 2 +- .../ocab_modules/standard/help/info.json | 34 +++++++------- .../ocab_modules/standard/help/main.py | 4 +- .../ocab_modules/standard/info/handlers.py | 6 +-- .../ocab_modules/standard/info/info.json | 2 +- .../ocab_modules/standard/info/main.py | 2 +- .../standard/message_processing/info.json | 2 +- .../message_processing/message_api.py | 4 +- .../ocab_modules/standard/miniapp/README.md | 2 +- .../standard/miniapp/dash_telegram_auth.py | 2 +- .../ocab_modules/standard/miniapp/info.json | 40 ++++++++-------- .../ocab_modules/standard/miniapp/lib.py | 8 ++-- .../ocab_modules/standard/miniapp/main.py | 4 +- .../ocab_modules/standard/report/info.json | 38 +++++++-------- .../ocab_modules/standard/report/main.py | 6 +-- .../ocab_modules/standard/roles/README.md | 2 +- .../ocab_modules/standard/roles/info.json | 2 +- .../ocab_modules/standard/roles/main.py | 4 +- .../ocab_modules/standard/roles/roles.py | 6 +-- .../ocab_modules/standard/welcome/info.json | 36 +++++++-------- .../ocab_modules/standard/welcome/main.py | 6 +-- .../welcome/verifications_methods/base.py | 2 +- src/ocab_modules/poetry.lock | 4 +- src/ocab_modules/pyproject.toml | 4 +- 75 files changed, 257 insertions(+), 265 deletions(-) delete mode 100644 CONTRIBUTORS diff --git a/.gitignore b/.gitignore index dddca8d..c747ee6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,6 @@ env .venv venv __pycache__ -OCAB.db +Karkas.db config.yaml dist diff --git a/CONTRIBUTORS b/CONTRIBUTORS deleted file mode 100644 index 39b759d..0000000 --- a/CONTRIBUTORS +++ /dev/null @@ -1,8 +0,0 @@ -Руководитель проекта: - - Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru - -Ведущие разработчики: - - Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com - -Участники проекта: - - Илья Женецкий (@ilyazheprog) diff --git a/README.md b/README.md index b9f8cd9..6cd4dc5 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ -# OCAB - Open Chat Ai Bot +# Karkas - Open Chat Ai Bot -## Что такое OCAB? +## Что такое Karkas? -OCAB - это платформа для разработки модульных Telegram-ботов, которая призвана упростить взаимодействие с чатами. -OCAB предоставляет возможность расширять функциональность бота с помощью интеграции различных модулей. +Karkas - это платформа для разработки модульных Telegram-ботов, которая призвана упростить взаимодействие с чатами. +Karkas предоставляет возможность расширять функциональность бота с помощью интеграции различных модулей. Код платформы и набор стандартных модулей находятся в этом монорепозитории. ## Структура монорепозитория -Монорепозиторий OCAB включает в себя: -* **Ядро OCAB (src/ocab_core):** Содержит основные компоненты платформы, такие как система управления модулями, +Монорепозиторий Karkas включает в себя: +* **Ядро Karkas (src/karkas_core):** Содержит основные компоненты платформы, такие как система управления модулями, логирование и утилиты. -* **Модули OCAB (src/ocab_modules):** Содержит стандартные и дополнительные модули, которые расширяют - функциональность ботов OCAB. -* **Пример бота (src/gnomik):** Пример реализации бота на платформе OCAB. +* **Модули Karkas (src/karkas_blocks):** Содержит стандартные и дополнительные модули, которые расширяют + функциональность ботов Karkas. +* **Пример бота (src/gnomik):** Пример реализации бота на платформе Karkas. ## Модули -Модули OCAB - это независимые компоненты, которые добавляют функциональность к боту. +Модули Karkas - это независимые компоненты, которые добавляют функциональность к боту. ### Структура модуля @@ -26,19 +26,19 @@ OCAB предоставляет возможность расширять фун ### Стандартные модули Стандартные модули предоставляют базовые функции для работы бота: -* [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](src/karkas_blocks/karkas_blocks/standard/admin/README.md) - модуль для модерирования чата. +* [roles](src/karkas_blocks/karkas_blocks/standard/roles/README.md) - модуль ролей пользователей. +* [config](src/karkas_blocks/karkas_blocks/standard/config/README.md) - модуль управления конфигурацией бота. +* [database](src/karkas_blocks/karkas_blocks/standard/database/README.md) - модуль для работы с базой данных. +* [fsm_database_storage](src/karkas_blocks/karkas_blocks/standard/fsm_database_storage/README.md) - модуль для хранения состояний FSM в базе данных. +* [filters](src/karkas_blocks/karkas_blocks/standard/filters/README.md) - модуль, предоставляющий фильтры для aiogram. +* [message_processing](src/karkas_blocks/karkas_blocks/standard/message_processing/README.md) - модуль обработки входящих сообщений. +* [miniapp](src/karkas_blocks/karkas_blocks/standard/miniapp/README.md) - модуль для реализации веб-интерфейса бота. +* [command_helper](src/karkas_blocks/karkas_blocks/standard/command_helper/README.md) - модуль для упрощения регистрации команд бота. +* [info](src/karkas_blocks/karkas_blocks/standard/info/README.md) - модуль предоставления информации о пользователях и чатах. ### Дополнительные официальные модули -Дополнительные официальные модули разработаны командой OCAB и предоставляют расширенные возможности для бота: -* [yandexgpt](src/ocab_modules/ocab_modules/external/yandexgpt/README.md) - модуль для интеграции с нейросетью YandexGPT. -* [create_report_apps](src/ocab_modules/ocab_modules/external/create_report_apps/README.md) - модуль для создания отчетов об ошибках. +Дополнительные официальные модули разработаны командой Karkas и предоставляют расширенные возможности для бота: +* [yandexgpt](src/karkas_blocks/karkas_blocks/external/yandexgpt/README.md) - модуль для интеграции с нейросетью YandexGPT. +* [create_report_apps](src/karkas_blocks/karkas_blocks/external/create_report_apps/README.md) - модуль для создания отчетов об ошибках. diff --git a/docs/DEV.md b/docs/DEV.md index 5962e19..9db59a5 100644 --- a/docs/DEV.md +++ b/docs/DEV.md @@ -1,10 +1,10 @@ ## Настройка рабочего окружения -Данная инструкция поможет вам настроить рабочее окружение для разработки OCAB. +Данная инструкция поможет вам настроить рабочее окружение для разработки Karkas. ### Предварительные требования -* **Python 3.12:** OCAB требует Python 3.12. +* **Python 3.12:** Karkas требует Python 3.12. * **VSCode:** Рекомендуется использовать VSCode для разработки. * **Git:** У вас должен быть установлен Git для клонирования репозитория. @@ -12,18 +12,18 @@ 1. **Клонируйте репозиторий:** ```bash - git clone https://gitflic.ru/project/armatik/ocab.git + git clone https://gitflic.ru/project/alt-gnome/karkas.git ``` 2. **Откройте проект в VSCode:** - * Откройте папку `ocab` в VSCode. - * VSCode автоматически предложит открыть проект как workspace, используя файл `ocab.code-workspace`. + * Откройте папку `karkas` в VSCode. + * VSCode автоматически предложит открыть проект как workspace, используя файл `karkas.code-workspace`. Нажмите "Открыть Workspace", чтобы принять предложение. 3. **Настройте Poetry:** * Установите Poetry, следуя инструкциям на официальном сайте: [https://python-poetry.org/docs/](https://python-poetry.org/docs/). * **Для каждого пакета:** - * Перейдите в папку пакета (например, `src/ocab_core`). + * Перейдите в папку пакета (например, `src/karkas_core`). * Выполните команду `poetry install`, чтобы установить зависимости пакета. * Poetry создаст виртуальное окружение внутри папки пакета (`.venv`). diff --git a/docs/MODULES-SPEC.md b/docs/MODULES-SPEC.md index 561e822..3445dd3 100644 --- a/docs/MODULES-SPEC.md +++ b/docs/MODULES-SPEC.md @@ -16,7 +16,7 @@ "id": "standard.info", "name": "Info", "description": "Модуль с информацией", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": false, "dependencies": { @@ -50,7 +50,7 @@ - `author`: Автор модуля. - `version`: Версия модуля в формате [SemVer](https://semver.org/). - `privileged`: Булево значение, указывающее, является ли модуль привилегированным. -- `dependencies`: Объект, описывающий зависимости модуля от других **OCAB** модулей. +- `dependencies`: Объект, описывающий зависимости модуля от других **Karkas** модулей. - `required`: Обязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`. - `optional`: Необязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`. - `pythonDependencies`: Объект, описывающий зависимости модуля от внешних Python пакетов. @@ -80,7 +80,7 @@ - Модуль выполняется в доверенной среде на основе RestrictedPython (это накладывает ряд ограничений). - Может импортировать только явно разрешенные модули, указанные в `pythonDependencies`, а также несколько стандартных модулей, необходимых для работы. -- Имеет доступ к пакету `ocab_core.modules_system.public_api` для взаимодействия с ботом. +- Имеет доступ к пакету `karkas_core.modules_system.public_api` для взаимодействия с ботом. **Привилегированный режим** (`privileged: true`): - Модуль выполняется без ограничений. @@ -100,7 +100,7 @@ ## Взаимодействие между модулями -Модули могут взаимодействовать друг с другом через [API](../src/ocab_core/ocab_core/modules_system/public_api/__init__.py), +Модули могут взаимодействовать друг с другом через [API](../src/karkas_core/karkas_core/modules_system/public_api/__init__.py), предоставляемое системой управления модулями. Например, есть функция `get_module`. Она позволяет получить модуль или предоставляемые им объекты по его diff --git a/ocab.code-workspace b/ocab.code-workspace index 96f794e..3aad916 100644 --- a/ocab.code-workspace +++ b/ocab.code-workspace @@ -1,16 +1,16 @@ { "folders": [ { - "name": "OCAB Monorepo Root", + "name": "Karkas Monorepo Root", "path": ".", }, { - "name": "OCAB Modules", - "path": "src/ocab_modules" + "name": "Karkas Blocks", + "path": "src/karkas_blocks" }, { - "name": "OCAB Core", - "path": "src/ocab_core" + "name": "Karkas Core", + "path": "src/karkas_core" }, { "name": "Gnomik", diff --git a/pyproject.toml b/pyproject.toml index f8cb63c..d35c7d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] -name = "ocab-monorepo" +name = "karkas-monorepo" version = "2.0.0" -description = "OCAB is a modular Telegram bot" +description = "Karkas is a modular Telegram bot" license = "GPL-3.0-only" authors = ["Семён Фомченков "] maintainers = [ @@ -11,13 +11,13 @@ maintainers = [ "Максим Слипенко " ] readme = "README.md" -repository = "https://gitflic.ru/project/armatik/ocab" +repository = "https://gitflic.ru/project/alt-gnome/karkas" packages = [ { include = "scripts" } ] [tool.poetry.urls] -"Bug Tracker" = "https://gitflic.ru/project/armatik/ocab/issue?status=OPEN" +"Bug Tracker" = "https://gitflic.ru/project/alt-gnome/karkas/issue?status=OPEN" [tool.poetry.scripts] test = 'scripts.test:main' diff --git a/scripts/init.py b/scripts/init.py index 362e4da..c4d9382 100644 --- a/scripts/init.py +++ b/scripts/init.py @@ -4,9 +4,9 @@ from pathlib import Path def main(): pwd = Path().cwd() - dir_core = pwd / "src" / "ocab_core" - dir_modules_standard = pwd / "src" / "ocab_modules" / "standard" - dir_modules_external = pwd / "src" / "ocab_modules" / "external" + dir_core = pwd / "src" / "karkas_core" + dir_modules_standard = pwd / "src" / "karkas_blocks" / "standard" + dir_modules_external = pwd / "src" / "karkas_blocks" / "external" json = { "core": str(dir_core), diff --git a/scripts/module.py b/scripts/module.py index 88e13c3..2e9522b 100644 --- a/scripts/module.py +++ b/scripts/module.py @@ -4,14 +4,14 @@ import os DEFAULTS = { "description": "Очень полезный модуль", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": "false", } def create_module(args): - module_dir = os.path.join("src/ocab_modules/standard", args.module_name) + module_dir = os.path.join("src/karkas_blocks/standard", args.module_name) os.makedirs(module_dir, exist_ok=True) module_info = { diff --git a/src/altlinux/Dockerfile b/src/altlinux/Dockerfile index c789f02..8a1f469 100644 --- a/src/altlinux/Dockerfile +++ b/src/altlinux/Dockerfile @@ -6,9 +6,9 @@ COPY . /app # Фикс -RUN sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \ - sed -i '/ocab-modules = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \ - sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/ocab_modules/pyproject.toml +RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \ + sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \ + sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/karkas_blocks/pyproject.toml WORKDIR /app/src/altlinux diff --git a/src/altlinux/README.md b/src/altlinux/README.md index ec07657..8bee95a 100644 --- a/src/altlinux/README.md +++ b/src/altlinux/README.md @@ -2,14 +2,14 @@ ## Описание -Подготовленная версия OCAB Lite для интеграции в чат [Альт Линукс](https://t.me/alt_linux) +Подготовленная версия Karkas Lite для интеграции в чат [Альт Линукс](https://t.me/alt_linux) ## Функционал Список OCAB-модулей используемых в боте: * report - Вызов администрации чата одной командой * welcome - Автоматическая вариативная проверка пользователей на признаки бота или другой автоматической рекламной системы -* help - Получение информации об OCAB Lite +* help - Получение информации об Karkas Lite ## Запуск diff --git a/src/altlinux/altlinux/__main__.py b/src/altlinux/altlinux/__main__.py index d49b85a..618082b 100644 --- a/src/altlinux/altlinux/__main__.py +++ b/src/altlinux/altlinux/__main__.py @@ -1,25 +1,25 @@ import asyncio from importlib.metadata import version -from ocab_core import OCAB -from ocab_modules import module_loader +from karkas_core import Karkas +from karkas_blocks import block_loader async def main(): - ocab = OCAB() - await ocab.init_app( + karkas = Karkas() + await karkas.init_app( [ - module_loader("standard", "config", safe=False), - module_loader("standard", "command_helper"), + block_loader("standard", "config", safe=False), + block_loader("standard", "command_helper"), # safe=False из-за super().__init__() - module_loader("standard", "filters", safe=False), - module_loader("standard", "report"), - module_loader("standard", "welcome", safe=False), - module_loader("standard", "help"), + block_loader("standard", "filters", safe=False), + block_loader("standard", "report"), + block_loader("standard", "welcome", safe=False), + block_loader("standard", "help"), ], metainfo={"app_version": version("altlinux")}, ) - await ocab.start() + await karkas.start() asyncio.run(main()) diff --git a/src/altlinux/poetry.lock b/src/altlinux/poetry.lock index 5224dc3..69d1016 100644 --- a/src/altlinux/poetry.lock +++ b/src/altlinux/poetry.lock @@ -1210,7 +1210,7 @@ files = [ ] [[package]] -name = "ocab-core" +name = "karkas-core" version = "0.1.0" description = "" optional = false @@ -1232,10 +1232,10 @@ webhook = ["fastapi (>=0.111.1,<0.112.0)", "hypercorn (>=0.17.3,<0.18.0)"] [package.source] type = "directory" -url = "../ocab_core" +url = "../karkas_core" [[package]] -name = "ocab-modules" +name = "karkas-blocks" version = "0.1.0" description = "" optional = false @@ -1247,13 +1247,13 @@ develop = true dash = "^2.17.1" dash-bootstrap-components = "^1.6.0" dash-extensions = "^1.0.18" -ocab-core = {path = "../ocab_core", develop = true} +karkas-core = {path = "../karkas_core", develop = true} peewee = "^3.17.6" pyyaml = "^6.0.1" [package.source] type = "directory" -url = "../ocab_modules" +url = "../karkas_blocks" [[package]] name = "packaging" diff --git a/src/altlinux/pyproject.toml b/src/altlinux/pyproject.toml index 38e816d..e63ca9e 100644 --- a/src/altlinux/pyproject.toml +++ b/src/altlinux/pyproject.toml @@ -9,8 +9,8 @@ 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 } +karkas-core = { extras=["webhook"], path = "../karkas_core", develop = true } +karkas-blocks = { path = "../karkas_blocks", develop = true } [build-system] requires = ["poetry-core"] diff --git a/src/ocab_core/README.md b/src/ocab_core/README.md index 4589c5d..0737215 100644 --- a/src/ocab_core/README.md +++ b/src/ocab_core/README.md @@ -1,6 +1,6 @@ -# OCAB Core +# Karkas Core -Это ядро OCAB, содержащее базовые компоненты: +Это ядро Karkas, содержащее базовые компоненты: - Система управления модулями. - Логирование. diff --git a/src/ocab_core/ocab_core/__init__.py b/src/ocab_core/ocab_core/__init__.py index de586f8..3940848 100644 --- a/src/ocab_core/ocab_core/__init__.py +++ b/src/ocab_core/ocab_core/__init__.py @@ -1 +1 @@ -from .main import OCAB +from .main import Karkas diff --git a/src/ocab_core/ocab_core/logger.py b/src/ocab_core/ocab_core/logger.py index 3a56ff6..620de07 100644 --- a/src/ocab_core/ocab_core/logger.py +++ b/src/ocab_core/ocab_core/logger.py @@ -1,7 +1,7 @@ import logging import traceback -app_logger = logging.getLogger("ocab") +app_logger = logging.getLogger("karkas") log_level = logging.INFO diff --git a/src/ocab_core/ocab_core/main.py b/src/ocab_core/ocab_core/main.py index fb91365..95a8764 100644 --- a/src/ocab_core/ocab_core/main.py +++ b/src/ocab_core/ocab_core/main.py @@ -3,17 +3,17 @@ 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 +from karkas_core.lib import register_bot_webhook +from karkas_core.logger import CustomLogger, log, setup_logger +from karkas_core.modules_system import ModulesManager +from karkas_core.modules_system.public_api import get_module +from karkas_core.singleton import Singleton if TYPE_CHECKING: - from ocab_modules.standard.config import IConfig + from karkas_blocks.standard.config import IConfig -class OCAB: +class Karkas: def __init__(self) -> None: pass @@ -26,10 +26,10 @@ class OCAB: try: singleton.modules_manager = ModulesManager() - for module_loader in bot_modules: - info = module_loader.info() + for block_loader in bot_modules: + info = block_loader.info() log(f"Loading {info.name} ({info.id}) module") - await singleton.modules_manager.load(module_loader) + await singleton.modules_manager.load(block_loader) register_config() diff --git a/src/ocab_core/ocab_core/modules_system/loaders/fs_loader/FSLoader.py b/src/ocab_core/ocab_core/modules_system/loaders/fs_loader/FSLoader.py index 3a04dd9..a0030bc 100644 --- a/src/ocab_core/ocab_core/modules_system/loaders/fs_loader/FSLoader.py +++ b/src/ocab_core/ocab_core/modules_system/loaders/fs_loader/FSLoader.py @@ -3,9 +3,9 @@ from pathlib import Path 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.safe.policy import ( +# from karkas_core.logger import log +from karkas_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader +from karkas_core.modules_system.safe.policy import ( ALLOWED_IMPORTS, BUILTINS, RestrictedPythonPolicy, @@ -62,9 +62,9 @@ class FSLoader(UnsafeFSLoader): return file_path def _hook_import(self, name: str, *args, **kwargs): - if name == "ocab_core.modules_system.public_api": + if name == "karkas_core.modules_system.public_api": module = __import__(name, *args, **kwargs) - module.__ocab_module_id__ = self.module_id + module.__karkas_block_id__ = self.module_id return module for key in self.allowed_python_dependencies.keys(): @@ -78,7 +78,7 @@ class FSLoader(UnsafeFSLoader): module = types.ModuleType(name) module.__dict__.update( - {"__builtins__": self.builtins, "__ocab_module_id__": self.module_id} + {"__builtins__": self.builtins, "__karkas_block_id__": self.module_id} ) result = compile_restricted_exec(src, "", policy=RestrictedPythonPolicy) diff --git a/src/ocab_core/ocab_core/modules_system/loaders/unsafe_fs_loader/UnsafeFSLoader.py b/src/ocab_core/ocab_core/modules_system/loaders/unsafe_fs_loader/UnsafeFSLoader.py index d2ec974..37f790e 100644 --- a/src/ocab_core/ocab_core/modules_system/loaders/unsafe_fs_loader/UnsafeFSLoader.py +++ b/src/ocab_core/ocab_core/modules_system/loaders/unsafe_fs_loader/UnsafeFSLoader.py @@ -3,7 +3,7 @@ import os import sys from pathlib import Path -from ocab_core.modules_system.loaders.base import AbstractLoader, ModuleInfo +from karkas_core.modules_system.loaders.base import AbstractLoader, ModuleInfo class UnsafeFSLoader(AbstractLoader): diff --git a/src/ocab_core/ocab_core/modules_system/modules_manager.py b/src/ocab_core/ocab_core/modules_system/modules_manager.py index 390e826..e0ec9e6 100644 --- a/src/ocab_core/ocab_core/modules_system/modules_manager.py +++ b/src/ocab_core/ocab_core/modules_system/modules_manager.py @@ -4,7 +4,7 @@ import inspect import pkg_resources import semver -from ocab_core.modules_system.loaders.base import ( +from karkas_core.modules_system.loaders.base import ( AbstractLoader, DependencyInfo, ModuleInfo, diff --git a/src/ocab_core/ocab_core/modules_system/public_api/__init__.py b/src/ocab_core/ocab_core/modules_system/public_api/__init__.py index 866f4d6..8ead156 100644 --- a/src/ocab_core/ocab_core/modules_system/public_api/__init__.py +++ b/src/ocab_core/ocab_core/modules_system/public_api/__init__.py @@ -1,4 +1,4 @@ -from ocab_core.logger import log +from karkas_core.logger import log from .public_api import ( Storage, diff --git a/src/ocab_core/ocab_core/modules_system/public_api/public_api.py b/src/ocab_core/ocab_core/modules_system/public_api/public_api.py index e9ce931..53e6185 100644 --- a/src/ocab_core/ocab_core/modules_system/public_api/public_api.py +++ b/src/ocab_core/ocab_core/modules_system/public_api/public_api.py @@ -6,9 +6,9 @@ from aiogram import BaseMiddleware, Router from aiogram.fsm.context import FSMContext from aiogram.fsm.storage.base import StorageKey -# from ocab_core.logger import log -from ocab_core.modules_system.loaders.base import DependencyInfo -from ocab_core.singleton import Singleton +# from karkas_core.logger import log +from karkas_core.modules_system.loaders.base import DependencyInfo +from karkas_core.singleton import Singleton async def set_chat_menu_button(menu_button): @@ -64,8 +64,8 @@ def get_module( allowed_uses = None - if "__ocab_module_id__" in caller_globals: - caller_module_id = caller_globals["__ocab_module_id__"] + if "__karkas_block_id__" in caller_globals: + caller_module_id = caller_globals["__karkas_block_id__"] caller_module_info = app.modules_manager.get_info_by_id(caller_module_id) if caller_module_info and caller_module_info.dependencies: diff --git a/src/ocab_core/ocab_core/modules_system/safe/policy.py b/src/ocab_core/ocab_core/modules_system/safe/policy.py index d74fe6f..8dfc14b 100644 --- a/src/ocab_core/ocab_core/modules_system/safe/policy.py +++ b/src/ocab_core/ocab_core/modules_system/safe/policy.py @@ -17,8 +17,8 @@ from RestrictedPython.Guards import ( # guarded_setattr,; full_write_guard, safer_getattr, ) -from ocab_core.logger import log -from ocab_core.modules_system.safe.zope_guards import extra_safe_builtins +from karkas_core.logger import log +from karkas_core.modules_system.safe.zope_guards import extra_safe_builtins class RestrictedPythonPolicy(RestrictingNodeTransformer): diff --git a/src/ocab_core/ocab_core/modules_system/safe/zope_guards.py b/src/ocab_core/ocab_core/modules_system/safe/zope_guards.py index e5e6436..c6fcde6 100644 --- a/src/ocab_core/ocab_core/modules_system/safe/zope_guards.py +++ b/src/ocab_core/ocab_core/modules_system/safe/zope_guards.py @@ -1,6 +1,6 @@ ############################################################################# # -# Copyright (c) 2024 OCAB Team +# Copyright (c) 2024 Karkas Team # Copyright (c) 2002 Zope Foundation and Contributors. # # This software includes a function derived from the software subject to the diff --git a/src/ocab_core/ocab_core/singleton.py b/src/ocab_core/ocab_core/singleton.py index 228092c..d0db542 100644 --- a/src/ocab_core/ocab_core/singleton.py +++ b/src/ocab_core/ocab_core/singleton.py @@ -1,7 +1,7 @@ from aiogram import Bot, Dispatcher from aiogram.fsm.storage.memory import MemoryStorage -from ocab_core.modules_system import ModulesManager +from karkas_core.modules_system import ModulesManager class SingletonMeta(type): diff --git a/src/ocab_core/poetry.lock b/src/ocab_core/poetry.lock index 97e7f4e..41bc5aa 100644 --- a/src/ocab_core/poetry.lock +++ b/src/ocab_core/poetry.lock @@ -1210,7 +1210,7 @@ files = [ ] [[package]] -name = "ocab-modules" +name = "karkas-blocks" version = "0.1.0" description = "" optional = false @@ -1222,13 +1222,13 @@ develop = true dash = "^2.17.1" dash-bootstrap-components = "^1.6.0" dash-extensions = "^1.0.18" -ocab-core = {path = "../ocab_core", develop = true} +karkas-core = {path = "../karkas_core", develop = true} peewee = "^3.17.6" pyyaml = "^6.0.1" [package.source] type = "directory" -url = "../ocab_modules" +url = "../karkas_blocks" [[package]] name = "packaging" diff --git a/src/ocab_core/pyproject.toml b/src/ocab_core/pyproject.toml index ea1e87d..26a6621 100644 --- a/src/ocab_core/pyproject.toml +++ b/src/ocab_core/pyproject.toml @@ -1,5 +1,5 @@ [tool.poetry] -name = "ocab-core" +name = "karkas-core" version = "0.1.0" description = "" authors = ["Максим Слипенко "] @@ -16,7 +16,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 } +karkas-blocks = { path = "../karkas_blocks", develop = true } [tool.poetry.extras] webhook = ["fastapi", "hypercorn"] diff --git a/src/ocab_modules/README.md b/src/ocab_modules/README.md index e3e2d50..a9de353 100644 --- a/src/ocab_modules/README.md +++ b/src/ocab_modules/README.md @@ -1,12 +1,12 @@ -# OCAB Modules +# Karkas Blocks -OCAB Modules содержит набор модулей для платформы Open Chat AI Bot (OCAB). +Karkas Blocks содержит набор модулей для платформы Open Chat AI Bot (Karkas). ## Описание -OCAB - это платформа для создания чат-ботов Telegram. Модули - это расширения, которые добавляют функциональность ботам OCAB. +Karkas - это платформа для создания чат-ботов Telegram. Модули - это расширения, которые добавляют функциональность ботам Karkas. ## Типы модулей * **Стандартные модули (standard.*):** Предоставляют основные функции, такие как управление пользователями, ролями и настройками. -* **Дополнительные официальные модули (external.*):** Разработаны командой OCAB и предоставляют расширенные возможности, такие как интеграция с нейросетями, внешними сервисами и API. +* **Дополнительные официальные модули (external.*):** Разработаны командой Karkas и предоставляют расширенные возможности, такие как интеграция с нейросетями, внешними сервисами и API. diff --git a/src/ocab_modules/ocab_modules/__init__.py b/src/ocab_modules/ocab_modules/__init__.py index cf4a902..d143f8a 100644 --- a/src/ocab_modules/ocab_modules/__init__.py +++ b/src/ocab_modules/ocab_modules/__init__.py @@ -1 +1 @@ -from .lib import module_loader +from .lib import block_loader diff --git a/src/ocab_modules/ocab_modules/lib.py b/src/ocab_modules/ocab_modules/lib.py index 7f71cc2..af7bcdb 100644 --- a/src/ocab_modules/ocab_modules/lib.py +++ b/src/ocab_modules/ocab_modules/lib.py @@ -1,8 +1,8 @@ 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 +from karkas_core.modules_system.loaders.fs_loader import FSLoader +from karkas_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader def get_module_directory(module_name): @@ -15,11 +15,11 @@ def get_module_directory(module_name): return os.path.dirname(module_path) -ocab_modules_path = get_module_directory("ocab_modules") +karkas_blocks_path = get_module_directory("karkas_blocks") -def module_loader(namespace: str, module_name: str, safe=True): +def block_loader(namespace: str, module_name: str, safe=True): if not safe: - return UnsafeFSLoader(f"{ocab_modules_path}/{namespace}/{module_name}") + return UnsafeFSLoader(f"{karkas_blocks_path}/{namespace}/{module_name}") else: - return FSLoader(f"{ocab_modules_path}/{namespace}/{module_name}") + return FSLoader(f"{karkas_blocks_path}/{namespace}/{module_name}") diff --git a/src/ocab_modules/ocab_modules/standard/admin/handlers.py b/src/ocab_modules/ocab_modules/standard/admin/handlers.py index 9440eda..368cb2b 100644 --- a/src/ocab_modules/ocab_modules/standard/admin/handlers.py +++ b/src/ocab_modules/ocab_modules/standard/admin/handlers.py @@ -4,10 +4,10 @@ from typing import TYPE_CHECKING from aiogram import Bot from aiogram.types import Message -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module if TYPE_CHECKING: - from ocab_modules.standard.config import IConfig + from karkas_blocks.standard.config import IConfig config: "IConfig" = get_module("standard.config", "config") diff --git a/src/ocab_modules/ocab_modules/standard/admin/info.json b/src/ocab_modules/ocab_modules/standard/admin/info.json index a3eae7a..fd54142 100644 --- a/src/ocab_modules/ocab_modules/standard/admin/info.json +++ b/src/ocab_modules/ocab_modules/standard/admin/info.json @@ -2,7 +2,7 @@ "id": "standard.admin", "name": "Admin", "description": "Модуль для работы с админкой", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": false, "dependencies": { diff --git a/src/ocab_modules/ocab_modules/standard/admin/main.py b/src/ocab_modules/ocab_modules/standard/admin/main.py index 0dffedb..1f67729 100644 --- a/src/ocab_modules/ocab_modules/standard/admin/main.py +++ b/src/ocab_modules/ocab_modules/standard/admin/main.py @@ -1,4 +1,4 @@ -from ocab_core.modules_system.public_api import register_router +from karkas_core.modules_system.public_api import register_router from .routers import router diff --git a/src/ocab_modules/ocab_modules/standard/admin/routers.py b/src/ocab_modules/ocab_modules/standard/admin/routers.py index b2dc7a5..326de75 100644 --- a/src/ocab_modules/ocab_modules/standard/admin/routers.py +++ b/src/ocab_modules/ocab_modules/standard/admin/routers.py @@ -2,7 +2,7 @@ from aiogram import F, Router from aiogram.filters import Command -from ocab_core.modules_system.public_api import get_module, log +from karkas_core.modules_system.public_api import get_module, log from .handlers import ( chat_not_in_approve_list, diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/README.md b/src/ocab_modules/ocab_modules/standard/command_helper/README.md index afb3deb..97a614f 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/README.md +++ b/src/ocab_modules/ocab_modules/standard/command_helper/README.md @@ -16,7 +16,7 @@ ## Пример ```python -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module register_command = get_module("standard.command_helper", "register_command") diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/info.json b/src/ocab_modules/ocab_modules/standard/command_helper/info.json index 00a14dc..8d41e24 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/info.json +++ b/src/ocab_modules/ocab_modules/standard/command_helper/info.json @@ -2,7 +2,7 @@ "id": "standard.command_helper", "name": "Command helper", "description": "Модуль для отображения команд при вводе '/'", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": false, "dependencies": {} diff --git a/src/ocab_modules/ocab_modules/standard/command_helper/main.py b/src/ocab_modules/ocab_modules/standard/command_helper/main.py index 9fcb5f9..91d0209 100644 --- a/src/ocab_modules/ocab_modules/standard/command_helper/main.py +++ b/src/ocab_modules/ocab_modules/standard/command_helper/main.py @@ -1,6 +1,6 @@ from aiogram.types import BotCommand -from ocab_core.modules_system.public_api import set_my_commands +from karkas_core.modules_system.public_api import set_my_commands commands = dict() diff --git a/src/ocab_modules/ocab_modules/standard/config/README.md b/src/ocab_modules/ocab_modules/standard/config/README.md index 784757b..9094efe 100644 --- a/src/ocab_modules/ocab_modules/standard/config/README.md +++ b/src/ocab_modules/ocab_modules/standard/config/README.md @@ -18,7 +18,7 @@ ## Пример ```python -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module config = get_module("standard.config", "config") diff --git a/src/ocab_modules/ocab_modules/standard/config/config_manager.py b/src/ocab_modules/ocab_modules/standard/config/config_manager.py index 1c61a39..d8951ab 100644 --- a/src/ocab_modules/ocab_modules/standard/config/config_manager.py +++ b/src/ocab_modules/ocab_modules/standard/config/config_manager.py @@ -66,7 +66,7 @@ class ConfigManager: 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__") + module_id = caller_globals.get("__karkas_block_id__") return module_id def mass_set(self, updates: Dict[str, Any]): diff --git a/src/ocab_modules/ocab_modules/standard/config/info.json b/src/ocab_modules/ocab_modules/standard/config/info.json index 9d6b7ef..e9e7b2c 100644 --- a/src/ocab_modules/ocab_modules/standard/config/info.json +++ b/src/ocab_modules/ocab_modules/standard/config/info.json @@ -2,7 +2,7 @@ "id": "standard.config", "name": "Config YAML", "description": "Модуль для работы с конфигурационным файлом бота (YAML)", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": true, "dependencies": { diff --git a/src/ocab_modules/ocab_modules/standard/config/main.py b/src/ocab_modules/ocab_modules/standard/config/main.py index 89096a0..8f1b835 100644 --- a/src/ocab_modules/ocab_modules/standard/config/main.py +++ b/src/ocab_modules/ocab_modules/standard/config/main.py @@ -1,4 +1,4 @@ -from ocab_core.modules_system.public_api import get_module, log +from karkas_core.modules_system.public_api import get_module, log from .config import config from .miniapp_ui import get_miniapp_blueprint diff --git a/src/ocab_modules/ocab_modules/standard/config/miniapp_ui.py b/src/ocab_modules/ocab_modules/standard/config/miniapp_ui.py index cd6fabd..799be60 100644 --- a/src/ocab_modules/ocab_modules/standard/config/miniapp_ui.py +++ b/src/ocab_modules/ocab_modules/standard/config/miniapp_ui.py @@ -12,10 +12,10 @@ try: except ImportError: DASH_AVAILABLE = False -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module if TYPE_CHECKING: - from ocab_modules.standard.roles import Roles as IRoles + from karkas_blocks.standard.roles import Roles as IRoles def create_control(key: str, config: ConfigManager): diff --git a/src/ocab_modules/ocab_modules/standard/config/tests/test_config.py b/src/ocab_modules/ocab_modules/standard/config/tests/test_config.py index cf17556..d704201 100644 --- a/src/ocab_modules/ocab_modules/standard/config/tests/test_config.py +++ b/src/ocab_modules/ocab_modules/standard/config/tests/test_config.py @@ -1,6 +1,6 @@ import unittest -from src.ocab_modules.standard.config.config import get_config +from src.karkas_blocks.standard.config.config import get_config yaml_load = get_config(is_test=True) diff --git a/src/ocab_modules/ocab_modules/standard/database/README.md b/src/ocab_modules/ocab_modules/standard/database/README.md index 769e793..6553172 100644 --- a/src/ocab_modules/ocab_modules/standard/database/README.md +++ b/src/ocab_modules/ocab_modules/standard/database/README.md @@ -1,6 +1,6 @@ ## Модуль DataBase -Модуль DataBase предназначен для ведения и работы с базами данных OCAB. +Модуль DataBase предназначен для ведения и работы с базами данных Karkas. Модуль содержит в себе следующие таблицы: diff --git a/src/ocab_modules/ocab_modules/standard/database/db_api.py b/src/ocab_modules/ocab_modules/standard/database/db_api.py index 855a673..fca29b3 100644 --- a/src/ocab_modules/ocab_modules/standard/database/db_api.py +++ b/src/ocab_modules/ocab_modules/standard/database/db_api.py @@ -16,12 +16,12 @@ def connect_database(is_test: bool = False, module: str | None = None): raise NotExpectedModuleName() db_path = "database" - database = pw.SqliteDatabase(f"{db_path}/OCAB.db") + database = pw.SqliteDatabase(f"{db_path}/Karkas.db") database_proxy.initialize(database) database.connect() create_tables(database) - return database, f"{db_path}/OCAB.db" + return database, f"{db_path}/Karkas.db" def create_tables(db: pw.SqliteDatabase): diff --git a/src/ocab_modules/ocab_modules/standard/database/info.json b/src/ocab_modules/ocab_modules/standard/database/info.json index 1a5060e..3534496 100644 --- a/src/ocab_modules/ocab_modules/standard/database/info.json +++ b/src/ocab_modules/ocab_modules/standard/database/info.json @@ -2,7 +2,7 @@ "id": "standard.database", "name": "Database", "description": "Модуль для работы с БД", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": true, "dependencies": {} diff --git a/src/ocab_modules/ocab_modules/standard/filters/README.md b/src/ocab_modules/ocab_modules/standard/filters/README.md index 2166390..1cc0a49 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/README.md +++ b/src/ocab_modules/ocab_modules/standard/filters/README.md @@ -16,7 +16,7 @@ ```python from aiogram import Router -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module ChatModerOrAdminFilter = get_module("standard.filters", "ChatModerOrAdminFilter") diff --git a/src/ocab_modules/ocab_modules/standard/filters/filters.py b/src/ocab_modules/ocab_modules/standard/filters/filters.py index 4370baf..dfe98bd 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/filters.py +++ b/src/ocab_modules/ocab_modules/standard/filters/filters.py @@ -5,11 +5,11 @@ from aiogram.filters import BaseFilter from aiogram.types import Message from typing_extensions import deprecated -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module if TYPE_CHECKING: - from ocab_modules.standard.config import IConfig - from ocab_modules.standard.roles import Roles as IRoles + from karkas_blocks.standard.config import IConfig + from karkas_blocks.standard.roles import Roles as IRoles config: "IConfig" = get_module("standard.config", "config") diff --git a/src/ocab_modules/ocab_modules/standard/filters/info.json b/src/ocab_modules/ocab_modules/standard/filters/info.json index 9554bea..aabb3fe 100644 --- a/src/ocab_modules/ocab_modules/standard/filters/info.json +++ b/src/ocab_modules/ocab_modules/standard/filters/info.json @@ -2,7 +2,7 @@ "id": "standard.filters", "name": "Filters", "description": "Модуль с фильтрами", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": true, "dependencies": { diff --git a/src/ocab_modules/ocab_modules/standard/fsm_database_storage/fsm.py b/src/ocab_modules/ocab_modules/standard/fsm_database_storage/fsm.py index 4b71145..1716158 100644 --- a/src/ocab_modules/ocab_modules/standard/fsm_database_storage/fsm.py +++ b/src/ocab_modules/ocab_modules/standard/fsm_database_storage/fsm.py @@ -4,11 +4,11 @@ from typing import TYPE_CHECKING, Any, Dict, Optional from aiogram.fsm.state import State from aiogram.fsm.storage.base import BaseStorage, StorageKey -from ocab_core.modules_system.public_api import get_module, log -from ocab_core.modules_system.public_api.public_api import set_fsm +from karkas_core.modules_system.public_api import get_module, log +from karkas_core.modules_system.public_api.public_api import set_fsm if TYPE_CHECKING: - from ocab_modules.standard.database.repositories import ( + from karkas_blocks.standard.database.repositories import ( FSMDataRepository as IFSMDataRepository, ) diff --git a/src/ocab_modules/ocab_modules/standard/fsm_database_storage/info.json b/src/ocab_modules/ocab_modules/standard/fsm_database_storage/info.json index 58c05b4..1302a34 100644 --- a/src/ocab_modules/ocab_modules/standard/fsm_database_storage/info.json +++ b/src/ocab_modules/ocab_modules/standard/fsm_database_storage/info.json @@ -2,7 +2,7 @@ "id": "standard.fsm_database_storage", "name": "FSM Database Storage", "description": "Очень полезный модуль", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": false, "dependencies": { diff --git a/src/ocab_modules/ocab_modules/standard/help/info.json b/src/ocab_modules/ocab_modules/standard/help/info.json index 30cbbe6..75df4ed 100644 --- a/src/ocab_modules/ocab_modules/standard/help/info.json +++ b/src/ocab_modules/ocab_modules/standard/help/info.json @@ -1,21 +1,21 @@ { - "id": "standard.help", - "name": "Help", - "description": "Модуль для вывода /help сообщения", - "author": "OCAB Team", - "version": "1.0.0", - "privileged": false, - "dependencies": { - "required": { - "standard.config": "^1.0.0" - }, - "optional": { - "standard.command_helper": "^1.0.0" - } + "id": "standard.help", + "name": "Help", + "description": "Модуль для вывода /help сообщения", + "author": "Karkas Team", + "version": "1.0.0", + "privileged": false, + "dependencies": { + "required": { + "standard.config": "^1.0.0" }, - "pythonDependencies": { - "required": { - "string": "*" - } + "optional": { + "standard.command_helper": "^1.0.0" } + }, + "pythonDependencies": { + "required": { + "string": "*" + } + } } diff --git a/src/ocab_modules/ocab_modules/standard/help/main.py b/src/ocab_modules/ocab_modules/standard/help/main.py index 6dedb83..a5e1de0 100644 --- a/src/ocab_modules/ocab_modules/standard/help/main.py +++ b/src/ocab_modules/ocab_modules/standard/help/main.py @@ -5,14 +5,14 @@ from aiogram import Router from aiogram.filters import Command from aiogram.types import Message -from ocab_core.modules_system.public_api import ( +from karkas_core.modules_system.public_api import ( get_metainfo, get_module, register_router, ) if TYPE_CHECKING: - from ocab_modules.standard.config import IConfig + from karkas_blocks.standard.config import IConfig config: "IConfig" = get_module("standard.config", "config") diff --git a/src/ocab_modules/ocab_modules/standard/info/handlers.py b/src/ocab_modules/ocab_modules/standard/info/handlers.py index eb369c9..8c18816 100644 --- a/src/ocab_modules/ocab_modules/standard/info/handlers.py +++ b/src/ocab_modules/ocab_modules/standard/info/handlers.py @@ -5,11 +5,11 @@ from typing import TYPE_CHECKING from aiogram import Bot from aiogram.types import Message -from ocab_core.modules_system.public_api import get_module, log +from karkas_core.modules_system.public_api import get_module, log if TYPE_CHECKING: - from ocab_modules.standard.database import db_api as IDbApi - from ocab_modules.standard.roles import Roles as IRoles + from karkas_blocks.standard.database import db_api as IDbApi + from karkas_blocks.standard.roles import Roles as IRoles db_api: "IDbApi" = get_module( "standard.database", diff --git a/src/ocab_modules/ocab_modules/standard/info/info.json b/src/ocab_modules/ocab_modules/standard/info/info.json index 3a37f73..454f1c7 100644 --- a/src/ocab_modules/ocab_modules/standard/info/info.json +++ b/src/ocab_modules/ocab_modules/standard/info/info.json @@ -2,7 +2,7 @@ "id": "standard.info", "name": "Info", "description": "Модуль с информацией", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": false, "dependencies": { diff --git a/src/ocab_modules/ocab_modules/standard/info/main.py b/src/ocab_modules/ocab_modules/standard/info/main.py index 8893a44..4756851 100644 --- a/src/ocab_modules/ocab_modules/standard/info/main.py +++ b/src/ocab_modules/ocab_modules/standard/info/main.py @@ -1,7 +1,7 @@ from aiogram import Router from aiogram.filters import Command -from ocab_core.modules_system.public_api import get_module, register_router +from karkas_core.modules_system.public_api import get_module, register_router from .handlers import get_chat_info, get_user_info diff --git a/src/ocab_modules/ocab_modules/standard/message_processing/info.json b/src/ocab_modules/ocab_modules/standard/message_processing/info.json index 8fbeb1a..6c72bed 100644 --- a/src/ocab_modules/ocab_modules/standard/message_processing/info.json +++ b/src/ocab_modules/ocab_modules/standard/message_processing/info.json @@ -2,7 +2,7 @@ "id": "standard.message_processing", "name": "Info", "description": "Модуль с информацией", - "author": "OCAB Team", + "author": "Karkas Team", "version": "1.0.0", "privileged": false, "dependencies": { diff --git a/src/ocab_modules/ocab_modules/standard/message_processing/message_api.py b/src/ocab_modules/ocab_modules/standard/message_processing/message_api.py index 834bbc5..496f454 100644 --- a/src/ocab_modules/ocab_modules/standard/message_processing/message_api.py +++ b/src/ocab_modules/ocab_modules/standard/message_processing/message_api.py @@ -4,10 +4,10 @@ from typing import TYPE_CHECKING from aiogram import Bot, F, Router, types -from ocab_core.modules_system.public_api import get_module, log, register_router +from karkas_core.modules_system.public_api import get_module, log, register_router if TYPE_CHECKING: - from ocab_modules.standard.config import IConfig + from karkas_blocks.standard.config import IConfig config: "IConfig" = get_module("standard.config", "config") diff --git a/src/ocab_modules/ocab_modules/standard/miniapp/README.md b/src/ocab_modules/ocab_modules/standard/miniapp/README.md index 5d47f17..0fd1008 100644 --- a/src/ocab_modules/ocab_modules/standard/miniapp/README.md +++ b/src/ocab_modules/ocab_modules/standard/miniapp/README.md @@ -15,7 +15,7 @@ ## Пример ```python -from ocab_core.modules_system.public_api import get_module +from karkas_core.modules_system.public_api import get_module register_page = get_module("standard.miniapp", "register_page") diff --git a/src/ocab_modules/ocab_modules/standard/miniapp/dash_telegram_auth.py b/src/ocab_modules/ocab_modules/standard/miniapp/dash_telegram_auth.py index 5137770..2d5a928 100644 --- a/src/ocab_modules/ocab_modules/standard/miniapp/dash_telegram_auth.py +++ b/src/ocab_modules/ocab_modules/standard/miniapp/dash_telegram_auth.py @@ -12,7 +12,7 @@ WEBAPP_LOADER_TEMPLATE = """ - OCAB + Karkas