diff --git a/.gitignore b/.gitignore index dc7ea06..20abbfd 100644 --- a/.gitignore +++ b/.gitignore @@ -217,4 +217,3 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..45e9c60 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 + hooks: + - id: trailing-whitespace # убирает лишние пробелы + - id: check-added-large-files # проверяет тяжелые файлы на изменения + - id: check-yaml # проверяет синтаксис .yaml файлов + - id: check-json # проверяет синтаксис .json файлов + exclude: launch.json + - id: check-case-conflict # проверяет файлы, которые могут конфликтовать в файловых системах без учета регистра. + - id: check-merge-conflict # проверяет файлы, содержащие конфликтные строки слияния. + - id: double-quote-string-fixer # заменяет " на ' + - id: end-of-file-fixer # добавляет пустую строку в конце файла + +# Отсортировывает импорты в проекте +- repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + exclude: __init__.py + args: [ --profile, black, --filter-files ] + +# Обновляет синтаксис Python кода в соответствии с последними версиями +- repo: https://github.com/asottile/pyupgrade + rev: v2.31.1 + hooks: + - id: pyupgrade + args: [--py310-plus] + +# Форматирует код под PEP8 +- repo: https://github.com/pre-commit/mirrors-autopep8 + rev: v2.0.1 + hooks: + - id: autopep8 + args: [--max-line-length=120, --in-place] + +# Сканер стилистических ошибок, нарушающие договоренности PEP8 +- repo: https://github.com/PyCQA/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + exclude: "__init__.py" + args: ["--ignore=E501,F821", "--max-line-length=120"] + +# Проверка статических типов с помощью mypy +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.991 + hooks: + - id: mypy + exclude: 'migrations' diff --git a/README.md b/README.md index 88ce8f2..a9daf59 100644 --- a/README.md +++ b/README.md @@ -53,19 +53,19 @@ Fastapi веб приложение реализующее api для общеп Для Menu доступен метод GET возвращающий все его SubMenu. Аналогично для SubMenu реализован метод для возврата всех Dish. ### Спринт 2 -- 1й пункт ТЗ -Тесты реализованы в виде 2х классов +- 1й пункт ТЗ +Тесты реализованы в виде 2х классов `TastBaseCrud` включает 3 подкласса `Menu`, `Submenu`, `Dish` которые реализуют интерфейсы взаимодействия с endpoint'ами реализованных на предыдущем спринте сущностей. Каждый подкласс реализует методы GET(получение всех сущностей), Get(получение конкректной сущности), Post(создание), Patch(обновление), Delete(удаления). Так же в классе реализованы 3 тестовых функции, которые осуществляют тестирование соответствующих endpoint'ов `TestContinuity` реализует последовательность сценария «Проверка кол-ва блюд и подменю в меню» из Postman -- 2й пункт ТЗ -Реализованы 3 контейнера(db, app, tests). В db написан блок "проверки здоровья", от которого зависят контейнеры app и test, который гарантирует, что зависимые контейнеры не будут запущены о полной готовности db. +- 2й пункт ТЗ +Реализованы 3 контейнера(db, app, tests). В db написан блок "проверки здоровья", от которого зависят контейнеры app и test, который гарантирует, что зависимые контейнеры не будут запущены о полной готовности db. -- 3й пункт ТЗ +- 3й пункт ТЗ см. функцию `get_menu_item` на 28 строке в файле /fastfood/crud/menu.py -- 4й пункт ТЗ +- 4й пункт ТЗ см. класс `TestContinuity` в файле /tests/test_api.py @@ -106,7 +106,7 @@ Fastapi веб приложение реализующее api для общеп По завершении работы остановите контейнеры > `$ docker-compose -f compose_app.yml down` -После успешного запуска образов документация по API будет доступна по адресу http://localhost:8000 +После успешного запуска образов документация по API будет доступна по адресу http://localhost:8000 - Запуск тестов @@ -117,7 +117,7 @@ Fastapi веб приложение реализующее api для общеп ### Linux -Установите и настройте postgresql согласно офф. документации. Создайте пользователя и бд. +Установите и настройте postgresql согласно офф. документации. Создайте пользователя и бд. Установите систему управления зависимостями > `$ pip[x] install poetry` @@ -136,7 +136,7 @@ Fastapi веб приложение реализующее api для общеп ## Запуск Запуск проекта возможен в 2х режимах: - Запуск в режиме "prod" с ключем --run-server - Подразумевает наличие уже созданных таблиц в базе данных(например с помощью Alembic). Манипуляций со структурой БД не происходит. Данные не удаляются. + Подразумевает наличие уже созданных таблиц в базе данных(например с помощью Alembic). Манипуляций со структурой БД не происходит. Данные не удаляются. - Запуск в режиме "dev" c ключем --run-test-server В этом случае при каждом запуске проекта все таблицы с данными удаляются из БД и создаются снова согласно описанных моделей. @@ -165,5 +165,3 @@ Fastapi веб приложение реализующее api для общеп ## Лицензия Распространяется под [MIT лицензией](https://mit-license.org/). - - diff --git a/compose_app.yml b/compose_app.yml index 2028dc8..a167cdb 100644 --- a/compose_app.yml +++ b/compose_app.yml @@ -2,44 +2,43 @@ version: "3.8" services: db: container_name: pgdb - + image: postgres:15.1-alpine - + env_file: - .env - + environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - + ports: - 6432:5432 - + healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 - + app: container_name: fastfood_app - + build: context: . - + env_file: - .env - + ports: - 8000:8000 - + depends_on: db: condition: service_healthy - + restart: always command: /bin/bash -c 'poetry run python /usr/src/fastfood/manage.py --run-test-server' - diff --git a/compose_test.yml b/compose_test.yml index 0b706f2..b7beb91 100644 --- a/compose_test.yml +++ b/compose_test.yml @@ -2,44 +2,43 @@ version: "3.8" services: db: container_name: pgdb_test - + image: postgres:15.1-alpine - + env_file: - .env - + environment: POSTGRES_DB: ${POSTGRES_DB_TEST} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - + ports: - 6432:5432 - + healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB_TEST}"] interval: 10s timeout: 5s retries: 5 - + app: container_name: fastfood_app_test - + build: context: . - + env_file: - .env - + ports: - 8000:8000 - + depends_on: db: condition: service_healthy - + restart: always command: /bin/bash -c 'poetry run pytest -vv' - diff --git a/fastfood/app.py b/fastfood/app.py index 092928b..6d6a016 100644 --- a/fastfood/app.py +++ b/fastfood/app.py @@ -50,14 +50,14 @@ description = """ tags_metadata = [ { - "name": "menu", - "description": "Операции с меню.", + 'name': 'menu', + 'description': 'Операции с меню.', }, { - "name": "submenu", - "description": "Подменю и работа с ним", + 'name': 'submenu', + 'description': 'Подменю и работа с ним', }, - {"name": "dish", "description": "Блюда и работа с ними"}, + {'name': 'dish', 'description': 'Блюда и работа с ними'}, ] @@ -66,17 +66,17 @@ def create_app(redis=None) -> FastAPI: Фабрика FastAPI. """ app = FastAPI( - title="Fastfood-API", + title='Fastfood-API', description=description, - version="0.0.1", + version='0.0.1', contact={ - "name": "Sergey Vanyushkin", - "url": "http://pi3c.ru", - "email": "pi3c@yandex.ru", + 'name': 'Sergey Vanyushkin', + 'url': 'http://pi3c.ru', + 'email': 'pi3c@yandex.ru', }, license_info={ - "name": "MIT license", - "url": "https://mit-license.org/", + 'name': 'MIT license', + 'url': 'https://mit-license.org/', }, openapi_tags=tags_metadata, ) diff --git a/fastfood/config.py b/fastfood/config.py index 58e5577..524da54 100644 --- a/fastfood/config.py +++ b/fastfood/config.py @@ -2,13 +2,13 @@ from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): - DB_HOST: str = "" + DB_HOST: str = '' DB_PORT: int = 5432 - POSTGRES_DB: str = "" - POSTGRES_PASSWORD: str = "" - POSTGRES_USER: str = "" - POSTGRES_DB_TEST: str = "" - REDIS_DB: str = "" + POSTGRES_DB: str = '' + POSTGRES_PASSWORD: str = '' + POSTGRES_USER: str = '' + POSTGRES_DB_TEST: str = '' + REDIS_DB: str = '' @property def DATABASE_URL_asyncpg(self): @@ -16,9 +16,9 @@ class Settings(BaseSettings): Возвращает строку подключения к БД необходимую для SQLAlchemy """ return ( - "postgresql+asyncpg://" - f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}" - f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}" + 'postgresql+asyncpg://' + f'{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}' + f'@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}' ) @property @@ -27,12 +27,12 @@ class Settings(BaseSettings): Возвращает строку подключения к БД необходимую для SQLAlchemy """ return ( - "postgresql+asyncpg://" - f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}" - f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB_TEST}" + 'postgresql+asyncpg://' + f'{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}' + f'@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB_TEST}' ) - model_config = SettingsConfigDict(env_file=".env") + model_config = SettingsConfigDict(env_file='.env') settings = Settings() diff --git a/fastfood/dbase.py b/fastfood/dbase.py index 5d3e5b9..f7b38d3 100644 --- a/fastfood/dbase.py +++ b/fastfood/dbase.py @@ -1,6 +1,6 @@ from typing import AsyncGenerator -import redis.asyncio as redis +import redis.asyncio as redis # type: ignore from fastapi import Depends from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine diff --git a/fastfood/models.py b/fastfood/models.py index 98d2d10..bc8e12a 100644 --- a/fastfood/models.py +++ b/fastfood/models.py @@ -1,6 +1,6 @@ import uuid from copy import deepcopy -from typing import Annotated, List, Optional +from typing import Annotated from sqlalchemy import ForeignKey from sqlalchemy.dialects.postgresql import UUID @@ -21,13 +21,13 @@ str_25 = Annotated[str, 25] class Base(DeclarativeBase): id: Mapped[uuidpk] title: Mapped[str_25] - description: Mapped[Optional[str]] + description: Mapped[str | None] def __eq__(self, other): classes_match = isinstance(other, self.__class__) a, b = deepcopy(self.__dict__), deepcopy(other.__dict__) - a.pop("_sa_instance_state", None) - b.pop("_sa_instance_state", None) + a.pop('_sa_instance_state', None) + b.pop('_sa_instance_state', None) attrs_match = a == b return classes_match and attrs_match @@ -36,13 +36,13 @@ class Base(DeclarativeBase): class Menu(Base): - __tablename__ = "menu" + __tablename__ = 'menu' - submenus: Mapped[List["SubMenu"]] = relationship( - "SubMenu", - backref="menu", - lazy="selectin", - cascade="all, delete", + submenus: Mapped[list['SubMenu']] = relationship( + 'SubMenu', + backref='menu', + lazy='selectin', + cascade='all, delete', ) @hybridproperty @@ -58,16 +58,16 @@ class Menu(Base): class SubMenu(Base): - __tablename__ = "submenu" + __tablename__ = 'submenu' parent_menu: Mapped[uuid.UUID] = mapped_column( - ForeignKey("menu.id", ondelete="CASCADE") + ForeignKey('menu.id', ondelete='CASCADE') ) - dishes: Mapped[List["Dish"]] = relationship( - "Dish", - backref="submenu", - lazy="selectin", - cascade="all, delete", + dishes: Mapped[list['Dish']] = relationship( + 'Dish', + backref='submenu', + lazy='selectin', + cascade='all, delete', ) @hybridproperty @@ -76,9 +76,9 @@ class SubMenu(Base): class Dish(Base): - __tablename__ = "dish" + __tablename__ = 'dish' price: Mapped[float] parent_submenu: Mapped[uuid.UUID] = mapped_column( - ForeignKey("submenu.id", ondelete="CASCADE") + ForeignKey('submenu.id', ondelete='CASCADE') ) diff --git a/fastfood/repository/menu.py b/fastfood/repository/menu.py index 818947a..51ac715 100644 --- a/fastfood/repository/menu.py +++ b/fastfood/repository/menu.py @@ -33,8 +33,8 @@ class MenuRepository: query = ( select( m, - func.count(distinct(s.id)).label("submenus_count"), - func.count(distinct(d.id)).label("dishes_count"), + func.count(distinct(s.id)).label('submenus_count'), + func.count(distinct(d.id)).label('dishes_count'), ) .join(s, s.parent_menu == m.id, isouter=True) .join(d, d.parent_submenu == s.id, isouter=True) diff --git a/fastfood/repository/redis.py b/fastfood/repository/redis.py index 1e1a08b..037be4d 100644 --- a/fastfood/repository/redis.py +++ b/fastfood/repository/redis.py @@ -1,6 +1,6 @@ from typing import Any -import redis.asyncio as redis +import redis.asyncio as redis # type: ignore from fastapi import BackgroundTasks, Depends from fastfood.dbase import get_redis_pool diff --git a/fastfood/repository/submenu.py b/fastfood/repository/submenu.py index 083757e..721c25b 100644 --- a/fastfood/repository/submenu.py +++ b/fastfood/repository/submenu.py @@ -40,7 +40,7 @@ class SubMenuRepository: s = aliased(models.SubMenu) d = aliased(models.Dish) query = ( - select(s, func.count(distinct(d.id)).label("dishes_count")) + select(s, func.count(distinct(d.id)).label('dishes_count')) .join(d, s.id == d.parent_submenu, isouter=True) .group_by(s.id) .where(s.id == submenu_id) diff --git a/fastfood/routers/dish.py b/fastfood/routers/dish.py index 05b9dd4..0c8fd33 100644 --- a/fastfood/routers/dish.py +++ b/fastfood/routers/dish.py @@ -7,12 +7,12 @@ from fastfood.service.dish import DishService from fastfood.utils import price_converter router = APIRouter( - prefix="/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes", - tags=["dish"], + prefix='/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes', + tags=['dish'], ) -@router.get("/") +@router.get('/') async def get_dishes( menu_id: UUID, submenu_id: UUID, @@ -23,7 +23,7 @@ async def get_dishes( return result -@router.post("/", status_code=201) +@router.post('/', status_code=201) async def create_dish( menu_id: UUID, submenu_id: UUID, @@ -39,7 +39,7 @@ async def create_dish( return price_converter(result) -@router.get("/{dish_id}") +@router.get('/{dish_id}') async def get_dish( menu_id: UUID, submenu_id: UUID, @@ -53,11 +53,11 @@ async def get_dish( dish_id, ) if not result: - raise HTTPException(status_code=404, detail="dish not found") + raise HTTPException(status_code=404, detail='dish not found') return price_converter(result) -@router.patch("/{dish_id}") +@router.patch('/{dish_id}') async def update_dish( menu_id: UUID, submenu_id: UUID, @@ -75,7 +75,7 @@ async def update_dish( return price_converter(result) -@router.delete("/{dish_id}") +@router.delete('/{dish_id}') async def delete_dish( menu_id: UUID, submenu_id: UUID, diff --git a/fastfood/routers/menu.py b/fastfood/routers/menu.py index bb7045d..7f96f5b 100644 --- a/fastfood/routers/menu.py +++ b/fastfood/routers/menu.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from uuid import UUID from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException @@ -7,12 +7,12 @@ from fastfood.schemas import Menu, MenuBase, MenuRead from fastfood.service.menu import MenuService router = APIRouter( - prefix="/api/v1/menus", - tags=["menu"], + prefix='/api/v1/menus', + tags=['menu'], ) -@router.get("/", response_model=Optional[List[Menu]]) +@router.get('/', response_model=Optional[list[Menu]]) async def get_menus( menu: MenuService = Depends(), background_tasks: BackgroundTasks = BackgroundTasks(), @@ -20,7 +20,7 @@ async def get_menus( return await menu.read_menus() -@router.post("/", status_code=201, response_model=Menu) +@router.post('/', status_code=201, response_model=Menu) async def add_menu( menu: MenuBase, responce: MenuService = Depends(), @@ -29,7 +29,7 @@ async def add_menu( return await responce.create_menu(menu) -@router.get("/{menu_id}", response_model=MenuRead) +@router.get('/{menu_id}', response_model=MenuRead) async def get_menu( menu_id: UUID, responce: MenuService = Depends(), @@ -38,11 +38,11 @@ async def get_menu( result = await responce.read_menu(menu_id=menu_id) if not result: - raise HTTPException(status_code=404, detail="menu not found") + raise HTTPException(status_code=404, detail='menu not found') return result -@router.patch("/{menu_id}", response_model=MenuRead) +@router.patch('/{menu_id}', response_model=MenuRead) async def update_menu( menu_id: UUID, menu: MenuBase, @@ -56,7 +56,7 @@ async def update_menu( return result.scalars().one() -@router.delete("/{menu_id}") +@router.delete('/{menu_id}') async def delete_menu( menu_id: UUID, menu: MenuService = Depends(), diff --git a/fastfood/routers/submenu.py b/fastfood/routers/submenu.py index 2e1578d..8b4bca8 100644 --- a/fastfood/routers/submenu.py +++ b/fastfood/routers/submenu.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from uuid import UUID from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException @@ -7,12 +7,12 @@ from fastfood.schemas import MenuBase, SubMenuRead from fastfood.service.submenu import SubmenuService router = APIRouter( - prefix="/api/v1/menus/{menu_id}/submenus", - tags=["submenu"], + prefix='/api/v1/menus/{menu_id}/submenus', + tags=['submenu'], ) -@router.get("/", response_model=Optional[List[SubMenuRead]]) +@router.get('/', response_model=Optional[list[SubMenuRead]]) async def get_submenus( menu_id: UUID, submenu: SubmenuService = Depends(), @@ -22,7 +22,7 @@ async def get_submenus( return result.scalars().all() -@router.post("/", status_code=201, response_model=SubMenuRead) +@router.post('/', status_code=201, response_model=SubMenuRead) async def create_submenu_item( menu_id: UUID, submenu_data: MenuBase, @@ -36,7 +36,7 @@ async def create_submenu_item( return result -@router.get("/{submenu_id}", response_model=SubMenuRead) +@router.get('/{submenu_id}', response_model=SubMenuRead) async def get_submenu( menu_id: UUID, submenu_id: UUID, @@ -48,12 +48,12 @@ async def get_submenu( submenu_id=submenu_id, ) if not result: - raise HTTPException(status_code=404, detail="submenu not found") + raise HTTPException(status_code=404, detail='submenu not found') return result @router.patch( - "/{submenu_id}", + '/{submenu_id}', response_model=MenuBase, ) async def update_submenu( @@ -71,7 +71,7 @@ async def update_submenu( return result.scalars().one() -@router.delete("/{submenu_id}") +@router.delete('/{submenu_id}') async def delete_submenu( menu_id: UUID, submenu_id: UUID, diff --git a/fastfood/schemas.py b/fastfood/schemas.py index 8fab6a1..c14ff13 100644 --- a/fastfood/schemas.py +++ b/fastfood/schemas.py @@ -1,4 +1,3 @@ -from typing import Optional from uuid import UUID from pydantic import BaseModel @@ -6,7 +5,7 @@ from pydantic import BaseModel class MenuBase(BaseModel): title: str - description: Optional[str] + description: str | None class Config: from_attributes = True diff --git a/fastfood/service/dish.py b/fastfood/service/dish.py index 57962be..5dad1c4 100644 --- a/fastfood/service/dish.py +++ b/fastfood/service/dish.py @@ -1,6 +1,6 @@ from uuid import UUID -import redis.asyncio as redis +import redis.asyncio as redis # type: ignore from fastapi import BackgroundTasks, Depends from fastfood.dbase import get_async_redis_client diff --git a/fastfood/service/menu.py b/fastfood/service/menu.py index f6be1b8..c3eb13f 100644 --- a/fastfood/service/menu.py +++ b/fastfood/service/menu.py @@ -1,6 +1,6 @@ from uuid import UUID -import redis.asyncio as redis +import redis.asyncio as redis # type: ignore from fastapi import BackgroundTasks, Depends from fastfood.dbase import get_async_redis_client diff --git a/fastfood/service/submenu.py b/fastfood/service/submenu.py index c415469..167e22f 100644 --- a/fastfood/service/submenu.py +++ b/fastfood/service/submenu.py @@ -1,6 +1,6 @@ from uuid import UUID -import redis.asyncio as redis +import redis.asyncio as redis # type: ignore from fastapi import BackgroundTasks, Depends from fastfood.dbase import get_async_redis_client diff --git a/fastfood/utils.py b/fastfood/utils.py index aa1205f..7ef5890 100644 --- a/fastfood/utils.py +++ b/fastfood/utils.py @@ -1,3 +1,3 @@ def price_converter(dish: dict) -> dict: - dish.price = str(dish.price) + dish['price'] = str(dish['price']) return dish diff --git a/manage.py b/manage.py index b4778d1..f204f65 100644 --- a/manage.py +++ b/manage.py @@ -11,8 +11,8 @@ def run_app(): Запуск FastAPI """ uvicorn.run( - app="fastfood.app:create_app", - host="0.0.0.0", + app='fastfood.app:create_app', + host='0.0.0.0', port=8000, reload=True, factory=True, @@ -25,10 +25,10 @@ async def recreate(): await create_db_and_tables() -if __name__ == "__main__": - if "--run-server" in sys.argv: +if __name__ == '__main__': + if '--run-server' in sys.argv: run_app() - if "--run-test-server" in sys.argv: + if '--run-test-server' in sys.argv: asyncio.run(recreate()) run_app() diff --git a/poetry.lock b/poetry.lock index 0bae181..dc0ad01 100644 --- a/poetry.lock +++ b/poetry.lock @@ -103,13 +103,88 @@ test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"] [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] @@ -204,6 +279,71 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cryptography" +version = "42.0.2" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"}, + {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"}, + {file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"}, + {file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"}, + {file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"}, + {file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"}, + {file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"}, + {file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +nox = ["nox"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + [[package]] name = "dnspython" version = "2.5.0" @@ -272,6 +412,22 @@ typing-extensions = ">=4.8.0" [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.5)", "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 = "filelock" +version = "3.13.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + [[package]] name = "greenlet" version = "3.0.3" @@ -399,6 +555,20 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +[[package]] +name = "identify" +version = "2.5.33" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, +] + +[package.extras] +license = ["ukkonen"] + [[package]] name = "idna" version = "3.6" @@ -421,6 +591,78 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "mypy" +version = "1.8.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[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 = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + [[package]] name = "packaging" version = "23.2" @@ -432,35 +674,79 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "platformdirs" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] + [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pre-commit" +version = "3.6.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, + {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + [[package]] name = "pydantic" -version = "2.5.3" +version = "2.6.0" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, - {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, + {file = "pydantic-2.6.0-py3-none-any.whl", hash = "sha256:1440966574e1b5b99cf75a13bec7b20e3512e8a61b894ae252f56275e2c465ae"}, + {file = "pydantic-2.6.0.tar.gz", hash = "sha256:ae887bd94eb404b09d86e4d12f93893bdca79d766e738528c6fa1c849f3c6bcf"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" +pydantic-core = "2.16.1" typing-extensions = ">=4.6.1" [package.extras] @@ -468,116 +754,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.6" +version = "2.16.1" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, - {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, - {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, - {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, - {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, - {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, - {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, - {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, - {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, - {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, - {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, - {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, - {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, - {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, - {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, - {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, + {file = "pydantic_core-2.16.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:300616102fb71241ff477a2cbbc847321dbec49428434a2f17f37528721c4948"}, + {file = "pydantic_core-2.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5511f962dd1b9b553e9534c3b9c6a4b0c9ded3d8c2be96e61d56f933feef9e1f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98f0edee7ee9cc7f9221af2e1b95bd02810e1c7a6d115cfd82698803d385b28f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9795f56aa6b2296f05ac79d8a424e94056730c0b860a62b0fdcfe6340b658cc8"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c45f62e4107ebd05166717ac58f6feb44471ed450d07fecd90e5f69d9bf03c48"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462d599299c5971f03c676e2b63aa80fec5ebc572d89ce766cd11ca8bcb56f3f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ebaa4bf6386a3b22eec518da7d679c8363fb7fb70cf6972161e5542f470798"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:99f9a50b56713a598d33bc23a9912224fc5d7f9f292444e6664236ae471ddf17"}, + {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8ec364e280db4235389b5e1e6ee924723c693cbc98e9d28dc1767041ff9bc388"}, + {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:653a5dfd00f601a0ed6654a8b877b18d65ac32c9d9997456e0ab240807be6cf7"}, + {file = "pydantic_core-2.16.1-cp310-none-win32.whl", hash = "sha256:1661c668c1bb67b7cec96914329d9ab66755911d093bb9063c4c8914188af6d4"}, + {file = "pydantic_core-2.16.1-cp310-none-win_amd64.whl", hash = "sha256:561be4e3e952c2f9056fba5267b99be4ec2afadc27261505d4992c50b33c513c"}, + {file = "pydantic_core-2.16.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:102569d371fadc40d8f8598a59379c37ec60164315884467052830b28cc4e9da"}, + {file = "pydantic_core-2.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:735dceec50fa907a3c314b84ed609dec54b76a814aa14eb90da31d1d36873a5e"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e83ebbf020be727d6e0991c1b192a5c2e7113eb66e3def0cd0c62f9f266247e4"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:30a8259569fbeec49cfac7fda3ec8123486ef1b729225222f0d41d5f840b476f"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920c4897e55e2881db6a6da151198e5001552c3777cd42b8a4c2f72eedc2ee91"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5247a3d74355f8b1d780d0f3b32a23dd9f6d3ff43ef2037c6dcd249f35ecf4c"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5bea8012df5bb6dda1e67d0563ac50b7f64a5d5858348b5c8cb5043811c19d"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ed3025a8a7e5a59817b7494686d449ebfbe301f3e757b852c8d0d1961d6be864"}, + {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06f0d5a1d9e1b7932477c172cc720b3b23c18762ed7a8efa8398298a59d177c7"}, + {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:150ba5c86f502c040b822777e2e519b5625b47813bd05f9273a8ed169c97d9ae"}, + {file = "pydantic_core-2.16.1-cp311-none-win32.whl", hash = "sha256:d6cbdf12ef967a6aa401cf5cdf47850559e59eedad10e781471c960583f25aa1"}, + {file = "pydantic_core-2.16.1-cp311-none-win_amd64.whl", hash = "sha256:afa01d25769af33a8dac0d905d5c7bb2d73c7c3d5161b2dd6f8b5b5eea6a3c4c"}, + {file = "pydantic_core-2.16.1-cp311-none-win_arm64.whl", hash = "sha256:1a2fe7b00a49b51047334d84aafd7e39f80b7675cad0083678c58983662da89b"}, + {file = "pydantic_core-2.16.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f478ec204772a5c8218e30eb813ca43e34005dff2eafa03931b3d8caef87d51"}, + {file = "pydantic_core-2.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1936ef138bed2165dd8573aa65e3095ef7c2b6247faccd0e15186aabdda7f66"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99d3a433ef5dc3021c9534a58a3686c88363c591974c16c54a01af7efd741f13"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd88f40f2294440d3f3c6308e50d96a0d3d0973d6f1a5732875d10f569acef49"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fac641bbfa43d5a1bed99d28aa1fded1984d31c670a95aac1bf1d36ac6ce137"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72bf9308a82b75039b8c8edd2be2924c352eda5da14a920551a8b65d5ee89253"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb4363e6c9fc87365c2bc777a1f585a22f2f56642501885ffc7942138499bf54"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:20f724a023042588d0f4396bbbcf4cffd0ddd0ad3ed4f0d8e6d4ac4264bae81e"}, + {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fb4370b15111905bf8b5ba2129b926af9470f014cb0493a67d23e9d7a48348e8"}, + {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23632132f1fd608034f1a56cc3e484be00854db845b3a4a508834be5a6435a6f"}, + {file = "pydantic_core-2.16.1-cp312-none-win32.whl", hash = "sha256:b9f3e0bffad6e238f7acc20c393c1ed8fab4371e3b3bc311020dfa6020d99212"}, + {file = "pydantic_core-2.16.1-cp312-none-win_amd64.whl", hash = "sha256:a0b4cfe408cd84c53bab7d83e4209458de676a6ec5e9c623ae914ce1cb79b96f"}, + {file = "pydantic_core-2.16.1-cp312-none-win_arm64.whl", hash = "sha256:d195add190abccefc70ad0f9a0141ad7da53e16183048380e688b466702195dd"}, + {file = "pydantic_core-2.16.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:502c062a18d84452858f8aea1e520e12a4d5228fc3621ea5061409d666ea1706"}, + {file = "pydantic_core-2.16.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8c032ccee90b37b44e05948b449a2d6baed7e614df3d3f47fe432c952c21b60"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920f4633bee43d7a2818e1a1a788906df5a17b7ab6fe411220ed92b42940f818"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f5d37ff01edcbace53a402e80793640c25798fb7208f105d87a25e6fcc9ea06"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:399166f24c33a0c5759ecc4801f040dbc87d412c1a6d6292b2349b4c505effc9"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac89ccc39cd1d556cc72d6752f252dc869dde41c7c936e86beac5eb555041b66"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73802194f10c394c2bedce7a135ba1d8ba6cff23adf4217612bfc5cf060de34c"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8fa00fa24ffd8c31fac081bf7be7eb495be6d248db127f8776575a746fa55c95"}, + {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:601d3e42452cd4f2891c13fa8c70366d71851c1593ed42f57bf37f40f7dca3c8"}, + {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07982b82d121ed3fc1c51faf6e8f57ff09b1325d2efccaa257dd8c0dd937acca"}, + {file = "pydantic_core-2.16.1-cp38-none-win32.whl", hash = "sha256:d0bf6f93a55d3fa7a079d811b29100b019784e2ee6bc06b0bb839538272a5610"}, + {file = "pydantic_core-2.16.1-cp38-none-win_amd64.whl", hash = "sha256:fbec2af0ebafa57eb82c18c304b37c86a8abddf7022955d1742b3d5471a6339e"}, + {file = "pydantic_core-2.16.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a497be217818c318d93f07e14502ef93d44e6a20c72b04c530611e45e54c2196"}, + {file = "pydantic_core-2.16.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:694a5e9f1f2c124a17ff2d0be613fd53ba0c26de588eb4bdab8bca855e550d95"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d4dfc66abea3ec6d9f83e837a8f8a7d9d3a76d25c9911735c76d6745950e62c"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8655f55fe68c4685673265a650ef71beb2d31871c049c8b80262026f23605ee3"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21e3298486c4ea4e4d5cc6fb69e06fb02a4e22089304308817035ac006a7f506"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71b4a48a7427f14679f0015b13c712863d28bb1ab700bd11776a5368135c7d60"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dca874e35bb60ce4f9f6665bfbfad050dd7573596608aeb9e098621ac331dc"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa496cd45cda0165d597e9d6f01e36c33c9508f75cf03c0a650018c5048f578e"}, + {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5317c04349472e683803da262c781c42c5628a9be73f4750ac7d13040efb5d2d"}, + {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c29d54ed4501a30cd71015bf982fa95e4a60117b44e1a200290ce687d3e640"}, + {file = "pydantic_core-2.16.1-cp39-none-win32.whl", hash = "sha256:ba07646f35e4e49376c9831130039d1b478fbfa1215ae62ad62d2ee63cf9c18f"}, + {file = "pydantic_core-2.16.1-cp39-none-win_amd64.whl", hash = "sha256:2133b0e412a47868a358713287ff9f9a328879da547dc88be67481cdac529118"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d25ef0c33f22649b7a088035fd65ac1ce6464fa2876578df1adad9472f918a76"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99c095457eea8550c9fa9a7a992e842aeae1429dab6b6b378710f62bfb70b394"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b49c604ace7a7aa8af31196abbf8f2193be605db6739ed905ecaf62af31ccae0"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56da23034fe66221f2208c813d8aa509eea34d97328ce2add56e219c3a9f41c"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cebf8d56fee3b08ad40d332a807ecccd4153d3f1ba8231e111d9759f02edfd05"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1ae8048cba95f382dba56766525abca438328455e35c283bb202964f41a780b0"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:780daad9e35b18d10d7219d24bfb30148ca2afc309928e1d4d53de86822593dc"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c94b5537bf6ce66e4d7830c6993152940a188600f6ae044435287753044a8fe2"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:adf28099d061a25fbcc6531febb7a091e027605385de9fe14dd6a97319d614cf"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:644904600c15816a1f9a1bafa6aab0d21db2788abcdf4e2a77951280473f33e1"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bce04f09f0552b66fca0c4e10da78d17cb0e71c205864bab4e9595122cb9d9"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877045a7969ace04d59516d5d6a7dee13106822f99a5d8df5e6822941f7bedc8"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9c46e556ee266ed3fb7b7a882b53df3c76b45e872fdab8d9cf49ae5e91147fd7"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4eebbd049008eb800f519578e944b8dc8e0f7d59a5abb5924cc2d4ed3a1834ff"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c0be58529d43d38ae849a91932391eb93275a06b93b79a8ab828b012e916a206"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b1fc07896fc1851558f532dffc8987e526b682ec73140886c831d773cef44b76"}, + {file = "pydantic_core-2.16.1.tar.gz", hash = "sha256:daff04257b49ab7f4b3f73f98283d3dbb1a65bf3500d55c7beac3c66c310fe34"}, ] [package.dependencies] @@ -622,17 +882,17 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.3" +version = "0.23.4" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.3.tar.gz", hash = "sha256:af313ce900a62fbe2b1aed18e37ad757f1ef9940c6b6a88e2954de38d6b1fb9f"}, - {file = "pytest_asyncio-0.23.3-py3-none-any.whl", hash = "sha256:37a9d912e8338ee7b4a3e917381d1c95bfc8682048cb0fbc35baba316ec1faba"}, + {file = "pytest-asyncio-0.23.4.tar.gz", hash = "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2"}, + {file = "pytest_asyncio-0.23.4-py3-none-any.whl", hash = "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef"}, ] [package.dependencies] -pytest = ">=7.0.0" +pytest = ">=7.0.0,<8" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -658,27 +918,86 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "python-dotenv" -version = "1.0.0" +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.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, - {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, + {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 = "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_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 = "redis" -version = "5.0.1" +version = "4.6.0" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.7" files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, + {file = "redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c"}, + {file = "redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d"}, ] [package.dependencies] @@ -688,6 +1007,22 @@ async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2 hiredis = ["hiredis (>=1.0.0)"] ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] +[[package]] +name = "setuptools" +version = "69.0.3" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "sniffio" version = "1.3.0" @@ -814,6 +1149,35 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "types-pyopenssl" +version = "24.0.0.20240130" +description = "Typing stubs for pyOpenSSL" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-pyOpenSSL-24.0.0.20240130.tar.gz", hash = "sha256:c812e5c1c35249f75ef5935708b2a997d62abf9745be222e5f94b9595472ab25"}, + {file = "types_pyOpenSSL-24.0.0.20240130-py3-none-any.whl", hash = "sha256:24a255458b5b8a7fca8139cf56f2a8ad5a4f1a5f711b73a5bb9cb50dc688fab5"}, +] + +[package.dependencies] +cryptography = ">=35.0.0" + +[[package]] +name = "types-redis" +version = "4.6.0.20240106" +description = "Typing stubs for redis" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-redis-4.6.0.20240106.tar.gz", hash = "sha256:2b2fa3a78f84559616242d23f86de5f4130dfd6c3b83fb2d8ce3329e503f756e"}, + {file = "types_redis-4.6.0.20240106-py3-none-any.whl", hash = "sha256:912de6507b631934bd225cdac310b04a58def94391003ba83939e5a10e99568d"}, +] + +[package.dependencies] +cryptography = ">=35.0.0" +types-pyOpenSSL = "*" + [[package]] name = "typing-extensions" version = "4.9.0" @@ -844,7 +1208,27 @@ typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [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 = "virtualenv" +version = "20.25.0" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "8da16a83882a9b35a5a05441a33e2296b04a5f664dbb090fec0f384c709fb7ef" +content-hash = "106e42984de924817e2dc083ad78699b3411f9aa60de5bb5c1a95ca94a21fda1" diff --git a/postman_scripts/menu app.postman_collection.json b/postman_scripts/menu app.postman_collection.json index f60b345..7898913 100644 --- a/postman_scripts/menu app.postman_collection.json +++ b/postman_scripts/menu app.postman_collection.json @@ -3887,4 +3887,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/postman_scripts/menu app.postman_environment.json b/postman_scripts/menu app.postman_environment.json index f85cfa5..9017bd3 100644 --- a/postman_scripts/menu app.postman_environment.json +++ b/postman_scripts/menu app.postman_environment.json @@ -90,4 +90,4 @@ "_postman_variable_scope": "environment", "_postman_exported_at": "2023-01-12T16:22:10.333Z", "_postman_exported_using": "Postman/10.6.7" -} \ No newline at end of file +} diff --git a/pyproject.toml b/pyproject.toml index 38fa2dd..a9dc80a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,13 +14,16 @@ asyncpg = "^0.29.0" pydantic-settings = "^2.1.0" email-validator = "^2.1.0.post1" pytest-asyncio = "^0.23.3" -redis = "^5.0.1" +redis = "^4.6.0" +types-redis = "^4.6.0.3" +mypy = "^1.4.1" [tool.poetry.group.dev.dependencies] pytest = "^7.4.4" pytest-cov = "^4.1.0" httpx = "^0.26.0" +pre-commit = "^3.6.0" [build-system] requires = ["poetry-core"] diff --git a/tests/conftest.py b/tests/conftest.py index 4ade2b0..c0c253c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ import asyncio -from typing import AsyncGenerator, Dict, Generator +from typing import AsyncGenerator, Generator import pytest import pytest_asyncio @@ -20,7 +20,7 @@ async_session_maker = async_sessionmaker( ) -@pytest.fixture(scope="session", autouse=True) +@pytest.fixture(scope='session', autouse=True) def event_loop(): try: loop = asyncio.get_event_loop() @@ -30,7 +30,7 @@ def event_loop(): loop.close() -@pytest_asyncio.fixture(scope="session", autouse=True) +@pytest_asyncio.fixture(scope='session', autouse=True) async def db_init(event_loop): async with async_engine.begin() as conn: await conn.run_sync(Base.metadata.drop_all) @@ -45,7 +45,7 @@ async def get_test_session() -> AsyncGenerator[AsyncSession, None]: yield session -@pytest.fixture(scope="session") +@pytest.fixture(scope='session') def app(event_loop) -> Generator[FastAPI, None, None]: app: FastAPI = create_app() app.dependency_overrides[get_async_session] = get_test_session @@ -56,11 +56,11 @@ def app(event_loop) -> Generator[FastAPI, None, None]: async def client(app) -> AsyncGenerator[AsyncClient, None]: async with AsyncClient( app=app, - base_url="http://localhost:8000/api/v1/menus", + base_url='http://localhost:8000/api/v1/menus', ) as async_client: yield async_client -@pytest.fixture(scope="session") -def session_data() -> Dict: +@pytest.fixture(scope='session') +def session_data() -> dict: return {} diff --git a/tests/repository.py b/tests/repository.py index 8c1c182..b1c9ce1 100644 --- a/tests/repository.py +++ b/tests/repository.py @@ -1,31 +1,29 @@ -from typing import Tuple - from httpx import AsyncClient, Response class Repository: class Menu: @staticmethod - async def read_all(ac: AsyncClient) -> Tuple[int, dict]: + async def read_all(ac: AsyncClient) -> tuple[int, dict]: """чтение всех меню""" - response: Response = await ac.get("/") + response: Response = await ac.get('/') return response.status_code, response.json() @staticmethod - async def get(ac: AsyncClient, data: dict) -> Tuple[int, dict]: + async def get(ac: AsyncClient, data: dict) -> tuple[int, dict]: """Получение меню по id""" response: Response = await ac.get(f"/{data.get('id')}") return response.status_code, response.json() @staticmethod - async def write(ac: AsyncClient, data: dict) -> Tuple[int, dict]: + async def write(ac: AsyncClient, data: dict) -> tuple[int, dict]: """создания меню""" - response: Response = await ac.post("/", json=data) + response: Response = await ac.post('/', json=data) return response.status_code, response.json() @staticmethod - async def update(ac: AsyncClient, data: dict) -> Tuple[int, dict]: + async def update(ac: AsyncClient, data: dict) -> tuple[int, dict]: """Обновление меню по id""" response: Response = await ac.patch( f"/{data.get('id')}", @@ -41,7 +39,7 @@ class Repository: class Submenu: @staticmethod - async def read_all(ac: AsyncClient, menu: dict) -> Tuple[int, dict]: + async def read_all(ac: AsyncClient, menu: dict) -> tuple[int, dict]: """чтение всех меню""" response: Response = await ac.get(f"/{menu.get('id')}/submenus/") return response.status_code, response.json() @@ -51,7 +49,7 @@ class Repository: ac: AsyncClient, menu: dict, submenu: dict, - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """Получение меню по id""" response: Response = await ac.get( f"/{menu.get('id')}/submenus/{submenu.get('id')}", @@ -63,7 +61,7 @@ class Repository: ac: AsyncClient, menu: dict, submenu: dict, - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """создания меню""" response: Response = await ac.post( f"/{menu.get('id')}/submenus/", @@ -74,7 +72,7 @@ class Repository: @staticmethod async def update( ac: AsyncClient, menu: dict, submenu: dict - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """Обновление меню по id""" response: Response = await ac.patch( f"/{menu.get('id')}/submenus/{submenu.get('id')}", @@ -94,7 +92,7 @@ class Repository: @staticmethod async def read_all( ac: AsyncClient, menu: dict, submenu: dict - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """чтение всех блюд""" response: Response = await ac.get( f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/", @@ -104,7 +102,7 @@ class Repository: @staticmethod async def get( ac: AsyncClient, menu: dict, submenu: dict, dish: dict - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """Получение блюда по id""" response: Response = await ac.get( f"/{menu.get('id')}/submenus/{submenu.get('id')}" @@ -115,7 +113,7 @@ class Repository: @staticmethod async def write( ac: AsyncClient, menu: dict, submenu: dict, dish: dict - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """создания блюда""" response: Response = await ac.post( f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/", @@ -126,7 +124,7 @@ class Repository: @staticmethod async def update( ac: AsyncClient, menu: dict, submenu: dict, dish: dict - ) -> Tuple[int, dict]: + ) -> tuple[int, dict]: """Обновление блюда по id""" response: Response = await ac.patch( f"/{menu.get('id')}/submenus/{submenu.get('id')}" diff --git a/tests/test_api.py b/tests/test_api.py index a13c20e..d57f408 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -15,52 +15,52 @@ async def test_menu_crud_empty(client: AsyncClient) -> None: @pytest.mark.asyncio async def test_menu_crud_add(client: AsyncClient) -> None: """Тестирование функций меню""" - data = {"title": "Menu", "description": None} + data = {'title': 'Menu', 'description': None} code, rspn = await Repo.Menu.write(client, data) assert code == 201 - assert rspn["title"] == "Menu" - assert rspn["description"] is None + assert rspn['title'] == 'Menu' + assert rspn['description'] is None await Repo.Menu.delete(client, rspn) @pytest.mark.asyncio async def test_menu_crud_get(client: AsyncClient) -> None: """Тестирование функций меню""" - data = {"title": "Menu", "description": None} + data = {'title': 'Menu', 'description': None} code, rspn = await Repo.Menu.write(client, data) - code, menu = await Repo.Menu.get(client, {"id": rspn.get("id")}) + code, menu = await Repo.Menu.get(client, {'id': rspn.get('id')}) assert code == 200 - assert menu["title"] == rspn["title"] + assert menu['title'] == rspn['title'] await Repo.Menu.delete(client, menu) @pytest.mark.asyncio async def test_menu_crud_update(client: AsyncClient) -> None: """Тестирование функций меню""" - data = {"title": "Menu", "description": None} + data = {'title': 'Menu', 'description': None} code, rspn = await Repo.Menu.write(client, data) upd_data = { - "id": rspn.get("id"), - "title": "upd Menu", - "description": "", + 'id': rspn.get('id'), + 'title': 'upd Menu', + 'description': '', } code, upd_rspn = await Repo.Menu.update(client, upd_data) assert code == 200 - assert upd_rspn["title"] == "upd Menu" + assert upd_rspn['title'] == 'upd Menu' await Repo.Menu.delete(client, upd_rspn) @pytest.mark.asyncio async def test_menu_crud_delete(client: AsyncClient) -> None: """Тестирование функций меню""" - data = {"title": "Menu", "description": None} + data = {'title': 'Menu', 'description': None} code, rspn = await Repo.Menu.write(client, data) code = await Repo.Menu.delete(client, rspn) assert code == 200 - code, rspn = await Repo.Menu.get(client, {"id": rspn.get("id")}) + code, rspn = await Repo.Menu.get(client, {'id': rspn.get('id')}) assert code == 404 @@ -71,7 +71,7 @@ async def test_menu_crud_get_all(client: AsyncClient) -> None: assert code == 200 assert rspn == [] - data = {"title": "Menu", "description": None} + data = {'title': 'Menu', 'description': None} code, rspn = await Repo.Menu.write(client, data) code, upd_rspn = await Repo.Menu.read_all(client) @@ -83,7 +83,7 @@ async def test_menu_crud_get_all(client: AsyncClient) -> None: @pytest.mark.asyncio async def test_submenus_get_all(client) -> None: # Создаем меню и проверяем ответ - menu = {"title": "Menu", "description": "main menu"} + menu = {'title': 'Menu', 'description': 'main menu'} code, rspn = await Repo.Menu.write(client, menu) assert code == 201 menu.update(rspn) @@ -95,9 +95,9 @@ async def test_submenus_get_all(client) -> None: # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) @@ -115,15 +115,15 @@ async def test_submenus_get_all(client) -> None: @pytest.mark.asyncio async def test_submenus_add(client) -> None: # Создаем меню и проверяем ответ - menu = {"title": "Menu", "description": "main menu"} + menu = {'title': 'Menu', 'description': 'main menu'} code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) assert code == 201 @@ -137,24 +137,24 @@ async def test_submenus_add(client) -> None: @pytest.mark.asyncio async def test_submenus_update(client) -> None: # Создаем меню и проверяем ответ - menu = {"title": "Menu", "description": "main menu"} + menu = {'title': 'Menu', 'description': 'main menu'} code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) # Обновляем подменю и проверяем - submenu["title"] = "updated_submenu" + submenu['title'] = 'updated_submenu' code, rspn = await Repo.Submenu.update(client, menu, submenu) assert code == 200 - assert submenu["title"] == rspn["title"] + assert submenu['title'] == rspn['title'] submenu.update(rspn) # удаляем сопутствующее @@ -165,15 +165,15 @@ async def test_submenus_update(client) -> None: @pytest.mark.asyncio async def test_submenus_delete(client) -> None: # Создаем меню и проверяем ответ - menu = {"title": "Menu", "description": "main menu"} + menu = {'title': 'Menu', 'description': 'main menu'} code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) @@ -194,17 +194,17 @@ async def test_submenus_delete(client) -> None: async def test_dishes_get_all(client: AsyncClient) -> None: # Создаем меню и проверяем ответ menu = { - "title": "Menu", - "description": "main menu", + 'title': 'Menu', + 'description': 'main menu', } code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) @@ -216,10 +216,10 @@ async def test_dishes_get_all(client: AsyncClient) -> None: # Добавляем блюдо dish = { - "title": "dish", - "description": "some dish", - "price": "12.5", - "parent_submenu": submenu["id"], + 'title': 'dish', + 'description': 'some dish', + 'price': '12.5', + 'parent_submenu': submenu['id'], } code, rspn = await Repo.Dish.write(client, menu, submenu, dish) assert code == 201 @@ -239,27 +239,27 @@ async def test_dishes_get_all(client: AsyncClient) -> None: async def test_dishes_add(client: AsyncClient) -> None: # Создаем меню и проверяем ответ menu = { - "title": "Menu", - "description": "main menu", + 'title': 'Menu', + 'description': 'main menu', } code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) # Добавляем блюдо dish = { - "title": "dish", - "description": "some dish", - "price": "12.5", - "parent_submenu": submenu["id"], + 'title': 'dish', + 'description': 'some dish', + 'price': '12.5', + 'parent_submenu': submenu['id'], } code, rspn = await Repo.Dish.write(client, menu, submenu, dish) assert code == 201 @@ -268,7 +268,7 @@ async def test_dishes_add(client: AsyncClient) -> None: # Получаем блюдо code, rspn = await Repo.Dish.get(client, menu, submenu, dish) assert code == 200 - assert rspn["title"] == dish["title"] + assert rspn['title'] == dish['title'] # удаляем сопутствующее await Repo.Dish.delete(client, menu, submenu, dish) @@ -280,36 +280,36 @@ async def test_dishes_add(client: AsyncClient) -> None: async def test_dishes_update(client: AsyncClient) -> None: # Создаем меню и проверяем ответ menu = { - "title": "Menu", - "description": "main menu", + 'title': 'Menu', + 'description': 'main menu', } code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) # Добавляем блюдо dish = { - "title": "dish", - "description": "some dish", - "price": "12.5", - "parent_submenu": submenu["id"], + 'title': 'dish', + 'description': 'some dish', + 'price': '12.5', + 'parent_submenu': submenu['id'], } code, rspn = await Repo.Dish.write(client, menu, submenu, dish) dish.update(rspn) # Обновляем блюдо и проверяем - dish["title"] = "updated_dish" + dish['title'] = 'updated_dish' code, rspn = await Repo.Dish.update(client, menu, submenu, dish) assert code == 200 - assert dish["title"] == rspn["title"] + assert dish['title'] == rspn['title'] dish.update(rspn) # удаляем сопутствующее @@ -322,27 +322,27 @@ async def test_dishes_update(client: AsyncClient) -> None: async def test_dishes_delete(client: AsyncClient) -> None: # Создаем меню и проверяем ответ menu = { - "title": "Menu", - "description": "main menu", + 'title': 'Menu', + 'description': 'main menu', } code, rspn = await Repo.Menu.write(client, menu) menu.update(rspn) # Создаем и проверяем подменю submenu = { - "title": "Submenu", - "description": "submenu", - "parent_menu": menu["id"], + 'title': 'Submenu', + 'description': 'submenu', + 'parent_menu': menu['id'], } code, rspn = await Repo.Submenu.write(client, menu, submenu) submenu.update(rspn) # Добавляем блюдо dish = { - "title": "dish", - "description": "some dish", - "price": "12.5", - "parent_submenu": submenu["id"], + 'title': 'dish', + 'description': 'some dish', + 'price': '12.5', + 'parent_submenu': submenu['id'], } code, rspn = await Repo.Dish.write(client, menu, submenu, dish) dish.update(rspn) diff --git a/tests/test_postman.py b/tests/test_postman.py index f42380e..c507bb1 100644 --- a/tests/test_postman.py +++ b/tests/test_postman.py @@ -1,5 +1,3 @@ -from typing import Dict - import pytest from httpx import AsyncClient @@ -7,160 +5,160 @@ from .repository import Repository as Repo @pytest.mark.asyncio -async def test_01(client: AsyncClient, session_data: Dict): +async def test_01(client: AsyncClient, session_data: dict): """Проверяет создание меню""" - menu = {"title": "Menu", "description": "some_menu_desc"} + menu = {'title': 'Menu', 'description': 'some_menu_desc'} code, rspn = await Repo.Menu.write(client, menu) assert code == 201 code, rspn = await Repo.Menu.get(client, rspn) - session_data["target_menu_id"] = rspn.get("id") - session_data["target_menu_title"] = rspn.get("title") - session_data["target_menu_description"] = rspn.get("description") + session_data['target_menu_id'] = rspn.get('id') + session_data['target_menu_title'] = rspn.get('title') + session_data['target_menu_description'] = rspn.get('description') assert code == 200 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert "submenus_count" in rspn - assert "dishes_count" in rspn - assert rspn["title"] == menu.get("title") - assert rspn.get("description") == menu.get("description") + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert 'submenus_count' in rspn + assert 'dishes_count' in rspn + assert rspn['title'] == menu.get('title') + assert rspn.get('description') == menu.get('description') @pytest.mark.asyncio -async def test_02(client: AsyncClient, session_data: Dict): - submenu = {"title": "Submenu", "description": "submenu_descr"} +async def test_02(client: AsyncClient, session_data: dict): + submenu = {'title': 'Submenu', 'description': 'submenu_descr'} menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } code, rspn = await Repo.Submenu.write(client, menu, submenu) assert code == 201 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert "dishes_count" in rspn - assert rspn["title"] == submenu.get("title") - assert rspn.get("description") == submenu.get("description") + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert 'dishes_count' in rspn + assert rspn['title'] == submenu.get('title') + assert rspn.get('description') == submenu.get('description') - session_data["target_submenu_id"] = rspn.get("id") - session_data["target_submenu_title"] = rspn.get("title") - session_data["target_submenu_description"] = rspn.get("description") + session_data['target_submenu_id'] = rspn.get('id') + session_data['target_submenu_title'] = rspn.get('title') + session_data['target_submenu_description'] = rspn.get('description') @pytest.mark.asyncio -async def test_03_dish1(client: AsyncClient, session_data: Dict): +async def test_03_dish1(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } submenu = { - "id": session_data.get("target_submenu_id"), - "title": session_data.get("target_submenu_title"), - "description": session_data.get("target_submenu_description"), + 'id': session_data.get('target_submenu_id'), + 'title': session_data.get('target_submenu_title'), + 'description': session_data.get('target_submenu_description'), } - dish = {"title": "dish_1", "description": "dish 1 descr", "price": "12.5"} + dish = {'title': 'dish_1', 'description': 'dish 1 descr', 'price': '12.5'} code, rspn = await Repo.Dish.write(client, menu, submenu, dish) assert code == 201 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert "price" in rspn - assert rspn["title"] == dish.get("title") - assert rspn.get("description") == dish.get("description") - assert rspn.get("price") == dish.get("price") + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert 'price' in rspn + assert rspn['title'] == dish.get('title') + assert rspn.get('description') == dish.get('description') + assert rspn.get('price') == dish.get('price') - session_data["target_dish_id"] = rspn.get("id") - session_data["target_dish_title"] = rspn.get("title") - session_data["target_dish_description"] = rspn.get("description") - session_data["target_dish_price"] = rspn.get("price") + session_data['target_dish_id'] = rspn.get('id') + session_data['target_dish_title'] = rspn.get('title') + session_data['target_dish_description'] = rspn.get('description') + session_data['target_dish_price'] = rspn.get('price') @pytest.mark.asyncio -async def test_04_dish2(client: AsyncClient, session_data: Dict): +async def test_04_dish2(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } submenu = { - "id": session_data.get("target_submenu_id"), - "title": session_data.get("target_submenu_title"), - "description": session_data.get("target_submenu_description"), + 'id': session_data.get('target_submenu_id'), + 'title': session_data.get('target_submenu_title'), + 'description': session_data.get('target_submenu_description'), } - dish = {"title": "dish_2", "description": "dish 2 descr", "price": "13.5"} + dish = {'title': 'dish_2', 'description': 'dish 2 descr', 'price': '13.5'} code, rspn = await Repo.Dish.write(client, menu, submenu, dish) assert code == 201 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert "price" in rspn - assert rspn["title"] == dish.get("title") - assert rspn.get("description") == dish.get("description") - assert rspn.get("price") == dish.get("price") + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert 'price' in rspn + assert rspn['title'] == dish.get('title') + assert rspn.get('description') == dish.get('description') + assert rspn.get('price') == dish.get('price') - session_data["target_dish1_id"] = rspn.get("id") - session_data["target_dish1_title"] = rspn.get("title") - session_data["target_dish1_description"] = rspn.get("description") - session_data["target_dish1_price"] = rspn.get("price") + session_data['target_dish1_id'] = rspn.get('id') + session_data['target_dish1_title'] = rspn.get('title') + session_data['target_dish1_description'] = rspn.get('description') + session_data['target_dish1_price'] = rspn.get('price') @pytest.mark.asyncio -async def test_05_check_menu(client: AsyncClient, session_data: Dict): +async def test_05_check_menu(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } code, rspn = await Repo.Menu.get(client, menu) assert code == 200 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert rspn.get("submenus_count") == 1 - assert rspn.get("dishes_count") == 2 + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert rspn.get('submenus_count') == 1 + assert rspn.get('dishes_count') == 2 @pytest.mark.asyncio -async def test_06_check_submenu(client: AsyncClient, session_data: Dict): +async def test_06_check_submenu(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } submenu = { - "id": session_data.get("target_submenu_id"), - "title": session_data.get("target_submenu_title"), - "description": session_data.get("target_submenu_description"), + 'id': session_data.get('target_submenu_id'), + 'title': session_data.get('target_submenu_title'), + 'description': session_data.get('target_submenu_description'), } code, rspn = await Repo.Submenu.get(client, menu, submenu) assert code == 200 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert rspn.get("dishes_count") == 2 + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert rspn.get('dishes_count') == 2 @pytest.mark.asyncio -async def test_07_del_submenu(client: AsyncClient, session_data: Dict): +async def test_07_del_submenu(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } submenu = { - "id": session_data.get("target_submenu_id"), - "title": session_data.get("target_submenu_title"), - "description": session_data.get("target_submenu_description"), + 'id': session_data.get('target_submenu_id'), + 'title': session_data.get('target_submenu_title'), + 'description': session_data.get('target_submenu_description'), } code = await Repo.Submenu.delete(client, menu, submenu) @@ -168,11 +166,11 @@ async def test_07_del_submenu(client: AsyncClient, session_data: Dict): @pytest.mark.asyncio -async def test_07_check_submenus(client: AsyncClient, session_data: Dict): +async def test_07_check_submenus(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } code, rspn = await Repo.Submenu.read_all(client, menu) @@ -181,16 +179,16 @@ async def test_07_check_submenus(client: AsyncClient, session_data: Dict): @pytest.mark.asyncio -async def test_08_check_dishes(client: AsyncClient, session_data: Dict): +async def test_08_check_dishes(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } submenu = { - "id": session_data.get("target_submenu_id"), - "title": session_data.get("target_submenu_title"), - "description": session_data.get("target_submenu_description"), + 'id': session_data.get('target_submenu_id'), + 'title': session_data.get('target_submenu_title'), + 'description': session_data.get('target_submenu_description'), } code, rspn = await Repo.Dish.read_all(client, menu, submenu) @@ -199,28 +197,28 @@ async def test_08_check_dishes(client: AsyncClient, session_data: Dict): @pytest.mark.asyncio -async def test_09_check_menu(client: AsyncClient, session_data: Dict): +async def test_09_check_menu(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } code, rspn = await Repo.Menu.get(client, menu) assert code == 200 - assert "id" in rspn - assert "title" in rspn - assert "description" in rspn - assert rspn.get("submenus_count") == 0 - assert rspn.get("dishes_count") == 0 + assert 'id' in rspn + assert 'title' in rspn + assert 'description' in rspn + assert rspn.get('submenus_count') == 0 + assert rspn.get('dishes_count') == 0 @pytest.mark.asyncio -async def test_10_del_menu(client: AsyncClient, session_data: Dict): +async def test_10_del_menu(client: AsyncClient, session_data: dict): menu = { - "id": session_data.get("target_menu_id"), - "title": session_data.get("target_menu_title"), - "description": session_data.get("target_menu_description"), + 'id': session_data.get('target_menu_id'), + 'title': session_data.get('target_menu_title'), + 'description': session_data.get('target_menu_description'), } code = await Repo.Menu.delete(client, menu) @@ -228,7 +226,7 @@ async def test_10_del_menu(client: AsyncClient, session_data: Dict): @pytest.mark.asyncio -async def test_11_check_menus(client: AsyncClient, session_data: Dict): +async def test_11_check_menus(client: AsyncClient, session_data: dict): code, rspn = await Repo.Menu.read_all(client) assert code == 200