diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..a5aaed3b4d792a623e6b054770db6468d411964b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,146 @@ +# Local app configuration +.gen.env +.env +# Ide shit +.idea/* +.vscode/ +# Session shit +bot_session.session + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000000000000000000000000000000000..7106d7b454ffe6d6baa97270a2675b7de9e23192 --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +[flake8] +max-complexity = 6 +inline-quotes = double +max-line-length = 88 +extend-ignore = E203 +docstring_style=sphinx diff --git a/.gitignore b/.gitignore index 9727cab8a4faa74f0437ab58be92e44dc97f9105..a5aaed3b4d792a623e6b054770db6468d411964b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Local app configuration +.gen.env .env # Ide shit .idea/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1837ac4516c3fb9cfdf4f3d120f03bc6e6104c2c..975f37b1c7c0210904a8a9c63153c22e9cce7da4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,14 +1,37 @@ stages: + - tools - test - cleanup_tests + - build - deploy -test: +build_test: + stage: tools + tags: + - bots-deployer + script: + - make build-test + +flake8: + stage: test + tags: + - bots-deployer + script: + - make flake8 + +pytest: stage: test tags: - bots-deployer script: - - make test + - make pytest + +black: + stage: test + tags: + - bots-deployer + script: + - make black cleanup_tests: stage: cleanup_tests @@ -16,16 +39,25 @@ cleanup_tests: - bots-deployer when: always script: - - make clean_test + - make clear-test + +build: + stage: build + when: manual + tags: + - bots-deployer + script: + - make build push deploy: stage: deploy - only: ['master'] + only: + - master + - tags environment: name: production - url: https://s3_bot.le-memese.com/ - + url: https://${BOT_HOST}/ tags: - bots-deployer script: - - sh deploy.sh + - make deploy-prod diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7b45badf4f53acfc8fd5fce5319a8d950a747499..7f5557645daaa00e085e92119edd716e650eb15a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,33 +1,32 @@ repos: - - repo: https://github.com/timothycrosley/isort - rev: 4.3.21 - hooks: - - id: isort - exclude: > - (?x)^( - alembic/.+| - systemd/.+ - )$ - - repo: https://github.com/ambv/black - rev: 19.10b0 - hooks: - - id: black - - repo: https://github.com/IamTheFij/docker-pre-commit - rev: v2.0.0 - hooks: - - id: docker-compose-check - - id: hadolint + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: check-ast - - id: requirements-txt-fixer - id: trailing-whitespace + + - repo: local + hooks: + - id: isort + name: isort + language: system + types: [python] + entry: isort + - id: flake8 name: flake8 + language: system entry: flake8 - exclude: > - (?x)^( - alembic/.+| - systemd/.+ - )$ + pass_filenames: false + types: [ python ] + args: + - --count + - . + + - id: pytest + name: pytest + language: system + entry: pytest + pass_filenames: false + types: [ python ] diff --git a/Dockerfiles/Dockerfile b/Dockerfiles/Dockerfile deleted file mode 100644 index a25926ccd8ccfbf38123bd0850ece4c49b94c888..0000000000000000000000000000000000000000 --- a/Dockerfiles/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.8 - -# Installing requirements -COPY requirements/requirements.base.txt /tmp/ -RUN pip install --no-cache-dir -r /tmp/requirements.base.txt - -# Copying actuall application -COPY src/ /app/src -COPY main.py /app/main.py -COPY static_messages/ /app/static_messages - -WORKDIR /app - -CMD ["python", "main.py"] diff --git a/Dockerfiles/test.Dockerfile b/Dockerfiles/test.Dockerfile deleted file mode 100644 index e7c28c343b31fd3ad5697a81741de8b6d58c915a..0000000000000000000000000000000000000000 --- a/Dockerfiles/test.Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM hadolint/hadolint:v1.18.0 as docker_linter - -FROM python:3.8 - -RUN apt-get update -y \ - && apt-get install -y --no-install-recommends \ - make=4.2.1-1.2 \ - sed=4.7-1 \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -COPY --from=docker_linter /bin/hadolint /bin/ -RUN hadolint -v -# Installing requirements -COPY requirements/ /reqs -RUN pip install --no-cache-dir -r /reqs/requirements.dev.txt - -# Copying actuall application -COPY . /app - -WORKDIR /app - -RUN sed -i 's/hadolint/hadolint-system/g' .pre-commit-config.yaml diff --git a/Makefile b/Makefile index b661a71655fa4e17851f4faf7e95d9b514fdbe63..076d1716d57bde3ef7cab0c3ef489117ba7b5d47 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,79 @@ -prod: - docker-compose -f docker-compose.yml up --build +.DEFAULT_GOAL := help -clean_prod: - docker-compose -f docker-compose.yml down +.PHONY: help +help: ## Show help + @grep -E '^[\.a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ + | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' -test: - docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from test_bot_service +.PHONY: env_file +env_file: ## Generate .gen.env file from env with "BOT_" prefix. + touch .gen.env && env | grep -E '^BOT_' > ".gen.env" || echo "Ðет переменных Ñреды" + test -f .env && cat .env > .gen.env || echo "Файл .env не найден" -clean_test: - docker-compose -f docker-compose.test.yml down -v +.PHONY: build +build: env_file ## Build docker container image. + docker-compose \ + -f ./deploy/docker-compose.yml \ + --project-directory . \ + build --pull bot_service -_test: - cp .env.example .env - pre-commit run -a || exit 1 - pytest +.PHONY: build_test +build-test: ## Build image for tests. + docker-compose \ + -f ./deploy/docker-compose.test.yml \ + --project-directory . \ + build --no-cache test_bot_service + +.PHONY: flake8 +flake8: ## Run flake8 check + docker-compose \ + -f ./deploy/docker-compose.test.yml \ + --project-directory . \ + run test_bot_service flake8 --count . + +.PHONY: black +black: ## Run black check + docker-compose \ + -f ./deploy/docker-compose.test.yml \ + --project-directory . \ + run test_bot_service black --check . + +.PHONY: pytest +pytest: ## Run pytest tests + docker-compose \ + -f ./deploy/docker-compose.test.yml \ + --project-directory . \ + run test_bot_service pytest -v --cov=bot_s3rius + +.PHONY: push +push: env_file ## Push container to the registry. + docker-compose \ + -f ./deploy/docker-compose.yml \ + --project-directory . \ + push bot_service + +.PHONY: pull +pull: env_file ## Download images from docker hub. + docker-compose \ + -f deploy/docker-compose.yml \ + --project-directory . \ + pull --ignore-pull-failures bot_service \ + || \ + docker-compose \ + -f deploy/docker-compose.yml \ + --project-directory . \ + pull bot_service + +.PHONY: deploy-prod +deploy-prod: pull ## deploy container in production. + docker-compose \ + -f ./deploy/docker-compose.yml \ + --project-directory . \ + up -d + +.PHONY: clear-test +clear-test: ## Remove containers and images for test + docker-compose \ + -f ./deploy/docker-compose.test.yml \ + --project-directory . \ + down --rmi=all diff --git a/README.md b/README.md index ce7ef57d4601c186700d3f37f87e921926768129..a1877edf76babbd1b5d09773f63cf36eb6c194c5 100644 --- a/README.md +++ b/README.md @@ -44,15 +44,3 @@ Clone this repo to your gitlab. - LIBRARIES_IO_API_TOKEN * Don't forget to declare a global network on your server like memes_network in [docker-compose.yml](./docker-compose.yml). * Add access to your container from the network for token submission. - -## How to contribute -First of all install docker and python -Then run the following: -```bash -virtualenv venv -source venv/bin/activate -pip install -r requirements/requirements.dev.txt -pre-commit install -``` -Then you can do changes. -For testing you can use `make test`. diff --git a/src/actions/__init__.py b/bot_s3rius/actions/__init__.py similarity index 100% rename from src/actions/__init__.py rename to bot_s3rius/actions/__init__.py diff --git a/src/actions/basic.py b/bot_s3rius/actions/basic.py similarity index 81% rename from src/actions/basic.py rename to bot_s3rius/actions/basic.py index c9fe005133a79ea314153be9aee0d11566131a68..c69cba715c5a0c8903838d55a4fcaefe540284d5 100644 --- a/src/actions/basic.py +++ b/bot_s3rius/actions/basic.py @@ -2,25 +2,18 @@ import logging from datetime import datetime import pytz -from src.config import config -from src.utils.responses import mark_unread from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.responses import mark_unread + logger = logging.getLogger(__name__) @config.telegram_client.on(events.NewMessage(pattern=r"^\.h$")) @mark_unread async def show_help(event): - with open("./static_messages/help.txt") as f: - contents = f.read() - await event.respond(contents) - - -@config.telegram_client.on(events.NewMessage(pattern=r"^\.ci$")) -@mark_unread -async def ci(event): - with open("./static_messages/app.info") as f: + with open(config.project_dir / "static_messages/help.txt") as f: contents = f.read() await event.respond(contents) diff --git a/src/actions/converters/__init__.py b/bot_s3rius/actions/converters/__init__.py similarity index 100% rename from src/actions/converters/__init__.py rename to bot_s3rius/actions/converters/__init__.py diff --git a/src/actions/converters/crypto_currency.py b/bot_s3rius/actions/converters/crypto_currency.py similarity index 95% rename from src/actions/converters/crypto_currency.py rename to bot_s3rius/actions/converters/crypto_currency.py index f8ac8eb308d707a32bba20bca83960c5cfd90492..36eee365c7996ac2fc70e7e9aa7a4ee20dedbee0 100644 --- a/src/actions/converters/crypto_currency.py +++ b/bot_s3rius/actions/converters/crypto_currency.py @@ -4,11 +4,12 @@ import urllib.parse from decimal import Decimal import httpx -from src.config import config -from src.utils.converters import get_info_from_group -from src.utils.responses import mark_unread from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.converters import get_info_from_group +from bot_s3rius.utils.responses import mark_unread + logger = logging.getLogger(__name__) TARGET_CURRENCY = "rub" diff --git a/src/actions/converters/currency.py b/bot_s3rius/actions/converters/currency.py similarity index 95% rename from src/actions/converters/currency.py rename to bot_s3rius/actions/converters/currency.py index b3b12aabe7006ab77661601495d8e8bf31be7259..6e190ae16bf1958a03e86b0b491d2372a2367c36 100644 --- a/src/actions/converters/currency.py +++ b/bot_s3rius/actions/converters/currency.py @@ -3,11 +3,12 @@ import re from decimal import Decimal import httpx -from src.config import config -from src.utils.converters import get_info_from_group -from src.utils.responses import mark_unread from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.converters import get_info_from_group +from bot_s3rius.utils.responses import mark_unread + logger = logging.getLogger(__name__) CURRENCY_MAPPING = { diff --git a/src/actions/fun.py b/bot_s3rius/actions/fun.py similarity index 97% rename from src/actions/fun.py rename to bot_s3rius/actions/fun.py index 440ab14e2f3ba55169cf977641c08ef86c6a9e33..af4df49ec48e114a865a21a37fa997719e327ce6 100644 --- a/src/actions/fun.py +++ b/bot_s3rius/actions/fun.py @@ -5,11 +5,12 @@ import re from datetime import datetime import httpx -from src.config import config -from src.utils.responses import danger_message, mark_unread -from src.utils.str_helpers import Rotor from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.responses import danger_message, mark_unread +from bot_s3rius.utils.str_helpers import Rotor + logger = logging.getLogger(__name__) swearing = [ "[Ии]ди нахуй", diff --git a/src/actions/package_indexes.py b/bot_s3rius/actions/package_indexes.py similarity index 95% rename from src/actions/package_indexes.py rename to bot_s3rius/actions/package_indexes.py index fe47063fc52f2c6f96f5d6d82c23290f384ce5b0..5961afefec694236484a7226ef059b4c7adeca84 100644 --- a/src/actions/package_indexes.py +++ b/bot_s3rius/actions/package_indexes.py @@ -3,11 +3,12 @@ from dataclasses import dataclass from typing import Union import httpx -from src.config import config -from src.utils.library_package import get_library_info, render_package_info -from src.utils.responses import failed_search_answer, mark_unread from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.library_package import get_library_info, render_package_info +from bot_s3rius.utils.responses import failed_search_answer, mark_unread + logger = logging.getLogger(__name__) diff --git a/src/actions/replies.py b/bot_s3rius/actions/replies.py similarity index 93% rename from src/actions/replies.py rename to bot_s3rius/actions/replies.py index a834cf1b61f358f8e4cfc65b0bbade97a7301191..dbb8ebbbb7bdf1e17f208802d1738434f0171de1 100644 --- a/src/actions/replies.py +++ b/bot_s3rius/actions/replies.py @@ -2,10 +2,11 @@ import logging import random import re -from src.config import config -from src.utils.responses import check_if_only_smiles, danger_message, mark_unread from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.responses import check_if_only_smiles, danger_message, mark_unread + logger = logging.getLogger(__name__) diff --git a/src/actions/search_engines.py b/bot_s3rius/actions/search_engines.py similarity index 91% rename from src/actions/search_engines.py rename to bot_s3rius/actions/search_engines.py index 1bf7d32a9e99834bfb1a99728ce8358dd2622c10..ca7d1c36a6bda06773d689c609e013a6a2830021 100644 --- a/src/actions/search_engines.py +++ b/bot_s3rius/actions/search_engines.py @@ -2,17 +2,18 @@ import logging from urllib.parse import urlencode import httpx -from src.config import config -from src.utils.responses import failed_search_answer, mark_unread, thinking from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.responses import failed_search_answer, mark_unread, thinking + logger = logging.getLogger(__name__) @config.telegram_client.on(events.NewMessage(pattern=r"^\.i (.*)", forwards=False)) @mark_unread @thinking -async def search_images(event: events.NewMessage.Event): +async def search_images(event: events.NewMessage.Event): # noqa: C901 query_str = event.pattern_match.group(1).strip() params = { "count": "30", diff --git a/src/actions/speller.py b/bot_s3rius/actions/speller.py similarity index 91% rename from src/actions/speller.py rename to bot_s3rius/actions/speller.py index de6184ce04a2189022eebf1dfbc7927bac3646b6..3243cb4d1c87e2876472068e341351c32fc9fff9 100644 --- a/src/actions/speller.py +++ b/bot_s3rius/actions/speller.py @@ -2,11 +2,12 @@ import asyncio import re from datetime import datetime -from src.config import config -from src.utils.responses import mark_unread -from src.utils.str_helpers import Rotor, replace_by_index from telethon import events +from bot_s3rius.config import config +from bot_s3rius.utils.responses import mark_unread +from bot_s3rius.utils.str_helpers import Rotor, replace_by_index + rotatable_swearing = ["[Бб]лÑ", "[СÑ]ука", "[Ии]ди нахуй", "[Eе]бать", "[Оо]чко"] rotatable_pattern = f"({'|'.join(rotatable_swearing)})" diff --git a/bot_s3rius/config.py b/bot_s3rius/config.py new file mode 100644 index 0000000000000000000000000000000000000000..417c058a87e3314eed90e3dec1307bc868000718 --- /dev/null +++ b/bot_s3rius/config.py @@ -0,0 +1,31 @@ +from pathlib import Path +from typing import List + +from pydantic import BaseSettings +from pydantic.fields import Field +from telethon import TelegramClient + +__all__ = ["config"] + + +class Config(BaseSettings): + telegram_app_id: str = Field(None, env="BOT_TELEGRAM_APP_ID", required=True) + telegram_api_hash: str = Field(None, env="BOT_TELEGRAM_API_HASH", required=True) + libraries_io_token: str = Field( + None, env="BOT_LIBRARIES_IO_API_TOKEN", required=True + ) + telegram_account_phone: str = Field( + None, env="BOT_TELEGRAM_ACCOUNT_PHONE", required=True + ) + app_mode: str = Field(name="app_mode", default="dev", env="BOT_APP_MODE") + debug_mode: bool = False + flask_port: str = Field(name="flask_port", default="8080", env="BOT_FLASK_PORT") + excluded_chats: List[str] = Field([], env="BOT_EXCLUDED_CHATS") + telegram_client: TelegramClient = None + + @property + def project_dir(self) -> Path: + return Path(__file__).parent + + +config = Config() diff --git a/src/initializator.py b/bot_s3rius/initializator.py similarity index 84% rename from src/initializator.py rename to bot_s3rius/initializator.py index 9f04cb172cb07b6749fde75a2e590bad1d85dd60..8f49c73f947f8979b462a7d6fd0511b13856b1dd 100644 --- a/src/initializator.py +++ b/bot_s3rius/initializator.py @@ -2,10 +2,11 @@ import asyncio import logging from multiprocessing import Manager, Process -from src.config import config -from src.server_app import create_web_app from telethon import TelegramClient +from bot_s3rius.config import config +from bot_s3rius.server_app import create_web_app + logger = logging.getLogger(__name__) @@ -40,8 +41,13 @@ def init(): phone=config.telegram_account_phone, code_callback=get_code_from_web(token) ) config.telegram_client = client - from src.actions import finish + from bot_s3rius.actions import finish finish() return client + + +def main(): + client = init() + client.run_until_disconnected() diff --git a/src/server_app.py b/bot_s3rius/server_app.py similarity index 88% rename from src/server_app.py rename to bot_s3rius/server_app.py index 6d447234bef2209746a917163f6ec7cf68a78776..00456d48683ec908abb1499791829e7263dd1fb7 100644 --- a/src/server_app.py +++ b/bot_s3rius/server_app.py @@ -3,7 +3,8 @@ import random import uuid from flask import Flask, current_app, render_template, request, send_file -from src.config import config + +from bot_s3rius.config import config logger = logging.getLogger(__name__) @@ -15,7 +16,9 @@ def form_template(): def girl_image(): num = random.randint(1, 3) - return send_file(f"./templates/static/girl_{num}.png", mimetype="image/png") + return send_file( + config.project_dir / f"templates/static/girl_{num}.png", mimetype="image/png", + ) def get_code(): diff --git a/static_messages/help.txt b/bot_s3rius/static_messages/help.txt similarity index 85% rename from static_messages/help.txt rename to bot_s3rius/static_messages/help.txt index 8f01655b28c2a7951f4991d7c01adb4da0859db5..44a88581abec49308670b32ca88d10c9fcca0b31 100644 --- a/static_messages/help.txt +++ b/bot_s3rius/static_messages/help.txt @@ -18,8 +18,6 @@ `.scc` ПоÑмотреть курÑÑ‹ криптовалют. `.rl` Создать бегущую Ñтроку из ÑообщениÑ. `.i <запроÑ>` вернет пачку картинок Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚Ð¸ÐºÐ¾Ð². -* `.bl` <любой текÑÑ‚> - заменит вÑе запÑтые на вÑÑкие гадоÑти. -* `.t` - показать текущее Ð²Ñ€ÐµÐ¼Ñ -* `@all` -- упомÑнуть вÑех в беÑеде +`@all` -- упомÑнуть вÑех в беÑеде И, ко вÑему прочему, Ñ Ð¾Ñ‡ÐµÐ½ÑŒ внимательный. ЕÑли Ð¼ÐµÐ½Ñ Ð¿Ð¾Ñлать на три буквы, либо добавитьÑÑ Ð¸Ð»Ð¸ выйти из беÑеды, то Ñ Ñто замечу и незамедлительно отреагирую. diff --git a/src/templates/index.html b/bot_s3rius/templates/index.html similarity index 100% rename from src/templates/index.html rename to bot_s3rius/templates/index.html diff --git a/src/templates/static/girl_1.png b/bot_s3rius/templates/static/girl_1.png similarity index 100% rename from src/templates/static/girl_1.png rename to bot_s3rius/templates/static/girl_1.png diff --git a/src/templates/static/girl_2.png b/bot_s3rius/templates/static/girl_2.png similarity index 100% rename from src/templates/static/girl_2.png rename to bot_s3rius/templates/static/girl_2.png diff --git a/src/templates/static/girl_3.png b/bot_s3rius/templates/static/girl_3.png similarity index 100% rename from src/templates/static/girl_3.png rename to bot_s3rius/templates/static/girl_3.png diff --git a/src/utils/__init__.py b/bot_s3rius/utils/__init__.py similarity index 100% rename from src/utils/__init__.py rename to bot_s3rius/utils/__init__.py diff --git a/src/utils/converters.py b/bot_s3rius/utils/converters.py similarity index 100% rename from src/utils/converters.py rename to bot_s3rius/utils/converters.py diff --git a/src/utils/library_package.py b/bot_s3rius/utils/library_package.py similarity index 93% rename from src/utils/library_package.py rename to bot_s3rius/utils/library_package.py index d84a7f5d5b001c10c5c8483b322a13b86d4217b1..e180ca6325f6fa95ab7a8417dcf7bbc6636ad35a 100644 --- a/src/utils/library_package.py +++ b/bot_s3rius/utils/library_package.py @@ -2,8 +2,9 @@ import urllib.parse from operator import itemgetter import httpx -from src.config import config -from src.utils.responses import failed_search_answer + +from bot_s3rius.config import config +from bot_s3rius.utils.responses import failed_search_answer def render_package_info(info: dict, add_command: str) -> str: diff --git a/src/utils/responses.py b/bot_s3rius/utils/responses.py similarity index 97% rename from src/utils/responses.py rename to bot_s3rius/utils/responses.py index 6a97f5733f7824352ee3a576a67a6cd2afcc91d7..9573c52d20ac4ff44356de0e2620ca257f00cebc 100644 --- a/src/utils/responses.py +++ b/bot_s3rius/utils/responses.py @@ -3,9 +3,10 @@ import functools import logging import random -from src.config import config from telethon import events, functions +from bot_s3rius.config import config + logger = logging.getLogger(__name__) FAILED_SEARCH = [ @@ -33,7 +34,7 @@ def failed_search_answer() -> str: return random.choice(FAILED_SEARCH) -def thinking(f): +def thinking(f): # noqa: C901 @functools.wraps(f) async def updated_function(event: events.NewMessage.Event): think_msg = random.choice(THINKING_MSGS) diff --git a/src/utils/str_helpers.py b/bot_s3rius/utils/str_helpers.py similarity index 100% rename from src/utils/str_helpers.py rename to bot_s3rius/utils/str_helpers.py diff --git a/deploy.sh b/deploy.sh deleted file mode 100644 index 30e5461a145d35b7245074d388b93fb6c801c879..0000000000000000000000000000000000000000 --- a/deploy.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -TELEGRAM_APP_ID="${TELEGRM_APP_ID_MASKED//a/}" -{ - echo "TELEGRAM_APP_ID=${TELEGRAM_APP_ID}" - echo "TELEGRAM_API_HASH=${TELEGRAM_API_HASH}" - echo "TELEGRAM_ACCOUNT_PHONE=${TELEGRAM_ACCOUNT_PHONE}" - echo "LIBRARIES_IO_API_TOKEN=${LIBRARIES_IO_API_TOKEN}" - echo "EXCLUDED_CHATS=${EXCLUDED_CHATS}" -} >>.env - -# Store some info in app.info file -{ -printf "Maintainer: \`win10@list.ru\`\n" -printf "Repo url: \`%s\`\n" "$CI_PROJECT_URL" -printf "Last commit: \`\`\`\n%s \`\`\`\n" "$(git log -1 --pretty=%B)" -} > ./static_messages/app.info - -sed -i "s#WorkingDirectory=.*#WorkingDirectory=${APP_DIR:?}#" -i ./systemd/bot_s3rius_san.service - -rm -rf "${APP_DIR:?}/"* -rsync -av --exclude=".git" . "${APP_DIR}" -cd "${APP_DIR}" || exit 1 -sudo cp -f "${APP_DIR:?}/systemd/"* /lib/systemd/system/ -sudo systemctl daemon-reload -sudo systemctl restart bot_s3rius_san.service diff --git a/deploy/Dockerfiles/Dockerfile b/deploy/Dockerfiles/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..b81f43133928487a40436ec004d1236e72701e19 --- /dev/null +++ b/deploy/Dockerfiles/Dockerfile @@ -0,0 +1,36 @@ +FROM python:3.9-alpine3.13 + +RUN adduser --disabled-password bot + +RUN apk add --no-cache curl + +ENV POETRY_VERSION 1.1.6 + +USER bot +RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + +ENV PATH="${PATH}:/home/bot/.poetry/bin:/home/bot/.local/bin" +RUN source "/home/bot/.poetry/env" + +# Installing requirements +RUN poetry config virtualenvs.create false + +COPY pyproject.toml poetry.lock /home/bot/app/ +WORKDIR /home/bot/app/ + +RUN poetry install --no-dev + +# Copying actuall application +COPY . /home/bot/app/src/ +WORKDIR /home/bot/app/src/ +RUN pip install --use-feature=in-tree-build . + +WORKDIR /home/bot/app + +USER root +RUN rm -rf /home/bot/app/src +RUN chown -R bot /home/bot +RUN chmod -R 700 /home/bot +USER bot + +CMD "start_bot" diff --git a/deploy/Dockerfiles/test.Dockerfile b/deploy/Dockerfiles/test.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..c0b27c0a6691f3265b5376d77c364ad4a60c9c44 --- /dev/null +++ b/deploy/Dockerfiles/test.Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.9-alpine3.13 + +RUN apk add --no-cache curl gcc musl-dev +ENV POETRY_VERSION 1.1.6 + +RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + +ENV PATH="${PATH}:/root/.local/bin:/root/.poetry/bin" +RUN source "/root/.poetry/env" + +# Installing requirements +RUN poetry config virtualenvs.create false + +COPY . /app/ +WORKDIR /app/ + +RUN poetry install diff --git a/docker-compose.test.yml b/deploy/docker-compose.test.yml similarity index 62% rename from docker-compose.test.yml rename to deploy/docker-compose.test.yml index 68bd8b5e75f6ed40eb189cbd55547ef79daf3b41..3e2dba770c491ab10377dc620f43e604c1407fde 100644 --- a/docker-compose.test.yml +++ b/deploy/docker-compose.test.yml @@ -4,6 +4,5 @@ services: test_bot_service: container_name: 'bot_s3rius_san_test' build: - dockerfile: Dockerfiles/test.Dockerfile + dockerfile: ./deploy/Dockerfiles/test.Dockerfile context: . - command: make _test diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..e6ff0b8fc644fc3eaaa3625f19bc84ccd7ec86f3 --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3.7' +networks: + memes_network: + external: + name: memes_network + + +services: + bot_service: + container_name: 'bot_s3rius_san' + build: + dockerfile: ./deploy/Dockerfiles/Dockerfile + context: . + image: docker.le-memese.com/bots/s3rius-bot:${CI_COMMIT_REF_SLUG:-latest} + env_file: + - .gen.env + labels: + - traefik.enable=true + + - traefik.http.routers.s3_bot_router.rule=Host('${BOT_HOST}') + - traefik.http.routers.s3_bot_router.service=s3_bot + - traefik.http.routers.s3_bot_router.tls=true + - traefik.http.routers.s3_bot_router.entrypoints=https + + - traefik.http.services.s3_bot.loadbalancer.server.port=${BOT_FLASK_PORT:-8080} + + networks: + - traefik-shared + +networks: + traefik-shared: + name: traefik-shared + external: true diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 07ce292244d5e55f674c3fe2fdc74ab92687ecff..0000000000000000000000000000000000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: '3.7' -networks: - memes_network: - external: - name: memes_network - - -services: - bot_service: - container_name: 'bot_s3rius_san' - build: - dockerfile: Dockerfiles/Dockerfile - context: . - env_file: - - .env - environment: - FLASK_PORT: '8080' - expose: - - 8080 - networks: - - memes_network diff --git a/main.py b/main.py deleted file mode 100644 index b2aa467516d8b51141aed6b9be84bbed8e4016b6..0000000000000000000000000000000000000000 --- a/main.py +++ /dev/null @@ -1,5 +0,0 @@ -from src.initializator import init - -if __name__ == "__main__": - client = init() - client.run_until_disconnected() diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000000000000000000000000000000000000..a904608a9ef9f01dd0c6662d476b6c4952d7c9ee --- /dev/null +++ b/poetry.lock @@ -0,0 +1,951 @@ +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "black" +version = "21.5b2" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +appdirs = "*" +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.8.1,<1" +regex = ">=2020.1.8" +toml = ">=0.10.1" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2021.5.30" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cfgv" +version = "3.3.0" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[[package]] +name = "click" +version = "8.0.1" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coverage" +version = "5.5" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +toml = ["toml"] + +[[package]] +name = "distlib" +version = "0.3.2" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "filelock" +version = "3.0.12" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "flake8" +version = "3.9.2" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" + +[[package]] +name = "flask" +version = "1.1.2" +description = "A simple framework for building complex web applications." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +click = ">=5.1" +itsdangerous = ">=0.24" +Jinja2 = ">=2.10.1" +Werkzeug = ">=0.15" + +[package.extras] +dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] +docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] +dotenv = ["python-dotenv"] + +[[package]] +name = "h11" +version = "0.12.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "httpcore" +version = "0.13.3" +description = "A minimal low-level HTTP client." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +h11 = ">=0.11,<0.13" +sniffio = ">=1.0.0,<2.0.0" + +[package.extras] +http2 = ["h2 (>=3,<5)"] + +[[package]] +name = "httpx" +version = "0.18.1" +description = "The next generation HTTP client." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +certifi = "*" +httpcore = ">=0.13.0,<0.14.0" +rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +sniffio = "*" + +[package.extras] +brotli = ["brotlicffi (>=1.0.0,<2.0.0)"] +http2 = ["h2 (>=3.0.0,<4.0.0)"] + +[[package]] +name = "identify" +version = "2.2.9" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.extras] +license = ["editdistance-s"] + +[[package]] +name = "idna" +version = "3.2" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "isort" +version = "5.8.0" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] + +[[package]] +name = "itsdangerous" +version = "2.0.1" +description = "Safely pass data to untrusted environments and back." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "jinja2" +version = "3.0.1" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "nodeenv" +version = "1.6.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "packaging" +version = "20.9" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +dev = ["pre-commit", "tox"] + +[[package]] +name = "pre-commit" +version = "2.13.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +toml = "*" +virtualenv = ">=20.0.8" + +[[package]] +name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyaes" +version = "1.6.1" +description = "Pure-Python Implementation of the AES block-cipher and common modes of operation" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyasn1" +version = "0.4.8" +description = "ASN.1 types and codecs" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pycodestyle" +version = "2.7.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pydantic" +version = "1.8.2" +description = "Data validation and settings management using python 3.6 type hinting" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +typing-extensions = ">=3.7.4.3" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pyflakes" +version = "2.3.1" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "pytest" +version = "6.2.4" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<1.0.0a1" +py = ">=1.8.2" +toml = "*" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.15.1" +description = "Pytest support for asyncio." +category = "dev" +optional = false +python-versions = ">= 3.6" + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +testing = ["coverage", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-cov" +version = "2.12.1" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +coverage = ">=5.2.1" +pytest = ">=4.6" +toml = "*" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytz" +version = "2021.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "regex" +version = "2021.4.4" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "rsa" +version = "4.7.2" +description = "Pure-Python RSA implementation" +category = "main" +optional = false +python-versions = ">=3.5, <4" + +[package.dependencies] +pyasn1 = ">=0.1.3" + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "sniffio" +version = "1.2.0" +description = "Sniff out which async library your code is running under" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "telethon" +version = "1.14.0" +description = "Full-featured Telegram client library for Python 3" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +pyaes = "*" +rsa = "*" + +[package.extras] +cryptg = ["cryptg"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "typing-extensions" +version = "3.10.0.0" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "virtualenv" +version = "20.4.7" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" + +[package.dependencies] +appdirs = ">=1.4.3,<2" +distlib = ">=0.3.1,<1" +filelock = ">=3.0.0,<4" +six = ">=1.9.0,<2" + +[package.extras] +docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] +testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] + +[[package]] +name = "werkzeug" +version = "2.0.1" +description = "The comprehensive WSGI web application library." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +watchdog = ["watchdog"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.9" +content-hash = "49ee7fc2622e2d548e496f801a6e87d68f8117c8921998687b05c7dd5d9bc070" + +[metadata.files] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +black = [ + {file = "black-21.5b2-py3-none-any.whl", hash = "sha256:e5cf21ebdffc7a9b29d73912b6a6a9a4df4ce70220d523c21647da2eae0751ef"}, + {file = "black-21.5b2.tar.gz", hash = "sha256:1fc0e0a2c8ae7d269dfcf0c60a89afa299664f3e811395d40b1922dff8f854b5"}, +] +certifi = [ + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, +] +cfgv = [ + {file = "cfgv-3.3.0-py2.py3-none-any.whl", hash = "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"}, + {file = "cfgv-3.3.0.tar.gz", hash = "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1"}, +] +click = [ + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +coverage = [ + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, +] +distlib = [ + {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"}, + {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"}, +] +filelock = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] +flake8 = [ + {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, + {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, +] +flask = [ + {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, + {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, +] +h11 = [ + {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, + {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, +] +httpcore = [ + {file = "httpcore-0.13.3-py3-none-any.whl", hash = "sha256:ff614f0ef875b9e5fe0bdd459b31ea0eea282ff12dc82add83d68b3811ee94ad"}, + {file = "httpcore-0.13.3.tar.gz", hash = "sha256:5d674b57a11275904d4fd0819ca02f960c538e4472533620f322fc7db1ea0edc"}, +] +httpx = [ + {file = "httpx-0.18.1-py3-none-any.whl", hash = "sha256:ad2e3db847be736edc4b272c4d5788790a7e5789ef132fc6b5fef8aeb9e9f6e0"}, + {file = "httpx-0.18.1.tar.gz", hash = "sha256:0a2651dd2b9d7662c70d12ada5c290abcf57373b9633515fe4baa9f62566086f"}, +] +identify = [ + {file = "identify-2.2.9-py2.py3-none-any.whl", hash = "sha256:96c57d493184daecc7299acdeef0ad7771c18a59931ea927942df393688fe849"}, + {file = "identify-2.2.9.tar.gz", hash = "sha256:3a8493cf49cfe4b28d50865e38f942c11be07a7b0aab8e715073e17f145caacc"}, +] +idna = [ + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +isort = [ + {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, + {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, +] +itsdangerous = [ + {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, + {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, +] +jinja2 = [ + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, +] +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +nodeenv = [ + {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, + {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, +] +packaging = [ + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, +] +pathspec = [ + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +pre-commit = [ + {file = "pre_commit-2.13.0-py2.py3-none-any.whl", hash = "sha256:b679d0fddd5b9d6d98783ae5f10fd0c4c59954f375b70a58cbe1ce9bcf9809a4"}, + {file = "pre_commit-2.13.0.tar.gz", hash = "sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378"}, +] +py = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] +pyaes = [ + {file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"}, +] +pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, +] +pycodestyle = [ + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, +] +pydantic = [ + {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, + {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, + {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, + {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, + {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, + {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, + {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, + {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, + {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, + {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, +] +pyflakes = [ + {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, + {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, + {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, +] +pytest-asyncio = [ + {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, + {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, +] +pytest-cov = [ + {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, + {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, +] +pytz = [ + {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, + {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, +] +pyyaml = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] +regex = [ + {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"}, + {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"}, + {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"}, + {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"}, + {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"}, + {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"}, + {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"}, + {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"}, + {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"}, + {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"}, + {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"}, + {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"}, + {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"}, +] +rfc3986 = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] +rsa = [ + {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, + {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +sniffio = [ + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, +] +telethon = [ + {file = "Telethon-1.14.0-py3-none-any.whl", hash = "sha256:c8b56e26bd4588e8e4e13b7866b86eab360d806358b110066af7a2b25be14fb9"}, + {file = "Telethon-1.14.0.tar.gz", hash = "sha256:d8bb37f80c4a8befa92d0525f00a578a74064645e48d7aa0cc4731f3d813e1b9"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, +] +virtualenv = [ + {file = "virtualenv-20.4.7-py2.py3-none-any.whl", hash = "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"}, + {file = "virtualenv-20.4.7.tar.gz", hash = "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467"}, +] +werkzeug = [ + {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"}, + {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..76e10057532760cbee9e9aca4b2cc2a25607e87c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,30 @@ +[tool.poetry] +name = "bot_s3rius" +version = "0.1.0" +description = "Telegram bot for @s3rius_san" +readme = "README.md" +authors = ["Pavel Kirilin <win10@list.ru>"] + +[tool.poetry.dependencies] +python = "^3.9" +Flask = "1.1.2" +pydantic = "^1.8.2" +pytz = "^2021.1" +Telethon = "1.14.0" +httpx = "^0.18.1" + +[tool.poetry.dev-dependencies] +pytest = "^6.2.4" +flake8 = "^3.9.2" +black = "^21.5b2" +isort = "^5.8.0" +pre-commit = "^2.13.0" +pytest-asyncio = "^0.15.1" +pytest-cov = "^2.12.1" + +[tool.poetry.scripts] +start_bot = "bot_s3rius.initializator:main" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements/requirements.base.txt b/requirements/requirements.base.txt deleted file mode 100644 index d23a95b5a25f078d37521cdb4ed0e9fc3a5c4c2f..0000000000000000000000000000000000000000 --- a/requirements/requirements.base.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==1.1.2 -httpx==0.13.* -pydantic==1.5.1 -pytz==2020.1 -Telethon==1.14.0 diff --git a/requirements/requirements.dev.txt b/requirements/requirements.dev.txt deleted file mode 100644 index ef00d8b858fd55634821695dead29d5a95a48bdf..0000000000000000000000000000000000000000 --- a/requirements/requirements.dev.txt +++ /dev/null @@ -1,8 +0,0 @@ --r requirements.base.txt -black==19.10b0 -docker-compose==1.26.0 -flake8==3.8.3 -isort==4.3.21 -pre-commit==2.5.1 -pytest==5.4.3 -pytest-asyncio==0.14.0 diff --git a/src/config.py b/src/config.py deleted file mode 100644 index 938d672357ea1720bcb938cd1c198805ad7d20ca..0000000000000000000000000000000000000000 --- a/src/config.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import List - -from pydantic import BaseSettings -from pydantic.fields import Field -from telethon import TelegramClient - -__all__ = ["config"] - - -class Config(BaseSettings): - telegram_app_id: str = Field(None, env="TELEGRAM_APP_ID", required=True) - - telegram_api_hash: str = Field(None, env="TELEGRAM_API_HASH", required=True) - - libraries_io_token: str = Field(None, env="LIBRARIES_IO_API_TOKEN", required=True) - - telegram_account_phone: str = Field( - None, env="TELEGRAM_ACCOUNT_PHONE", required=True - ) - - app_mode: str = Field(name="app_mode", default="dev", env="APP_MODE") - - debug_mode: bool = False - - flask_port: str = Field(name="flask_port", default="8080", env="FLASK_PORT") - - excluded_chats: List[str] = Field([], env="EXCLUDED_CHATS") - - telegram_client: TelegramClient = None - - -config = Config() diff --git a/static_messages/app.info b/static_messages/app.info deleted file mode 100644 index 089ee52bf61b65e7375d44eb6389263937843006..0000000000000000000000000000000000000000 --- a/static_messages/app.info +++ /dev/null @@ -1,3 +0,0 @@ -Maintainer: `win10@list.ru` -Repo url: `repo` -Last commit: ```Nothing to show``` diff --git a/systemd/bot_s3rius_san.service b/systemd/bot_s3rius_san.service deleted file mode 100644 index 93450b19247009b38430b1fa59d4c7acc49d1a74..0000000000000000000000000000000000000000 --- a/systemd/bot_s3rius_san.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=S3rius's san account bot. -After=network.target - -[Service] -Type=simple -User=bots -WorkingDirectory= -ExecStart=/bin/bash -c 'make prod' -ExecStop=/bin/bash -c 'make clean_prod' -Restart=on-abort - -[Install] -WantedBy=multi-user.target - diff --git a/tests/__init__.py b/tests/__init__.py index e745c0da8959a1c9ccfa23aeb08adabc9032fc31..9dd23369bee510fcfecba3c3b022c81ad81a988c 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock def patch_client(): - from src.config import config + from bot_s3rius.config import config client_mock = MagicMock() print("Updating config") diff --git a/tests/test_fun.py b/tests/test_fun.py index 57757ab064b419b60f67c8c08cc493f0b70e63e4..a546c377218f5afb5ed3c6cc3a67faebdc6e8fec 100644 --- a/tests/test_fun.py +++ b/tests/test_fun.py @@ -1,5 +1,6 @@ import pytest -from src.actions import fun + +from bot_s3rius.actions import fun from tests.conftest import NewMessageTestEvent