add .pre-commit-config.yaml Поправил проблемы

develop
Сергей Ванюшкин 2024-02-03 01:08:04 +03:00
parent 0ba422397a
commit f667026d62
29 changed files with 893 additions and 466 deletions

1
.gitignore vendored
View File

@ -217,4 +217,3 @@ fabric.properties
# Android studio 3.1+ serialized cache file # Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser .idea/caches/build_file_checksums.ser

50
.pre-commit-config.yaml Normal file
View File

@ -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'

View File

@ -165,5 +165,3 @@ Fastapi веб приложение реализующее api для общеп
## Лицензия ## Лицензия
Распространяется под [MIT лицензией](https://mit-license.org/). Распространяется под [MIT лицензией](https://mit-license.org/).

View File

@ -42,4 +42,3 @@ services:
restart: always restart: always
command: /bin/bash -c 'poetry run python /usr/src/fastfood/manage.py --run-test-server' command: /bin/bash -c 'poetry run python /usr/src/fastfood/manage.py --run-test-server'

View File

@ -42,4 +42,3 @@ services:
restart: always restart: always
command: /bin/bash -c 'poetry run pytest -vv' command: /bin/bash -c 'poetry run pytest -vv'

View File

@ -50,14 +50,14 @@ description = """
tags_metadata = [ tags_metadata = [
{ {
"name": "menu", 'name': 'menu',
"description": "Операции с меню.", 'description': 'Операции с меню.',
}, },
{ {
"name": "submenu", 'name': 'submenu',
"description": "Подменю и работа с ним", 'description': 'Подменю и работа с ним',
}, },
{"name": "dish", "description": "Блюда и работа с ними"}, {'name': 'dish', 'description': 'Блюда и работа с ними'},
] ]
@ -66,17 +66,17 @@ def create_app(redis=None) -> FastAPI:
Фабрика FastAPI. Фабрика FastAPI.
""" """
app = FastAPI( app = FastAPI(
title="Fastfood-API", title='Fastfood-API',
description=description, description=description,
version="0.0.1", version='0.0.1',
contact={ contact={
"name": "Sergey Vanyushkin", 'name': 'Sergey Vanyushkin',
"url": "http://pi3c.ru", 'url': 'http://pi3c.ru',
"email": "pi3c@yandex.ru", 'email': 'pi3c@yandex.ru',
}, },
license_info={ license_info={
"name": "MIT license", 'name': 'MIT license',
"url": "https://mit-license.org/", 'url': 'https://mit-license.org/',
}, },
openapi_tags=tags_metadata, openapi_tags=tags_metadata,
) )

View File

@ -2,13 +2,13 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings): class Settings(BaseSettings):
DB_HOST: str = "" DB_HOST: str = ''
DB_PORT: int = 5432 DB_PORT: int = 5432
POSTGRES_DB: str = "" POSTGRES_DB: str = ''
POSTGRES_PASSWORD: str = "" POSTGRES_PASSWORD: str = ''
POSTGRES_USER: str = "" POSTGRES_USER: str = ''
POSTGRES_DB_TEST: str = "" POSTGRES_DB_TEST: str = ''
REDIS_DB: str = "" REDIS_DB: str = ''
@property @property
def DATABASE_URL_asyncpg(self): def DATABASE_URL_asyncpg(self):
@ -16,9 +16,9 @@ class Settings(BaseSettings):
Возвращает строку подключения к БД необходимую для SQLAlchemy Возвращает строку подключения к БД необходимую для SQLAlchemy
""" """
return ( return (
"postgresql+asyncpg://" 'postgresql+asyncpg://'
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}" f'{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}'
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}" f'@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}'
) )
@property @property
@ -27,12 +27,12 @@ class Settings(BaseSettings):
Возвращает строку подключения к БД необходимую для SQLAlchemy Возвращает строку подключения к БД необходимую для SQLAlchemy
""" """
return ( return (
"postgresql+asyncpg://" 'postgresql+asyncpg://'
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}" f'{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}'
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB_TEST}" 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() settings = Settings()

View File

@ -1,6 +1,6 @@
from typing import AsyncGenerator from typing import AsyncGenerator
import redis.asyncio as redis import redis.asyncio as redis # type: ignore
from fastapi import Depends from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine

View File

@ -1,6 +1,6 @@
import uuid import uuid
from copy import deepcopy from copy import deepcopy
from typing import Annotated, List, Optional from typing import Annotated
from sqlalchemy import ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
@ -21,13 +21,13 @@ str_25 = Annotated[str, 25]
class Base(DeclarativeBase): class Base(DeclarativeBase):
id: Mapped[uuidpk] id: Mapped[uuidpk]
title: Mapped[str_25] title: Mapped[str_25]
description: Mapped[Optional[str]] description: Mapped[str | None]
def __eq__(self, other): def __eq__(self, other):
classes_match = isinstance(other, self.__class__) classes_match = isinstance(other, self.__class__)
a, b = deepcopy(self.__dict__), deepcopy(other.__dict__) a, b = deepcopy(self.__dict__), deepcopy(other.__dict__)
a.pop("_sa_instance_state", None) a.pop('_sa_instance_state', None)
b.pop("_sa_instance_state", None) b.pop('_sa_instance_state', None)
attrs_match = a == b attrs_match = a == b
return classes_match and attrs_match return classes_match and attrs_match
@ -36,13 +36,13 @@ class Base(DeclarativeBase):
class Menu(Base): class Menu(Base):
__tablename__ = "menu" __tablename__ = 'menu'
submenus: Mapped[List["SubMenu"]] = relationship( submenus: Mapped[list['SubMenu']] = relationship(
"SubMenu", 'SubMenu',
backref="menu", backref='menu',
lazy="selectin", lazy='selectin',
cascade="all, delete", cascade='all, delete',
) )
@hybridproperty @hybridproperty
@ -58,16 +58,16 @@ class Menu(Base):
class SubMenu(Base): class SubMenu(Base):
__tablename__ = "submenu" __tablename__ = 'submenu'
parent_menu: Mapped[uuid.UUID] = mapped_column( parent_menu: Mapped[uuid.UUID] = mapped_column(
ForeignKey("menu.id", ondelete="CASCADE") ForeignKey('menu.id', ondelete='CASCADE')
) )
dishes: Mapped[List["Dish"]] = relationship( dishes: Mapped[list['Dish']] = relationship(
"Dish", 'Dish',
backref="submenu", backref='submenu',
lazy="selectin", lazy='selectin',
cascade="all, delete", cascade='all, delete',
) )
@hybridproperty @hybridproperty
@ -76,9 +76,9 @@ class SubMenu(Base):
class Dish(Base): class Dish(Base):
__tablename__ = "dish" __tablename__ = 'dish'
price: Mapped[float] price: Mapped[float]
parent_submenu: Mapped[uuid.UUID] = mapped_column( parent_submenu: Mapped[uuid.UUID] = mapped_column(
ForeignKey("submenu.id", ondelete="CASCADE") ForeignKey('submenu.id', ondelete='CASCADE')
) )

View File

@ -33,8 +33,8 @@ class MenuRepository:
query = ( query = (
select( select(
m, m,
func.count(distinct(s.id)).label("submenus_count"), func.count(distinct(s.id)).label('submenus_count'),
func.count(distinct(d.id)).label("dishes_count"), func.count(distinct(d.id)).label('dishes_count'),
) )
.join(s, s.parent_menu == m.id, isouter=True) .join(s, s.parent_menu == m.id, isouter=True)
.join(d, d.parent_submenu == s.id, isouter=True) .join(d, d.parent_submenu == s.id, isouter=True)

View File

@ -1,6 +1,6 @@
from typing import Any from typing import Any
import redis.asyncio as redis import redis.asyncio as redis # type: ignore
from fastapi import BackgroundTasks, Depends from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_redis_pool from fastfood.dbase import get_redis_pool

View File

@ -40,7 +40,7 @@ class SubMenuRepository:
s = aliased(models.SubMenu) s = aliased(models.SubMenu)
d = aliased(models.Dish) d = aliased(models.Dish)
query = ( 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) .join(d, s.id == d.parent_submenu, isouter=True)
.group_by(s.id) .group_by(s.id)
.where(s.id == submenu_id) .where(s.id == submenu_id)

View File

@ -7,12 +7,12 @@ from fastfood.service.dish import DishService
from fastfood.utils import price_converter from fastfood.utils import price_converter
router = APIRouter( router = APIRouter(
prefix="/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes", prefix='/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes',
tags=["dish"], tags=['dish'],
) )
@router.get("/") @router.get('/')
async def get_dishes( async def get_dishes(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
@ -23,7 +23,7 @@ async def get_dishes(
return result return result
@router.post("/", status_code=201) @router.post('/', status_code=201)
async def create_dish( async def create_dish(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
@ -39,7 +39,7 @@ async def create_dish(
return price_converter(result) return price_converter(result)
@router.get("/{dish_id}") @router.get('/{dish_id}')
async def get_dish( async def get_dish(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
@ -53,11 +53,11 @@ async def get_dish(
dish_id, dish_id,
) )
if not result: 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) return price_converter(result)
@router.patch("/{dish_id}") @router.patch('/{dish_id}')
async def update_dish( async def update_dish(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
@ -75,7 +75,7 @@ async def update_dish(
return price_converter(result) return price_converter(result)
@router.delete("/{dish_id}") @router.delete('/{dish_id}')
async def delete_dish( async def delete_dish(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,

View File

@ -1,4 +1,4 @@
from typing import List, Optional from typing import Optional
from uuid import UUID from uuid import UUID
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
@ -7,12 +7,12 @@ from fastfood.schemas import Menu, MenuBase, MenuRead
from fastfood.service.menu import MenuService from fastfood.service.menu import MenuService
router = APIRouter( router = APIRouter(
prefix="/api/v1/menus", prefix='/api/v1/menus',
tags=["menu"], tags=['menu'],
) )
@router.get("/", response_model=Optional[List[Menu]]) @router.get('/', response_model=Optional[list[Menu]])
async def get_menus( async def get_menus(
menu: MenuService = Depends(), menu: MenuService = Depends(),
background_tasks: BackgroundTasks = BackgroundTasks(), background_tasks: BackgroundTasks = BackgroundTasks(),
@ -20,7 +20,7 @@ async def get_menus(
return await menu.read_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( async def add_menu(
menu: MenuBase, menu: MenuBase,
responce: MenuService = Depends(), responce: MenuService = Depends(),
@ -29,7 +29,7 @@ async def add_menu(
return await responce.create_menu(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( async def get_menu(
menu_id: UUID, menu_id: UUID,
responce: MenuService = Depends(), responce: MenuService = Depends(),
@ -38,11 +38,11 @@ async def get_menu(
result = await responce.read_menu(menu_id=menu_id) result = await responce.read_menu(menu_id=menu_id)
if not result: if not result:
raise HTTPException(status_code=404, detail="menu not found") raise HTTPException(status_code=404, detail='menu not found')
return result return result
@router.patch("/{menu_id}", response_model=MenuRead) @router.patch('/{menu_id}', response_model=MenuRead)
async def update_menu( async def update_menu(
menu_id: UUID, menu_id: UUID,
menu: MenuBase, menu: MenuBase,
@ -56,7 +56,7 @@ async def update_menu(
return result.scalars().one() return result.scalars().one()
@router.delete("/{menu_id}") @router.delete('/{menu_id}')
async def delete_menu( async def delete_menu(
menu_id: UUID, menu_id: UUID,
menu: MenuService = Depends(), menu: MenuService = Depends(),

View File

@ -1,4 +1,4 @@
from typing import List, Optional from typing import Optional
from uuid import UUID from uuid import UUID
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
@ -7,12 +7,12 @@ from fastfood.schemas import MenuBase, SubMenuRead
from fastfood.service.submenu import SubmenuService from fastfood.service.submenu import SubmenuService
router = APIRouter( router = APIRouter(
prefix="/api/v1/menus/{menu_id}/submenus", prefix='/api/v1/menus/{menu_id}/submenus',
tags=["submenu"], tags=['submenu'],
) )
@router.get("/", response_model=Optional[List[SubMenuRead]]) @router.get('/', response_model=Optional[list[SubMenuRead]])
async def get_submenus( async def get_submenus(
menu_id: UUID, menu_id: UUID,
submenu: SubmenuService = Depends(), submenu: SubmenuService = Depends(),
@ -22,7 +22,7 @@ async def get_submenus(
return result.scalars().all() 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( async def create_submenu_item(
menu_id: UUID, menu_id: UUID,
submenu_data: MenuBase, submenu_data: MenuBase,
@ -36,7 +36,7 @@ async def create_submenu_item(
return result return result
@router.get("/{submenu_id}", response_model=SubMenuRead) @router.get('/{submenu_id}', response_model=SubMenuRead)
async def get_submenu( async def get_submenu(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
@ -48,12 +48,12 @@ async def get_submenu(
submenu_id=submenu_id, submenu_id=submenu_id,
) )
if not result: if not result:
raise HTTPException(status_code=404, detail="submenu not found") raise HTTPException(status_code=404, detail='submenu not found')
return result return result
@router.patch( @router.patch(
"/{submenu_id}", '/{submenu_id}',
response_model=MenuBase, response_model=MenuBase,
) )
async def update_submenu( async def update_submenu(
@ -71,7 +71,7 @@ async def update_submenu(
return result.scalars().one() return result.scalars().one()
@router.delete("/{submenu_id}") @router.delete('/{submenu_id}')
async def delete_submenu( async def delete_submenu(
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,

View File

@ -1,4 +1,3 @@
from typing import Optional
from uuid import UUID from uuid import UUID
from pydantic import BaseModel from pydantic import BaseModel
@ -6,7 +5,7 @@ from pydantic import BaseModel
class MenuBase(BaseModel): class MenuBase(BaseModel):
title: str title: str
description: Optional[str] description: str | None
class Config: class Config:
from_attributes = True from_attributes = True

View File

@ -1,6 +1,6 @@
from uuid import UUID from uuid import UUID
import redis.asyncio as redis import redis.asyncio as redis # type: ignore
from fastapi import BackgroundTasks, Depends from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_async_redis_client from fastfood.dbase import get_async_redis_client

View File

@ -1,6 +1,6 @@
from uuid import UUID from uuid import UUID
import redis.asyncio as redis import redis.asyncio as redis # type: ignore
from fastapi import BackgroundTasks, Depends from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_async_redis_client from fastfood.dbase import get_async_redis_client

View File

@ -1,6 +1,6 @@
from uuid import UUID from uuid import UUID
import redis.asyncio as redis import redis.asyncio as redis # type: ignore
from fastapi import BackgroundTasks, Depends from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_async_redis_client from fastfood.dbase import get_async_redis_client

View File

@ -1,3 +1,3 @@
def price_converter(dish: dict) -> dict: def price_converter(dish: dict) -> dict:
dish.price = str(dish.price) dish['price'] = str(dish['price'])
return dish return dish

View File

@ -11,8 +11,8 @@ def run_app():
Запуск FastAPI Запуск FastAPI
""" """
uvicorn.run( uvicorn.run(
app="fastfood.app:create_app", app='fastfood.app:create_app',
host="0.0.0.0", host='0.0.0.0',
port=8000, port=8000,
reload=True, reload=True,
factory=True, factory=True,
@ -25,10 +25,10 @@ async def recreate():
await create_db_and_tables() await create_db_and_tables()
if __name__ == "__main__": if __name__ == '__main__':
if "--run-server" in sys.argv: if '--run-server' in sys.argv:
run_app() run_app()
if "--run-test-server" in sys.argv: if '--run-test-server' in sys.argv:
asyncio.run(recreate()) asyncio.run(recreate())
run_app() run_app()

642
poetry.lock generated
View File

@ -103,13 +103,88 @@ test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"]
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2023.11.17" version = "2024.2.2"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"},
{file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, {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]] [[package]]
@ -204,6 +279,71 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1
[package.extras] [package.extras]
toml = ["tomli"] 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]] [[package]]
name = "dnspython" name = "dnspython"
version = "2.5.0" version = "2.5.0"
@ -272,6 +412,22 @@ typing-extensions = ">=4.8.0"
[package.extras] [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)"] 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]] [[package]]
name = "greenlet" name = "greenlet"
version = "3.0.3" version = "3.0.3"
@ -399,6 +555,20 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"] http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"] 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]] [[package]]
name = "idna" name = "idna"
version = "3.6" version = "3.6"
@ -421,6 +591,78 @@ files = [
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, {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]] [[package]]
name = "packaging" name = "packaging"
version = "23.2" version = "23.2"
@ -432,35 +674,79 @@ files = [
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, {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]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.3.0" version = "1.4.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"},
{file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"},
] ]
[package.extras] [package.extras]
dev = ["pre-commit", "tox"] dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"] 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]] [[package]]
name = "pydantic" name = "pydantic"
version = "2.5.3" version = "2.6.0"
description = "Data validation using Python type hints" description = "Data validation using Python type hints"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, {file = "pydantic-2.6.0-py3-none-any.whl", hash = "sha256:1440966574e1b5b99cf75a13bec7b20e3512e8a61b894ae252f56275e2c465ae"},
{file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, {file = "pydantic-2.6.0.tar.gz", hash = "sha256:ae887bd94eb404b09d86e4d12f93893bdca79d766e738528c6fa1c849f3c6bcf"},
] ]
[package.dependencies] [package.dependencies]
annotated-types = ">=0.4.0" annotated-types = ">=0.4.0"
pydantic-core = "2.14.6" pydantic-core = "2.16.1"
typing-extensions = ">=4.6.1" typing-extensions = ">=4.6.1"
[package.extras] [package.extras]
@ -468,116 +754,90 @@ email = ["email-validator (>=2.0.0)"]
[[package]] [[package]]
name = "pydantic-core" name = "pydantic-core"
version = "2.14.6" version = "2.16.1"
description = "" description = ""
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, {file = "pydantic_core-2.16.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:300616102fb71241ff477a2cbbc847321dbec49428434a2f17f37528721c4948"},
{file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, {file = "pydantic_core-2.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5511f962dd1b9b553e9534c3b9c6a4b0c9ded3d8c2be96e61d56f933feef9e1f"},
{file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98f0edee7ee9cc7f9221af2e1b95bd02810e1c7a6d115cfd82698803d385b28f"},
{file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9795f56aa6b2296f05ac79d8a424e94056730c0b860a62b0fdcfe6340b658cc8"},
{file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c45f62e4107ebd05166717ac58f6feb44471ed450d07fecd90e5f69d9bf03c48"},
{file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462d599299c5971f03c676e2b63aa80fec5ebc572d89ce766cd11ca8bcb56f3f"},
{file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ebaa4bf6386a3b22eec518da7d679c8363fb7fb70cf6972161e5542f470798"},
{file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:99f9a50b56713a598d33bc23a9912224fc5d7f9f292444e6664236ae471ddf17"},
{file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8ec364e280db4235389b5e1e6ee924723c693cbc98e9d28dc1767041ff9bc388"},
{file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:653a5dfd00f601a0ed6654a8b877b18d65ac32c9d9997456e0ab240807be6cf7"},
{file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, {file = "pydantic_core-2.16.1-cp310-none-win32.whl", hash = "sha256:1661c668c1bb67b7cec96914329d9ab66755911d093bb9063c4c8914188af6d4"},
{file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, {file = "pydantic_core-2.16.1-cp310-none-win_amd64.whl", hash = "sha256:561be4e3e952c2f9056fba5267b99be4ec2afadc27261505d4992c50b33c513c"},
{file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, {file = "pydantic_core-2.16.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:102569d371fadc40d8f8598a59379c37ec60164315884467052830b28cc4e9da"},
{file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, {file = "pydantic_core-2.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:735dceec50fa907a3c314b84ed609dec54b76a814aa14eb90da31d1d36873a5e"},
{file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e83ebbf020be727d6e0991c1b192a5c2e7113eb66e3def0cd0c62f9f266247e4"},
{file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:30a8259569fbeec49cfac7fda3ec8123486ef1b729225222f0d41d5f840b476f"},
{file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920c4897e55e2881db6a6da151198e5001552c3777cd42b8a4c2f72eedc2ee91"},
{file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5247a3d74355f8b1d780d0f3b32a23dd9f6d3ff43ef2037c6dcd249f35ecf4c"},
{file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5bea8012df5bb6dda1e67d0563ac50b7f64a5d5858348b5c8cb5043811c19d"},
{file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ed3025a8a7e5a59817b7494686d449ebfbe301f3e757b852c8d0d1961d6be864"},
{file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06f0d5a1d9e1b7932477c172cc720b3b23c18762ed7a8efa8398298a59d177c7"},
{file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:150ba5c86f502c040b822777e2e519b5625b47813bd05f9273a8ed169c97d9ae"},
{file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, {file = "pydantic_core-2.16.1-cp311-none-win32.whl", hash = "sha256:d6cbdf12ef967a6aa401cf5cdf47850559e59eedad10e781471c960583f25aa1"},
{file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, {file = "pydantic_core-2.16.1-cp311-none-win_amd64.whl", hash = "sha256:afa01d25769af33a8dac0d905d5c7bb2d73c7c3d5161b2dd6f8b5b5eea6a3c4c"},
{file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, {file = "pydantic_core-2.16.1-cp311-none-win_arm64.whl", hash = "sha256:1a2fe7b00a49b51047334d84aafd7e39f80b7675cad0083678c58983662da89b"},
{file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, {file = "pydantic_core-2.16.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f478ec204772a5c8218e30eb813ca43e34005dff2eafa03931b3d8caef87d51"},
{file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, {file = "pydantic_core-2.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1936ef138bed2165dd8573aa65e3095ef7c2b6247faccd0e15186aabdda7f66"},
{file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99d3a433ef5dc3021c9534a58a3686c88363c591974c16c54a01af7efd741f13"},
{file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd88f40f2294440d3f3c6308e50d96a0d3d0973d6f1a5732875d10f569acef49"},
{file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fac641bbfa43d5a1bed99d28aa1fded1984d31c670a95aac1bf1d36ac6ce137"},
{file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72bf9308a82b75039b8c8edd2be2924c352eda5da14a920551a8b65d5ee89253"},
{file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb4363e6c9fc87365c2bc777a1f585a22f2f56642501885ffc7942138499bf54"},
{file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:20f724a023042588d0f4396bbbcf4cffd0ddd0ad3ed4f0d8e6d4ac4264bae81e"},
{file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fb4370b15111905bf8b5ba2129b926af9470f014cb0493a67d23e9d7a48348e8"},
{file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23632132f1fd608034f1a56cc3e484be00854db845b3a4a508834be5a6435a6f"},
{file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, {file = "pydantic_core-2.16.1-cp312-none-win32.whl", hash = "sha256:b9f3e0bffad6e238f7acc20c393c1ed8fab4371e3b3bc311020dfa6020d99212"},
{file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, {file = "pydantic_core-2.16.1-cp312-none-win_amd64.whl", hash = "sha256:a0b4cfe408cd84c53bab7d83e4209458de676a6ec5e9c623ae914ce1cb79b96f"},
{file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, {file = "pydantic_core-2.16.1-cp312-none-win_arm64.whl", hash = "sha256:d195add190abccefc70ad0f9a0141ad7da53e16183048380e688b466702195dd"},
{file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, {file = "pydantic_core-2.16.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:502c062a18d84452858f8aea1e520e12a4d5228fc3621ea5061409d666ea1706"},
{file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, {file = "pydantic_core-2.16.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8c032ccee90b37b44e05948b449a2d6baed7e614df3d3f47fe432c952c21b60"},
{file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920f4633bee43d7a2818e1a1a788906df5a17b7ab6fe411220ed92b42940f818"},
{file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f5d37ff01edcbace53a402e80793640c25798fb7208f105d87a25e6fcc9ea06"},
{file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:399166f24c33a0c5759ecc4801f040dbc87d412c1a6d6292b2349b4c505effc9"},
{file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac89ccc39cd1d556cc72d6752f252dc869dde41c7c936e86beac5eb555041b66"},
{file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73802194f10c394c2bedce7a135ba1d8ba6cff23adf4217612bfc5cf060de34c"},
{file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8fa00fa24ffd8c31fac081bf7be7eb495be6d248db127f8776575a746fa55c95"},
{file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:601d3e42452cd4f2891c13fa8c70366d71851c1593ed42f57bf37f40f7dca3c8"},
{file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07982b82d121ed3fc1c51faf6e8f57ff09b1325d2efccaa257dd8c0dd937acca"},
{file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, {file = "pydantic_core-2.16.1-cp38-none-win32.whl", hash = "sha256:d0bf6f93a55d3fa7a079d811b29100b019784e2ee6bc06b0bb839538272a5610"},
{file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, {file = "pydantic_core-2.16.1-cp38-none-win_amd64.whl", hash = "sha256:fbec2af0ebafa57eb82c18c304b37c86a8abddf7022955d1742b3d5471a6339e"},
{file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, {file = "pydantic_core-2.16.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a497be217818c318d93f07e14502ef93d44e6a20c72b04c530611e45e54c2196"},
{file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, {file = "pydantic_core-2.16.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:694a5e9f1f2c124a17ff2d0be613fd53ba0c26de588eb4bdab8bca855e550d95"},
{file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d4dfc66abea3ec6d9f83e837a8f8a7d9d3a76d25c9911735c76d6745950e62c"},
{file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8655f55fe68c4685673265a650ef71beb2d31871c049c8b80262026f23605ee3"},
{file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21e3298486c4ea4e4d5cc6fb69e06fb02a4e22089304308817035ac006a7f506"},
{file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71b4a48a7427f14679f0015b13c712863d28bb1ab700bd11776a5368135c7d60"},
{file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dca874e35bb60ce4f9f6665bfbfad050dd7573596608aeb9e098621ac331dc"},
{file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa496cd45cda0165d597e9d6f01e36c33c9508f75cf03c0a650018c5048f578e"},
{file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5317c04349472e683803da262c781c42c5628a9be73f4750ac7d13040efb5d2d"},
{file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c29d54ed4501a30cd71015bf982fa95e4a60117b44e1a200290ce687d3e640"},
{file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, {file = "pydantic_core-2.16.1-cp39-none-win32.whl", hash = "sha256:ba07646f35e4e49376c9831130039d1b478fbfa1215ae62ad62d2ee63cf9c18f"},
{file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, {file = "pydantic_core-2.16.1-cp39-none-win_amd64.whl", hash = "sha256:2133b0e412a47868a358713287ff9f9a328879da547dc88be67481cdac529118"},
{file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d25ef0c33f22649b7a088035fd65ac1ce6464fa2876578df1adad9472f918a76"},
{file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99c095457eea8550c9fa9a7a992e842aeae1429dab6b6b378710f62bfb70b394"},
{file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b49c604ace7a7aa8af31196abbf8f2193be605db6739ed905ecaf62af31ccae0"},
{file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, {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.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cebf8d56fee3b08ad40d332a807ecccd4153d3f1ba8231e111d9759f02edfd05"},
{file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1ae8048cba95f382dba56766525abca438328455e35c283bb202964f41a780b0"},
{file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:780daad9e35b18d10d7219d24bfb30148ca2afc309928e1d4d53de86822593dc"},
{file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c94b5537bf6ce66e4d7830c6993152940a188600f6ae044435287753044a8fe2"},
{file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:adf28099d061a25fbcc6531febb7a091e027605385de9fe14dd6a97319d614cf"},
{file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:644904600c15816a1f9a1bafa6aab0d21db2788abcdf4e2a77951280473f33e1"},
{file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bce04f09f0552b66fca0c4e10da78d17cb0e71c205864bab4e9595122cb9d9"},
{file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, {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.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9c46e556ee266ed3fb7b7a882b53df3c76b45e872fdab8d9cf49ae5e91147fd7"},
{file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4eebbd049008eb800f519578e944b8dc8e0f7d59a5abb5924cc2d4ed3a1834ff"},
{file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c0be58529d43d38ae849a91932391eb93275a06b93b79a8ab828b012e916a206"},
{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.16.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b1fc07896fc1851558f532dffc8987e526b682ec73140886c831d773cef44b76"},
{file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, {file = "pydantic_core-2.16.1.tar.gz", hash = "sha256:daff04257b49ab7f4b3f73f98283d3dbb1a65bf3500d55c7beac3c66c310fe34"},
{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"},
] ]
[package.dependencies] [package.dependencies]
@ -622,17 +882,17 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no
[[package]] [[package]]
name = "pytest-asyncio" name = "pytest-asyncio"
version = "0.23.3" version = "0.23.4"
description = "Pytest support for asyncio" description = "Pytest support for asyncio"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pytest-asyncio-0.23.3.tar.gz", hash = "sha256:af313ce900a62fbe2b1aed18e37ad757f1ef9940c6b6a88e2954de38d6b1fb9f"}, {file = "pytest-asyncio-0.23.4.tar.gz", hash = "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2"},
{file = "pytest_asyncio-0.23.3-py3-none-any.whl", hash = "sha256:37a9d912e8338ee7b4a3e917381d1c95bfc8682048cb0fbc35baba316ec1faba"}, {file = "pytest_asyncio-0.23.4-py3-none-any.whl", hash = "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef"},
] ]
[package.dependencies] [package.dependencies]
pytest = ">=7.0.0" pytest = ">=7.0.0,<8"
[package.extras] [package.extras]
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
@ -658,27 +918,86 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale
[[package]] [[package]]
name = "python-dotenv" 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" description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
] ]
[package.extras] [package.extras]
cli = ["click (>=5.0)"] 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]] [[package]]
name = "redis" name = "redis"
version = "5.0.1" version = "4.6.0"
description = "Python client for Redis database and key-value store" description = "Python client for Redis database and key-value store"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, {file = "redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c"},
{file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, {file = "redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d"},
] ]
[package.dependencies] [package.dependencies]
@ -688,6 +1007,22 @@ async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2
hiredis = ["hiredis (>=1.0.0)"] hiredis = ["hiredis (>=1.0.0)"]
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.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]] [[package]]
name = "sniffio" name = "sniffio"
version = "1.3.0" version = "1.3.0"
@ -814,6 +1149,35 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {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]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.9.0" version = "4.9.0"
@ -844,7 +1208,27 @@ typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
[package.extras] [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)"] 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] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "8da16a83882a9b35a5a05441a33e2296b04a5f664dbb090fec0f384c709fb7ef" content-hash = "106e42984de924817e2dc083ad78699b3411f9aa60de5bb5c1a95ca94a21fda1"

View File

@ -14,13 +14,16 @@ asyncpg = "^0.29.0"
pydantic-settings = "^2.1.0" pydantic-settings = "^2.1.0"
email-validator = "^2.1.0.post1" email-validator = "^2.1.0.post1"
pytest-asyncio = "^0.23.3" 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] [tool.poetry.group.dev.dependencies]
pytest = "^7.4.4" pytest = "^7.4.4"
pytest-cov = "^4.1.0" pytest-cov = "^4.1.0"
httpx = "^0.26.0" httpx = "^0.26.0"
pre-commit = "^3.6.0"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]

View File

@ -1,5 +1,5 @@
import asyncio import asyncio
from typing import AsyncGenerator, Dict, Generator from typing import AsyncGenerator, Generator
import pytest import pytest
import pytest_asyncio 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(): def event_loop():
try: try:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
@ -30,7 +30,7 @@ def event_loop():
loop.close() loop.close()
@pytest_asyncio.fixture(scope="session", autouse=True) @pytest_asyncio.fixture(scope='session', autouse=True)
async def db_init(event_loop): async def db_init(event_loop):
async with async_engine.begin() as conn: async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.drop_all)
@ -45,7 +45,7 @@ async def get_test_session() -> AsyncGenerator[AsyncSession, None]:
yield session yield session
@pytest.fixture(scope="session") @pytest.fixture(scope='session')
def app(event_loop) -> Generator[FastAPI, None, None]: def app(event_loop) -> Generator[FastAPI, None, None]:
app: FastAPI = create_app() app: FastAPI = create_app()
app.dependency_overrides[get_async_session] = get_test_session 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 def client(app) -> AsyncGenerator[AsyncClient, None]:
async with AsyncClient( async with AsyncClient(
app=app, app=app,
base_url="http://localhost:8000/api/v1/menus", base_url='http://localhost:8000/api/v1/menus',
) as async_client: ) as async_client:
yield async_client yield async_client
@pytest.fixture(scope="session") @pytest.fixture(scope='session')
def session_data() -> Dict: def session_data() -> dict:
return {} return {}

View File

@ -1,31 +1,29 @@
from typing import Tuple
from httpx import AsyncClient, Response from httpx import AsyncClient, Response
class Repository: class Repository:
class Menu: class Menu:
@staticmethod @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() return response.status_code, response.json()
@staticmethod @staticmethod
async def get(ac: AsyncClient, data: dict) -> Tuple[int, dict]: async def get(ac: AsyncClient, data: dict) -> tuple[int, dict]:
"""Получение меню по id""" """Получение меню по id"""
response: Response = await ac.get(f"/{data.get('id')}") response: Response = await ac.get(f"/{data.get('id')}")
return response.status_code, response.json() return response.status_code, response.json()
@staticmethod @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() return response.status_code, response.json()
@staticmethod @staticmethod
async def update(ac: AsyncClient, data: dict) -> Tuple[int, dict]: async def update(ac: AsyncClient, data: dict) -> tuple[int, dict]:
"""Обновление меню по id""" """Обновление меню по id"""
response: Response = await ac.patch( response: Response = await ac.patch(
f"/{data.get('id')}", f"/{data.get('id')}",
@ -41,7 +39,7 @@ class Repository:
class Submenu: class Submenu:
@staticmethod @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/") response: Response = await ac.get(f"/{menu.get('id')}/submenus/")
return response.status_code, response.json() return response.status_code, response.json()
@ -51,7 +49,7 @@ class Repository:
ac: AsyncClient, ac: AsyncClient,
menu: dict, menu: dict,
submenu: dict, submenu: dict,
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""Получение меню по id""" """Получение меню по id"""
response: Response = await ac.get( response: Response = await ac.get(
f"/{menu.get('id')}/submenus/{submenu.get('id')}", f"/{menu.get('id')}/submenus/{submenu.get('id')}",
@ -63,7 +61,7 @@ class Repository:
ac: AsyncClient, ac: AsyncClient,
menu: dict, menu: dict,
submenu: dict, submenu: dict,
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""создания меню""" """создания меню"""
response: Response = await ac.post( response: Response = await ac.post(
f"/{menu.get('id')}/submenus/", f"/{menu.get('id')}/submenus/",
@ -74,7 +72,7 @@ class Repository:
@staticmethod @staticmethod
async def update( async def update(
ac: AsyncClient, menu: dict, submenu: dict ac: AsyncClient, menu: dict, submenu: dict
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""Обновление меню по id""" """Обновление меню по id"""
response: Response = await ac.patch( response: Response = await ac.patch(
f"/{menu.get('id')}/submenus/{submenu.get('id')}", f"/{menu.get('id')}/submenus/{submenu.get('id')}",
@ -94,7 +92,7 @@ class Repository:
@staticmethod @staticmethod
async def read_all( async def read_all(
ac: AsyncClient, menu: dict, submenu: dict ac: AsyncClient, menu: dict, submenu: dict
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""чтение всех блюд""" """чтение всех блюд"""
response: Response = await ac.get( response: Response = await ac.get(
f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/", f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/",
@ -104,7 +102,7 @@ class Repository:
@staticmethod @staticmethod
async def get( async def get(
ac: AsyncClient, menu: dict, submenu: dict, dish: dict ac: AsyncClient, menu: dict, submenu: dict, dish: dict
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""Получение блюда по id""" """Получение блюда по id"""
response: Response = await ac.get( response: Response = await ac.get(
f"/{menu.get('id')}/submenus/{submenu.get('id')}" f"/{menu.get('id')}/submenus/{submenu.get('id')}"
@ -115,7 +113,7 @@ class Repository:
@staticmethod @staticmethod
async def write( async def write(
ac: AsyncClient, menu: dict, submenu: dict, dish: dict ac: AsyncClient, menu: dict, submenu: dict, dish: dict
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""создания блюда""" """создания блюда"""
response: Response = await ac.post( response: Response = await ac.post(
f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/", f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/",
@ -126,7 +124,7 @@ class Repository:
@staticmethod @staticmethod
async def update( async def update(
ac: AsyncClient, menu: dict, submenu: dict, dish: dict ac: AsyncClient, menu: dict, submenu: dict, dish: dict
) -> Tuple[int, dict]: ) -> tuple[int, dict]:
"""Обновление блюда по id""" """Обновление блюда по id"""
response: Response = await ac.patch( response: Response = await ac.patch(
f"/{menu.get('id')}/submenus/{submenu.get('id')}" f"/{menu.get('id')}/submenus/{submenu.get('id')}"

View File

@ -15,52 +15,52 @@ async def test_menu_crud_empty(client: AsyncClient) -> None:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_menu_crud_add(client: AsyncClient) -> None: 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) code, rspn = await Repo.Menu.write(client, data)
assert code == 201 assert code == 201
assert rspn["title"] == "Menu" assert rspn['title'] == 'Menu'
assert rspn["description"] is None assert rspn['description'] is None
await Repo.Menu.delete(client, rspn) await Repo.Menu.delete(client, rspn)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_menu_crud_get(client: AsyncClient) -> None: 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, 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 code == 200
assert menu["title"] == rspn["title"] assert menu['title'] == rspn['title']
await Repo.Menu.delete(client, menu) await Repo.Menu.delete(client, menu)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_menu_crud_update(client: AsyncClient) -> None: 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) code, rspn = await Repo.Menu.write(client, data)
upd_data = { upd_data = {
"id": rspn.get("id"), 'id': rspn.get('id'),
"title": "upd Menu", 'title': 'upd Menu',
"description": "", 'description': '',
} }
code, upd_rspn = await Repo.Menu.update(client, upd_data) code, upd_rspn = await Repo.Menu.update(client, upd_data)
assert code == 200 assert code == 200
assert upd_rspn["title"] == "upd Menu" assert upd_rspn['title'] == 'upd Menu'
await Repo.Menu.delete(client, upd_rspn) await Repo.Menu.delete(client, upd_rspn)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_menu_crud_delete(client: AsyncClient) -> None: 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, rspn = await Repo.Menu.write(client, data)
code = await Repo.Menu.delete(client, rspn) code = await Repo.Menu.delete(client, rspn)
assert code == 200 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 assert code == 404
@ -71,7 +71,7 @@ async def test_menu_crud_get_all(client: AsyncClient) -> None:
assert code == 200 assert code == 200
assert rspn == [] assert rspn == []
data = {"title": "Menu", "description": None} data = {'title': 'Menu', 'description': None}
code, rspn = await Repo.Menu.write(client, data) code, rspn = await Repo.Menu.write(client, data)
code, upd_rspn = await Repo.Menu.read_all(client) 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 @pytest.mark.asyncio
async def test_submenus_get_all(client) -> None: 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) code, rspn = await Repo.Menu.write(client, menu)
assert code == 201 assert code == 201
menu.update(rspn) menu.update(rspn)
@ -95,9 +95,9 @@ async def test_submenus_get_all(client) -> None:
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
@ -115,15 +115,15 @@ async def test_submenus_get_all(client) -> None:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_submenus_add(client) -> None: 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) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
assert code == 201 assert code == 201
@ -137,24 +137,24 @@ async def test_submenus_add(client) -> None:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_submenus_update(client) -> None: 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) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
# Обновляем подменю и проверяем # Обновляем подменю и проверяем
submenu["title"] = "updated_submenu" submenu['title'] = 'updated_submenu'
code, rspn = await Repo.Submenu.update(client, menu, submenu) code, rspn = await Repo.Submenu.update(client, menu, submenu)
assert code == 200 assert code == 200
assert submenu["title"] == rspn["title"] assert submenu['title'] == rspn['title']
submenu.update(rspn) submenu.update(rspn)
# удаляем сопутствующее # удаляем сопутствующее
@ -165,15 +165,15 @@ async def test_submenus_update(client) -> None:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_submenus_delete(client) -> None: 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) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
@ -194,17 +194,17 @@ async def test_submenus_delete(client) -> None:
async def test_dishes_get_all(client: AsyncClient) -> None: async def test_dishes_get_all(client: AsyncClient) -> None:
# Создаем меню и проверяем ответ # Создаем меню и проверяем ответ
menu = { menu = {
"title": "Menu", 'title': 'Menu',
"description": "main menu", 'description': 'main menu',
} }
code, rspn = await Repo.Menu.write(client, menu) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
@ -216,10 +216,10 @@ async def test_dishes_get_all(client: AsyncClient) -> None:
# Добавляем блюдо # Добавляем блюдо
dish = { dish = {
"title": "dish", 'title': 'dish',
"description": "some dish", 'description': 'some dish',
"price": "12.5", 'price': '12.5',
"parent_submenu": submenu["id"], 'parent_submenu': submenu['id'],
} }
code, rspn = await Repo.Dish.write(client, menu, submenu, dish) code, rspn = await Repo.Dish.write(client, menu, submenu, dish)
assert code == 201 assert code == 201
@ -239,27 +239,27 @@ async def test_dishes_get_all(client: AsyncClient) -> None:
async def test_dishes_add(client: AsyncClient) -> None: async def test_dishes_add(client: AsyncClient) -> None:
# Создаем меню и проверяем ответ # Создаем меню и проверяем ответ
menu = { menu = {
"title": "Menu", 'title': 'Menu',
"description": "main menu", 'description': 'main menu',
} }
code, rspn = await Repo.Menu.write(client, menu) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
# Добавляем блюдо # Добавляем блюдо
dish = { dish = {
"title": "dish", 'title': 'dish',
"description": "some dish", 'description': 'some dish',
"price": "12.5", 'price': '12.5',
"parent_submenu": submenu["id"], 'parent_submenu': submenu['id'],
} }
code, rspn = await Repo.Dish.write(client, menu, submenu, dish) code, rspn = await Repo.Dish.write(client, menu, submenu, dish)
assert code == 201 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) code, rspn = await Repo.Dish.get(client, menu, submenu, dish)
assert code == 200 assert code == 200
assert rspn["title"] == dish["title"] assert rspn['title'] == dish['title']
# удаляем сопутствующее # удаляем сопутствующее
await Repo.Dish.delete(client, menu, submenu, dish) 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: async def test_dishes_update(client: AsyncClient) -> None:
# Создаем меню и проверяем ответ # Создаем меню и проверяем ответ
menu = { menu = {
"title": "Menu", 'title': 'Menu',
"description": "main menu", 'description': 'main menu',
} }
code, rspn = await Repo.Menu.write(client, menu) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
# Добавляем блюдо # Добавляем блюдо
dish = { dish = {
"title": "dish", 'title': 'dish',
"description": "some dish", 'description': 'some dish',
"price": "12.5", 'price': '12.5',
"parent_submenu": submenu["id"], 'parent_submenu': submenu['id'],
} }
code, rspn = await Repo.Dish.write(client, menu, submenu, dish) code, rspn = await Repo.Dish.write(client, menu, submenu, dish)
dish.update(rspn) dish.update(rspn)
# Обновляем блюдо и проверяем # Обновляем блюдо и проверяем
dish["title"] = "updated_dish" dish['title'] = 'updated_dish'
code, rspn = await Repo.Dish.update(client, menu, submenu, dish) code, rspn = await Repo.Dish.update(client, menu, submenu, dish)
assert code == 200 assert code == 200
assert dish["title"] == rspn["title"] assert dish['title'] == rspn['title']
dish.update(rspn) dish.update(rspn)
# удаляем сопутствующее # удаляем сопутствующее
@ -322,27 +322,27 @@ async def test_dishes_update(client: AsyncClient) -> None:
async def test_dishes_delete(client: AsyncClient) -> None: async def test_dishes_delete(client: AsyncClient) -> None:
# Создаем меню и проверяем ответ # Создаем меню и проверяем ответ
menu = { menu = {
"title": "Menu", 'title': 'Menu',
"description": "main menu", 'description': 'main menu',
} }
code, rspn = await Repo.Menu.write(client, menu) code, rspn = await Repo.Menu.write(client, menu)
menu.update(rspn) menu.update(rspn)
# Создаем и проверяем подменю # Создаем и проверяем подменю
submenu = { submenu = {
"title": "Submenu", 'title': 'Submenu',
"description": "submenu", 'description': 'submenu',
"parent_menu": menu["id"], 'parent_menu': menu['id'],
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
submenu.update(rspn) submenu.update(rspn)
# Добавляем блюдо # Добавляем блюдо
dish = { dish = {
"title": "dish", 'title': 'dish',
"description": "some dish", 'description': 'some dish',
"price": "12.5", 'price': '12.5',
"parent_submenu": submenu["id"], 'parent_submenu': submenu['id'],
} }
code, rspn = await Repo.Dish.write(client, menu, submenu, dish) code, rspn = await Repo.Dish.write(client, menu, submenu, dish)
dish.update(rspn) dish.update(rspn)

View File

@ -1,5 +1,3 @@
from typing import Dict
import pytest import pytest
from httpx import AsyncClient from httpx import AsyncClient
@ -7,160 +5,160 @@ from .repository import Repository as Repo
@pytest.mark.asyncio @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) code, rspn = await Repo.Menu.write(client, menu)
assert code == 201 assert code == 201
code, rspn = await Repo.Menu.get(client, rspn) code, rspn = await Repo.Menu.get(client, rspn)
session_data["target_menu_id"] = rspn.get("id") session_data['target_menu_id'] = rspn.get('id')
session_data["target_menu_title"] = rspn.get("title") session_data['target_menu_title'] = rspn.get('title')
session_data["target_menu_description"] = rspn.get("description") session_data['target_menu_description'] = rspn.get('description')
assert code == 200 assert code == 200
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert "submenus_count" in rspn assert 'submenus_count' in rspn
assert "dishes_count" in rspn assert 'dishes_count' in rspn
assert rspn["title"] == menu.get("title") assert rspn['title'] == menu.get('title')
assert rspn.get("description") == menu.get("description") assert rspn.get('description') == menu.get('description')
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_02(client: AsyncClient, session_data: Dict): async def test_02(client: AsyncClient, session_data: dict):
submenu = {"title": "Submenu", "description": "submenu_descr"} submenu = {'title': 'Submenu', 'description': 'submenu_descr'}
menu = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
code, rspn = await Repo.Submenu.write(client, menu, submenu) code, rspn = await Repo.Submenu.write(client, menu, submenu)
assert code == 201 assert code == 201
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert "dishes_count" in rspn assert 'dishes_count' in rspn
assert rspn["title"] == submenu.get("title") assert rspn['title'] == submenu.get('title')
assert rspn.get("description") == submenu.get("description") assert rspn.get('description') == submenu.get('description')
session_data["target_submenu_id"] = rspn.get("id") session_data['target_submenu_id'] = rspn.get('id')
session_data["target_submenu_title"] = rspn.get("title") session_data['target_submenu_title'] = rspn.get('title')
session_data["target_submenu_description"] = rspn.get("description") session_data['target_submenu_description'] = rspn.get('description')
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_03_dish1(client: AsyncClient, session_data: Dict): async def test_03_dish1(client: AsyncClient, session_data: dict):
menu = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
submenu = { submenu = {
"id": session_data.get("target_submenu_id"), 'id': session_data.get('target_submenu_id'),
"title": session_data.get("target_submenu_title"), 'title': session_data.get('target_submenu_title'),
"description": session_data.get("target_submenu_description"), '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) code, rspn = await Repo.Dish.write(client, menu, submenu, dish)
assert code == 201 assert code == 201
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert "price" in rspn assert 'price' in rspn
assert rspn["title"] == dish.get("title") assert rspn['title'] == dish.get('title')
assert rspn.get("description") == dish.get("description") assert rspn.get('description') == dish.get('description')
assert rspn.get("price") == dish.get("price") assert rspn.get('price') == dish.get('price')
session_data["target_dish_id"] = rspn.get("id") session_data['target_dish_id'] = rspn.get('id')
session_data["target_dish_title"] = rspn.get("title") session_data['target_dish_title'] = rspn.get('title')
session_data["target_dish_description"] = rspn.get("description") session_data['target_dish_description'] = rspn.get('description')
session_data["target_dish_price"] = rspn.get("price") session_data['target_dish_price'] = rspn.get('price')
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_04_dish2(client: AsyncClient, session_data: Dict): async def test_04_dish2(client: AsyncClient, session_data: dict):
menu = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
submenu = { submenu = {
"id": session_data.get("target_submenu_id"), 'id': session_data.get('target_submenu_id'),
"title": session_data.get("target_submenu_title"), 'title': session_data.get('target_submenu_title'),
"description": session_data.get("target_submenu_description"), '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) code, rspn = await Repo.Dish.write(client, menu, submenu, dish)
assert code == 201 assert code == 201
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert "price" in rspn assert 'price' in rspn
assert rspn["title"] == dish.get("title") assert rspn['title'] == dish.get('title')
assert rspn.get("description") == dish.get("description") assert rspn.get('description') == dish.get('description')
assert rspn.get("price") == dish.get("price") assert rspn.get('price') == dish.get('price')
session_data["target_dish1_id"] = rspn.get("id") session_data['target_dish1_id'] = rspn.get('id')
session_data["target_dish1_title"] = rspn.get("title") session_data['target_dish1_title'] = rspn.get('title')
session_data["target_dish1_description"] = rspn.get("description") session_data['target_dish1_description'] = rspn.get('description')
session_data["target_dish1_price"] = rspn.get("price") session_data['target_dish1_price'] = rspn.get('price')
@pytest.mark.asyncio @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
code, rspn = await Repo.Menu.get(client, menu) code, rspn = await Repo.Menu.get(client, menu)
assert code == 200 assert code == 200
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert rspn.get("submenus_count") == 1 assert rspn.get('submenus_count') == 1
assert rspn.get("dishes_count") == 2 assert rspn.get('dishes_count') == 2
@pytest.mark.asyncio @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
submenu = { submenu = {
"id": session_data.get("target_submenu_id"), 'id': session_data.get('target_submenu_id'),
"title": session_data.get("target_submenu_title"), 'title': session_data.get('target_submenu_title'),
"description": session_data.get("target_submenu_description"), 'description': session_data.get('target_submenu_description'),
} }
code, rspn = await Repo.Submenu.get(client, menu, submenu) code, rspn = await Repo.Submenu.get(client, menu, submenu)
assert code == 200 assert code == 200
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert rspn.get("dishes_count") == 2 assert rspn.get('dishes_count') == 2
@pytest.mark.asyncio @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
submenu = { submenu = {
"id": session_data.get("target_submenu_id"), 'id': session_data.get('target_submenu_id'),
"title": session_data.get("target_submenu_title"), 'title': session_data.get('target_submenu_title'),
"description": session_data.get("target_submenu_description"), 'description': session_data.get('target_submenu_description'),
} }
code = await Repo.Submenu.delete(client, menu, submenu) 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 @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
code, rspn = await Repo.Submenu.read_all(client, menu) 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 @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
submenu = { submenu = {
"id": session_data.get("target_submenu_id"), 'id': session_data.get('target_submenu_id'),
"title": session_data.get("target_submenu_title"), 'title': session_data.get('target_submenu_title'),
"description": session_data.get("target_submenu_description"), 'description': session_data.get('target_submenu_description'),
} }
code, rspn = await Repo.Dish.read_all(client, menu, submenu) 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 @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
code, rspn = await Repo.Menu.get(client, menu) code, rspn = await Repo.Menu.get(client, menu)
assert code == 200 assert code == 200
assert "id" in rspn assert 'id' in rspn
assert "title" in rspn assert 'title' in rspn
assert "description" in rspn assert 'description' in rspn
assert rspn.get("submenus_count") == 0 assert rspn.get('submenus_count') == 0
assert rspn.get("dishes_count") == 0 assert rspn.get('dishes_count') == 0
@pytest.mark.asyncio @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 = { menu = {
"id": session_data.get("target_menu_id"), 'id': session_data.get('target_menu_id'),
"title": session_data.get("target_menu_title"), 'title': session_data.get('target_menu_title'),
"description": session_data.get("target_menu_description"), 'description': session_data.get('target_menu_description'),
} }
code = await Repo.Menu.delete(client, menu) 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 @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) code, rspn = await Repo.Menu.read_all(client)
assert code == 200 assert code == 200