diff --git a/Makefile b/Makefile index 2fd0e5d..08ef87c 100644 --- a/Makefile +++ b/Makefile @@ -49,3 +49,12 @@ install: %:: echo $(MESSAGE) + +format-api: + cd api && \ + poetry run ruff format . + + +check-api: + cd api && \ + poetry run ruff format . --check diff --git a/api/api/__main__.py b/api/api/__main__.py index ef43631..6e57ec2 100644 --- a/api/api/__main__.py +++ b/api/api/__main__.py @@ -21,7 +21,6 @@ def bind_routes(application: FastAPI, setting: DefaultSettings) -> None: application.include_router(route, prefix=setting.PATH_PREFIX) - def get_app() -> FastAPI: """Creates application and all dependable objects.""" loguru.logger.remove() @@ -80,7 +79,6 @@ app.add_middleware( allow_credentials=True, allow_methods=["GET", "POST", "OPTIONS", "DELETE", "PUT"], allow_headers=["*"], - ) app.add_middleware(MiddlewareAccessTokenValidadtion) diff --git a/api/api/config/default.py b/api/api/config/default.py index 5a12880..8821f2e 100644 --- a/api/api/config/default.py +++ b/api/api/config/default.py @@ -44,16 +44,11 @@ class DefaultSettings(BaseSettings): REDIS_DB: int = int(environ.get("REDIS_DB", "0")) REDIS_PASSWORD: str = environ.get("REDIS_PASSWORD", "hackme") - SECRET_KEY: str = environ.get("SECRET_KEY", "secret") ALGORITHM: str = environ.get("ALGORITHM", "HS256") - ACCESS_TOKEN_EXPIRE_MINUTES: int = int( - environ.get("ACCESS_TOKEN_EXPIRE_MINUTES", 600) - ) + ACCESS_TOKEN_EXPIRE_MINUTES: int = int(environ.get("ACCESS_TOKEN_EXPIRE_MINUTES", 600)) - REFRESH_TOKEN_EXPIRE_DAYS: int = int( - environ.get("REFRESH_TOKEN_EXPIRE_DAYS_LONG", 365) - ) + REFRESH_TOKEN_EXPIRE_DAYS: int = int(environ.get("REFRESH_TOKEN_EXPIRE_DAYS_LONG", 365)) @cached_property def database_settings(self) -> dict: diff --git a/api/api/db/connection/session.py b/api/api/db/connection/session.py index 1137f39..9454a69 100644 --- a/api/api/db/connection/session.py +++ b/api/api/db/connection/session.py @@ -8,18 +8,16 @@ import asyncio import sqlalchemy from loguru import logger from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine, create_async_engine -from sqlalchemy import URL,create_engine, text +from sqlalchemy import URL, create_engine, text from api.config import get_settings from api.config.default import DbCredentialsSchema - class SessionManager: engines: Any - def __init__(self, database_uri=get_settings().database_uri) -> None: self.database_uri = database_uri self.refresh(database_uri) @@ -44,9 +42,11 @@ class SessionManager: pool_size=get_settings().CONNECTION_POOL_SIZE, max_overflow=get_settings().CONNECTION_OVERFLOW, ) + def get_engine_by_db_uri(self, database_uri) -> AsyncEngine: return self.engines[database_uri] + @contextlib.asynccontextmanager async def get_connection( database_uri=None, @@ -58,6 +58,7 @@ async def get_connection( async with engine.connect() as conn: yield conn + async def get_connection_dep() -> AsyncConnection: async with get_connection() as conn: yield conn diff --git a/api/api/db/logic/account.py b/api/api/db/logic/account.py index c2e30a7..65ccef7 100644 --- a/api/api/db/logic/account.py +++ b/api/api/db/logic/account.py @@ -56,10 +56,7 @@ async def get_user_by_id(connection: AsyncConnection, id: int) -> Optional[User] """ Получает юзера по id. """ - query = ( - select(account_table) - .where(account_table.c.id == id) - ) + query = select(account_table).where(account_table.c.id == id) user_db_cursor = await connection.execute(query) user_db = user_db_cursor.one_or_none() @@ -68,8 +65,11 @@ async def get_user_by_id(connection: AsyncConnection, id: int) -> Optional[User] return None user_data = { - column.name: (getattr(user_db, column.name).name if isinstance( - getattr(user_db, column.name), Enum) else getattr(user_db, column.name)) + column.name: ( + getattr(user_db, column.name).name + if isinstance(getattr(user_db, column.name), Enum) + else getattr(user_db, column.name) + ) for column in account_table.columns } @@ -80,10 +80,7 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional """ Получает юзера по login. """ - query = ( - select(account_table) - .where(account_table.c.login == login) - ) + query = select(account_table).where(account_table.c.login == login) user_db_cursor = await connection.execute(query) user_db = user_db_cursor.one_or_none() @@ -92,8 +89,11 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional return None user_data = { - column.name: (getattr(user_db, column.name).name if isinstance( - getattr(user_db, column.name), Enum) else getattr(user_db, column.name)) + column.name: ( + getattr(user_db, column.name).name + if isinstance(getattr(user_db, column.name), Enum) + else getattr(user_db, column.name) + ) for column in account_table.columns } @@ -104,11 +104,7 @@ async def update_user_by_id(connection: AsyncConnection, update_values, user) -> """ Вносит изменеия в нужное поле таблицы account_table. """ - await connection.execute( - account_table.update() - .where(account_table.c.id == user.id) - .values(**update_values) - ) + await connection.execute(account_table.update().where(account_table.c.id == user.id).values(**update_values)) await connection.commit() @@ -126,7 +122,7 @@ async def create_user(connection: AsyncConnection, user: User, creator_id: int) meta=user.meta, creator_id=creator_id, created_at=datetime.now(timezone.utc), - status=user.status.value + status=user.status.value, ) await connection.execute(query) diff --git a/api/api/db/logic/auth.py b/api/api/db/logic/auth.py index 8137964..393598d 100644 --- a/api/api/db/logic/auth.py +++ b/api/api/db/logic/auth.py @@ -1,6 +1,6 @@ from typing import Optional -from sqlalchemy import select, update +from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncConnection from enum import Enum @@ -11,16 +11,14 @@ from api.schemas.account.account_keyring import AccountKeyring from api.utils.key_id_gen import KeyIdGenerator -from datetime import datetime, timezone +from datetime import datetime, timezone async def get_user(connection: AsyncConnection, login: str) -> Optional[User]: - query = ( select(account_table, account_keyring_table) .join(account_keyring_table, account_table.c.id == account_keyring_table.c.owner_id) - .where(account_table.c.login == login, - account_keyring_table.c.key_type == KeyType.PASSWORD) + .where(account_table.c.login == login, account_keyring_table.c.key_type == KeyType.PASSWORD) ) user_db_cursor = await connection.execute(query) @@ -29,16 +27,21 @@ async def get_user(connection: AsyncConnection, login: str) -> Optional[User]: if not user_db: return None, None - user_data = { - column.name: (getattr(user_db, column.name).name if isinstance( - getattr(user_db, column.name), Enum) else getattr(user_db, column.name)) + column.name: ( + getattr(user_db, column.name).name + if isinstance(getattr(user_db, column.name), Enum) + else getattr(user_db, column.name) + ) for column in account_table.columns } password_data = { - column.name: (getattr(user_db, column.name).name if isinstance( - getattr(user_db, column.name), Enum) else getattr(user_db, column.name)) + column.name: ( + getattr(user_db, column.name).name + if isinstance(getattr(user_db, column.name), Enum) + else getattr(user_db, column.name) + ) for column in account_keyring_table.columns } @@ -47,8 +50,7 @@ async def get_user(connection: AsyncConnection, login: str) -> Optional[User]: return user, password -async def upgrade_old_refresh_token(connection: AsyncConnection, user,refresh_token) -> Optional[User]: - +async def upgrade_old_refresh_token(connection: AsyncConnection, user, refresh_token) -> Optional[User]: new_status = KeyStatus.EXPIRED update_query = ( @@ -57,7 +59,7 @@ async def upgrade_old_refresh_token(connection: AsyncConnection, user,refresh_to account_table.c.id == user.id, account_keyring_table.c.status == KeyStatus.ACTIVE, account_keyring_table.c.key_type == KeyType.REFRESH_TOKEN, - account_keyring_table.c.key_value == refresh_token + account_keyring_table.c.key_value == refresh_token, ) .values(status=new_status) ) @@ -67,8 +69,9 @@ async def upgrade_old_refresh_token(connection: AsyncConnection, user,refresh_to await connection.commit() -async def add_new_refresh_token(connection: AsyncConnection, new_refresh_token, new_refresh_token_expires_time, user) -> Optional[User]: - +async def add_new_refresh_token( + connection: AsyncConnection, new_refresh_token, new_refresh_token_expires_time, user +) -> Optional[User]: new_refresh_token = account_keyring_table.insert().values( owner_id=user.id, key_type=KeyType.REFRESH_TOKEN, diff --git a/api/api/db/logic/keyring.py b/api/api/db/logic/keyring.py index 9d91321..f663c2f 100644 --- a/api/api/db/logic/keyring.py +++ b/api/api/db/logic/keyring.py @@ -5,7 +5,7 @@ from enum import Enum from sqlalchemy import insert, select from sqlalchemy.ext.asyncio import AsyncConnection -from api.db.tables.account import account_keyring_table +from api.db.tables.account import account_keyring_table from api.schemas.account.account_keyring import AccountKeyring @@ -16,10 +16,7 @@ async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[Ac """ Получает key по key_id. """ - query = ( - select(account_keyring_table) - .where(account_keyring_table.c.key_id == key_id) - ) + query = select(account_keyring_table).where(account_keyring_table.c.key_id == key_id) user_db_cursor = await connection.execute(query) user_db = user_db_cursor.one_or_none() @@ -28,8 +25,11 @@ async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[Ac return None user_data = { - column.name: (getattr(user_db, column.name).name if isinstance( - getattr(user_db, column.name), Enum) else getattr(user_db, column.name)) + column.name: ( + getattr(user_db, column.name).name + if isinstance(getattr(user_db, column.name), Enum) + else getattr(user_db, column.name) + ) for column in account_keyring_table.columns } @@ -41,30 +41,28 @@ async def update_key_by_id(connection: AsyncConnection, update_values, key) -> O Вносит изменеия в нужное поле таблицы account_keyring_table. """ await connection.execute( - account_keyring_table.update() - .where(account_keyring_table.c.key_id == key.key_id) - .values(**update_values) - ) + account_keyring_table.update().where(account_keyring_table.c.key_id == key.key_id).values(**update_values) + ) await connection.commit() -async def create_key(connection: AsyncConnection, key: AccountKeyring, key_id:int) -> Optional[AccountKeyring]: +async def create_key(connection: AsyncConnection, key: AccountKeyring, key_id: int) -> Optional[AccountKeyring]: """ Создает нове поле в таблице account_keyring_table). """ query = insert(account_keyring_table).values( - owner_id = key.owner_id, - key_type= key.key_type.value, - key_id= key_id, - key_value= key.key_value, - created_at= datetime.now(timezone.utc), - expiry= key.expiry, - status= key.status.value + owner_id=key.owner_id, + key_type=key.key_type.value, + key_id=key_id, + key_value=key.key_value, + created_at=datetime.now(timezone.utc), + expiry=key.expiry, + status=key.status.value, ) - key.created_at= datetime.now(timezone.utc) - key.key_id= key_id + key.created_at = datetime.now(timezone.utc) + key.key_id = key_id await connection.execute(query) diff --git a/api/api/db/tables/__init__.py b/api/api/db/tables/__init__.py index d531ebd..944212d 100644 --- a/api/api/db/tables/__init__.py +++ b/api/api/db/tables/__init__.py @@ -1 +1 @@ -from . import account,events,process +from . import account, events, process diff --git a/api/api/db/tables/account.py b/api/api/db/tables/account.py index f7c5c61..cf8e795 100644 --- a/api/api/db/tables/account.py +++ b/api/api/db/tables/account.py @@ -21,22 +21,23 @@ class AccountStatus(str,Enum): account_table = Table( - 'account', metadata, - Column('id', UnsignedInt, primary_key=True, autoincrement=True), - Column('name', String(100), nullable=False), - Column('login', String(100), nullable=False), - Column('email', String(100), nullable=True), - Column('bind_tenant_id', String(40), nullable=True), - Column('role', SQLAEnum(AccountRole), nullable=False), - Column('meta', JSON, default={}), - Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=True), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('status', SQLAEnum(AccountStatus), nullable=False), - - Index('idx_login', 'login'), - Index('idx_name', 'name'), + "account", + metadata, + Column("id", UnsignedInt, primary_key=True, autoincrement=True), + Column("name", String(100), nullable=False), + Column("login", String(100), nullable=False), + Column("email", String(100), nullable=True), + Column("bind_tenant_id", String(40), nullable=True), + Column("role", SQLAEnum(AccountRole), nullable=False), + Column("meta", JSON, default={}), + Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=True), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("status", SQLAEnum(AccountStatus), nullable=False), + Index("idx_login", "login"), + Index("idx_name", "name"), ) + class KeyType(str,Enum): PASSWORD = "PASSWORD" ACCESS_TOKEN = "ACCESS_TOKEN" @@ -48,12 +49,15 @@ class KeyStatus(str,Enum): EXPIRED = "EXPIRED" DELETED = "DELETED" + account_keyring_table = Table( - 'account_keyring', metadata, - Column('owner_id', UnsignedInt, ForeignKey('account.id'), primary_key=True, nullable=False), - Column('key_type', SQLAEnum(KeyType), primary_key=True, nullable=False), - Column('key_id', String(40),primary_key=True, default=None), - Column('key_value', String(255), nullable=False), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('expiry', DateTime(timezone=True), nullable=True), - Column('status', SQLAEnum(KeyStatus), nullable=False), ) + "account_keyring", + metadata, + Column("owner_id", UnsignedInt, ForeignKey("account.id"), primary_key=True, nullable=False), + Column("key_type", SQLAEnum(KeyType), primary_key=True, nullable=False), + Column("key_id", String(40), primary_key=True, default=None), + Column("key_value", String(255), nullable=False), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("expiry", DateTime(timezone=True), nullable=True), + Column("status", SQLAEnum(KeyStatus), nullable=False), +) diff --git a/api/api/db/tables/events.py b/api/api/db/tables/events.py index eb9c742..c4d8ab2 100644 --- a/api/api/db/tables/events.py +++ b/api/api/db/tables/events.py @@ -6,10 +6,12 @@ from api.db.sql_types import UnsignedInt from api.db import metadata + class EventState(str, Enum): AUTO = auto() DESCRIPTED = auto() + class EventStatus(str, Enum): ACTIVE = auto() DISABLED = auto() @@ -17,13 +19,14 @@ class EventStatus(str, Enum): list_events_table = Table( - 'list_events', metadata, - Column('id', UnsignedInt, primary_key=True, autoincrement=True), - Column('name', String(40, collation='latin1_bin'), nullable=False,unique=True), - Column('title', String(64), nullable=False), - Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('schema', JSON, default={}), - Column('state', SQLAEnum(EventState), nullable=False), - Column('status', SQLAEnum(EventStatus), nullable=False), + "list_events", + metadata, + Column("id", UnsignedInt, primary_key=True, autoincrement=True), + Column("name", String(40, collation="latin1_bin"), nullable=False, unique=True), + Column("title", String(64), nullable=False), + Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("schema", JSON, default={}), + Column("state", SQLAEnum(EventState), nullable=False), + Column("status", SQLAEnum(EventStatus), nullable=False), ) diff --git a/api/api/db/tables/process.py b/api/api/db/tables/process.py index 0fd2bc3..e2f8c68 100644 --- a/api/api/db/tables/process.py +++ b/api/api/db/tables/process.py @@ -1,4 +1,16 @@ -from sqlalchemy import Table, Column, Integer, String, Text, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index, PrimaryKeyConstraint +from sqlalchemy import ( + Table, + Column, + Integer, + String, + Text, + Enum as SQLAEnum, + JSON, + ForeignKey, + DateTime, + Index, + PrimaryKeyConstraint, +) from sqlalchemy.sql import func from enum import Enum, auto @@ -7,7 +19,6 @@ from api.db.sql_types import UnsignedInt from api.db import metadata - class ProcessStatus(str, Enum): ACTIVE = auto() STOPPING = auto() @@ -16,69 +27,80 @@ class ProcessStatus(str, Enum): process_schema_table = Table( - 'process_schema', metadata, - Column('id', UnsignedInt, primary_key=True, autoincrement=True), - Column('title', String(100), nullable=False), - Column('description', Text, nullable=False), - Column('owner_id', UnsignedInt, ForeignKey('account.id'), nullable=False), - Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('settings', JSON, default={}), - Column('status', SQLAEnum(ProcessStatus), nullable=False), - - Index('idx_owner_id', 'owner_id',) + "process_schema", + metadata, + Column("id", UnsignedInt, primary_key=True, autoincrement=True), + Column("title", String(100), nullable=False), + Column("description", Text, nullable=False), + Column("owner_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("settings", JSON, default={}), + Column("status", SQLAEnum(ProcessStatus), nullable=False), + Index( + "idx_owner_id", + "owner_id", + ), ) process_version_archive_table = Table( - 'process_version_archive', metadata, - Column('id', UnsignedInt, autoincrement=True, nullable=False), - Column('ps_id', UnsignedInt, ForeignKey('process_schema.id'), nullable=False), - Column('version', UnsignedInt, default=1, nullable=False), - Column('snapshot', JSON, default={}), - Column('owner_id', UnsignedInt, ForeignKey('account.id'), nullable=False), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('is_last', UnsignedInt, default=0), - PrimaryKeyConstraint('id', 'version') ) + "process_version_archive", + metadata, + Column("id", UnsignedInt, autoincrement=True, nullable=False), + Column("ps_id", UnsignedInt, ForeignKey("process_schema.id"), nullable=False), + Column("version", UnsignedInt, default=1, nullable=False), + Column("snapshot", JSON, default={}), + Column("owner_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("is_last", UnsignedInt, default=0), + PrimaryKeyConstraint("id", "version"), +) + class NodeStatus(str, Enum): ACTIVE = auto() DISABLED = auto() DELETED = auto() + class NodeType(Enum): - TYPE1 = 'Type1' - TYPE2 = 'Type2' - TYPE3 = 'Type3' + TYPE1 = "Type1" + TYPE2 = "Type2" + TYPE3 = "Type3" + ps_node_table = Table( - 'ps_node', metadata, - Column('id', UnsignedInt, autoincrement=True, primary_key=True, nullable=False), - Column('ps_id', UnsignedInt, ForeignKey('process_schema.id'), nullable=False), - Column('node_type', SQLAEnum(NodeType), nullable=False), - Column('settings', JSON, default={}), - Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('status', SQLAEnum(NodeStatus), nullable=False), - - Index('idx_ps_id', 'ps_id') + "ps_node", + metadata, + Column("id", UnsignedInt, autoincrement=True, primary_key=True, nullable=False), + Column("ps_id", UnsignedInt, ForeignKey("process_schema.id"), nullable=False), + Column("node_type", SQLAEnum(NodeType), nullable=False), + Column("settings", JSON, default={}), + Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("status", SQLAEnum(NodeStatus), nullable=False), + Index("idx_ps_id", "ps_id"), ) + class NodeLinkStatus(str, Enum): ACTIVE = auto() STOPPING = auto() STOPPED = auto() DELETED = auto() -node_link_table = Table( - 'node_link', metadata, - Column('id', UnsignedInt, autoincrement=True, primary_key=True, nullable=False), - Column('link_name', String(20), nullable=False), - Column('node_id', UnsignedInt, ForeignKey('ps_node.id'), nullable=False), - Column('next_node_id', UnsignedInt, ForeignKey('ps_node.id'), nullable=False), - Column('settings', JSON, default={}), - Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False), - Column('created_at', DateTime(timezone=True), server_default=func.now()), - Column('status', SQLAEnum(NodeLinkStatus),nullable=False), - Index('idx_node_id', 'node_id'), - Index('idx_next_node_id', 'next_node_id')) +node_link_table = Table( + "node_link", + metadata, + Column("id", UnsignedInt, autoincrement=True, primary_key=True, nullable=False), + Column("link_name", String(20), nullable=False), + Column("node_id", UnsignedInt, ForeignKey("ps_node.id"), nullable=False), + Column("next_node_id", UnsignedInt, ForeignKey("ps_node.id"), nullable=False), + Column("settings", JSON, default={}), + Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("created_at", DateTime(timezone=True), server_default=func.now()), + Column("status", SQLAEnum(NodeLinkStatus), nullable=False), + Index("idx_node_id", "node_id"), + Index("idx_next_node_id", "next_node_id"), +) diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index ad6708a..6e98978 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -2,11 +2,8 @@ from api.endpoints.auth import api_router as auth_router from api.endpoints.profile import api_router as profile_router from api.endpoints.account import api_router as account_router from api.endpoints.keyring import api_router as keyring_router -list_of_routes = [ - auth_router, - profile_router, - account_router, - keyring_router] + +list_of_routes = [auth_router, profile_router, account_router, keyring_router] __all__ = [ "list_of_routes", diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 50de6c0..2497766 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -28,7 +28,6 @@ api_router = APIRouter( tags=["User accountModel"], ) - @api_router.get("",response_model=AllUserResponse) async def get_all_account( @@ -87,33 +86,23 @@ async def create_account( else: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="An account with this information already exists.") - - + status_code=status.HTTP_400_BAD_REQUEST, detail="An account with this information already exists." + ) @api_router.put("/{user_id}", response_model=User) async def update_account( - user_id: int, - request: Request, - user_update: UserUpdate, - connection: AsyncConnection = Depends(get_connection_dep) - ): - + user_id: int, request: Request, user_update: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep) +): current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) - user = await get_user_by_id(connection, user_id) if user is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Account not found") + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") - - update_values = update_user_data_changes(user_update,user) + update_values = update_user_data_changes(user_update, user) if update_values is None: return user @@ -139,17 +128,13 @@ async def delete_account( authorize_user = await db_user_role_validation(connection, current_user) - user = await get_user_by_id(connection, user_id) if user is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Account not found") - + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") user_update = UserUpdate(status=AccountStatus.DELETED.value) - update_values = update_user_data_changes(user_update,user) + update_values = update_user_data_changes(user_update, user) if update_values is None: return user diff --git a/api/api/endpoints/auth.py b/api/api/endpoints/auth.py index 5758c7f..a4f5806 100644 --- a/api/api/endpoints/auth.py +++ b/api/api/endpoints/auth.py @@ -9,9 +9,7 @@ from fastapi import ( status, ) - from loguru import logger -from pydantic.main import BaseModel from fastapi_jwt_auth import AuthJWT from pydantic import BaseModel @@ -22,7 +20,7 @@ from api.config import get_settings from api.db.connection.session import get_connection_dep from api.services.auth import authenticate_user -from api.db.logic.auth import add_new_refresh_token,upgrade_old_refresh_token +from api.db.logic.auth import add_new_refresh_token, upgrade_old_refresh_token from api.schemas.endpoints.auth import Auth, Access @@ -52,12 +50,11 @@ def get_config(): @api_router.post("", response_model=Access) async def login_for_access_token( - user: Auth, - response: Response, - connection: AsyncConnection = Depends(get_connection_dep), - Authorize: AuthJWT = Depends(), - ): - + user: Auth, + response: Response, + connection: AsyncConnection = Depends(get_connection_dep), + Authorize: AuthJWT = Depends(), +): """Авторизирует, выставляет токены в куки.""" user = await authenticate_user(connection, user.login, user.password) @@ -71,25 +68,18 @@ async def login_for_access_token( # headers={"WWW-Authenticate": "Bearer"}, ) - access_token_expires = timedelta( - minutes=get_settings().ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = timedelta(minutes=get_settings().ACCESS_TOKEN_EXPIRE_MINUTES) - refresh_token_expires = timedelta( - days=get_settings().REFRESH_TOKEN_EXPIRE_DAYS - ) + refresh_token_expires = timedelta(days=get_settings().REFRESH_TOKEN_EXPIRE_DAYS) logger.debug(f"refresh_token_expires {refresh_token_expires}") - access_token = Authorize.create_access_token( - subject=user.login, expires_time=access_token_expires - ) - refresh_token = Authorize.create_refresh_token( - subject=user.login, expires_time=refresh_token_expires - ) + access_token = Authorize.create_access_token(subject=user.login, expires_time=access_token_expires) + refresh_token = Authorize.create_refresh_token(subject=user.login, expires_time=refresh_token_expires) refresh_token_expires_time = datetime.now(timezone.utc) + refresh_token_expires - await add_new_refresh_token(connection,refresh_token,refresh_token_expires_time,user) + await add_new_refresh_token(connection, refresh_token, refresh_token_expires_time, user) Authorize.set_refresh_cookies(refresh_token) @@ -99,11 +89,8 @@ async def login_for_access_token( @api_router.post("/refresh",response_model=Access) async def refresh( - request: Request, - connection: AsyncConnection = Depends(get_connection_dep), - Authorize: AuthJWT = Depends() - ): - + request: Request, connection: AsyncConnection = Depends(get_connection_dep), Authorize: AuthJWT = Depends() +): refresh_token = request.cookies.get("refresh_token_cookie") # print("Refresh Token:", refresh_token) @@ -111,24 +98,19 @@ async def refresh( raise HTTPException(status_code=401, detail="Refresh token is missing") try: - Authorize.jwt_refresh_token_required() current_user = Authorize.get_jwt_subject() - except Exception as e: - - await upgrade_old_refresh_token(connection,current_user,refresh_token) + await upgrade_old_refresh_token(connection, current_user, refresh_token) raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid refresh token", - ) + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid refresh token", + ) access_token_expires = timedelta(minutes=get_settings().ACCESS_TOKEN_EXPIRE_MINUTES) - new_access_token = Authorize.create_access_token( - subject=current_user, expires_time=access_token_expires - ) + new_access_token = Authorize.create_access_token(subject=current_user, expires_time=access_token_expires) return Access(access_token=new_access_token) diff --git a/api/api/endpoints/keyring.py b/api/api/endpoints/keyring.py index 6e21f93..7d0917c 100644 --- a/api/api/endpoints/keyring.py +++ b/api/api/endpoints/keyring.py @@ -47,22 +47,19 @@ async def get_keyring( keyring = await get_key_by_id(connection, key_id) if keyring is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Key not found") + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Key not found") return keyring @api_router.post("/{user_id}/{key_id}", response_model=AccountKeyring) async def create_keyring( - user_id: int, - key_id: str, - request: Request, - key: AccountKeyringUpdate, - connection: AsyncConnection = Depends(get_connection_dep) - ): - + user_id: int, + key_id: str, + request: Request, + key: AccountKeyringUpdate, + connection: AsyncConnection = Depends(get_connection_dep), +): current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) @@ -75,40 +72,33 @@ async def create_keyring( else: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="An keyring with this information already exists.") - + status_code=status.HTTP_400_BAD_REQUEST, detail="An keyring with this information already exists." + ) @api_router.put("/{user_id}/{key_id}", response_model=AccountKeyring) async def update_keyring( - user_id: int, - key_id: str, - request: Request, - keyring_update: AccountKeyringUpdate, - connection: AsyncConnection = Depends(get_connection_dep) - ): - + user_id: int, + key_id: str, + request: Request, + keyring_update: AccountKeyringUpdate, + connection: AsyncConnection = Depends(get_connection_dep), +): current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) - keyring = await get_key_by_id(connection, key_id) if keyring is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="keyring not found") + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="keyring not found") - - update_values = update_key_data_changes(keyring_update,keyring) + update_values = update_key_data_changes(keyring_update, keyring) if update_values is None: return keyring keyring_update_data = AccountKeyring.model_validate({**keyring.model_dump(), **update_values}) - await update_key_by_id(connection, update_values, keyring) @@ -118,27 +108,19 @@ async def update_keyring( @api_router.delete("/{user_id}/{key_id}", response_model=AccountKeyring) async def delete_keyring( - user_id: int, - key_id: str, - request: Request, - connection: AsyncConnection = Depends(get_connection_dep) - ): - + user_id: int, key_id: str, request: Request, connection: AsyncConnection = Depends(get_connection_dep) +): current_user = request.state.current_user authorize_user = await db_user_role_validation(connection, current_user) - keyring = await get_key_by_id(connection, key_id) if keyring is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="keyring not found") - + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="keyring not found") keyring_update = AccountKeyringUpdate(status=KeyStatus.DELETED.value) - update_values = update_key_data_changes(keyring_update,keyring) + update_values = update_key_data_changes(keyring_update, keyring) if update_values is None: return keyring diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index f75f5ab..e4abc66 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -28,50 +28,42 @@ api_router = APIRouter( @api_router.get("",response_model=User) async def get_profile( - request: Request, - connection: AsyncConnection = Depends(get_connection_dep), - ): + request: Request, + connection: AsyncConnection = Depends(get_connection_dep), +): # Извлекаем текущего пользователя из request.state current_user = request.state.current_user user = await get_user_by_login(connection, current_user) if user is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Account not found") + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") return user @api_router.put("",response_model=User) async def update_profile( - request: Request, - user_updata: UserUpdate, - connection: AsyncConnection = Depends(get_connection_dep), - - ): - + request: Request, + user_updata: UserUpdate, + connection: AsyncConnection = Depends(get_connection_dep), +): current_user = request.state.current_user user = await get_user_by_login(connection, current_user) if user is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Account not found") + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") if user_updata.role == None and user_updata.login == None: - update_values = update_user_data_changes(user_updata,user) + update_values = update_user_data_changes(user_updata, user) - if update_values is None: - return user + if update_values is None: + return user await update_user_by_id(connection, update_values, user) user = await get_user_by_id(connection, user.id) - return user + return user else: - raise HTTPException( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY , - detail="Bad body") + raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Bad body") diff --git a/api/api/schemas/account/account.py b/api/api/schemas/account/account.py index 1ceb3b0..38529e6 100644 --- a/api/api/schemas/account/account.py +++ b/api/api/schemas/account/account.py @@ -5,7 +5,7 @@ from pydantic import BaseModel, EmailStr, Field from api.db.tables.account import AccountRole,AccountStatus -class User(BaseModel): +class User(Base): id: Optional[int] = None name: str = Field(..., max_length=100) login: str = Field(..., max_length=100) diff --git a/api/api/schemas/account/account_keyring.py b/api/api/schemas/account/account_keyring.py index b504797..dff9561 100644 --- a/api/api/schemas/account/account_keyring.py +++ b/api/api/schemas/account/account_keyring.py @@ -5,7 +5,7 @@ from datetime import datetime from api.db.tables.account import KeyType,KeyStatus -class AccountKeyring(BaseModel): +class AccountKeyring(Base): owner_id: int key_type: KeyType key_id: Optional[str] = Field(None, max_length=40) diff --git a/api/api/schemas/base.py b/api/api/schemas/base.py new file mode 100644 index 0000000..5fcc034 --- /dev/null +++ b/api/api/schemas/base.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, ConfigDict +from pydantic.alias_generators import to_camel + + +class Base(BaseModel): + model_config = ConfigDict( + from_attributes=True, + alias_generator=to_camel, + populate_by_name=True, + ) diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index c91a9a2..b845e4d 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -6,7 +6,7 @@ from api.db.tables.account import AccountRole,AccountStatus -class UserUpdate(BaseModel): +class UserUpdate(Base): id: Optional[int] = None name: Optional[str] = Field(None, max_length=100) login: Optional[str] = Field(None, max_length=100) diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index 5e646dc..162e2da 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -1,11 +1,11 @@ import datetime from typing import Optional -from pydantic import BaseModel, Field +from pydantic import Field from datetime import datetime from api.db.tables.account import KeyType,KeyStatus -class AccountKeyringUpdate(BaseModel): +class AccountKeyringUpdate(Base): owner_id: Optional[int] = None key_type: Optional[KeyType] = None key_id: Optional[str] = Field(None, max_length=40) diff --git a/api/api/schemas/endpoints/auth.py b/api/api/schemas/endpoints/auth.py index 011d458..7d11765 100644 --- a/api/api/schemas/endpoints/auth.py +++ b/api/api/schemas/endpoints/auth.py @@ -1,13 +1,19 @@ -from pydantic import BaseModel +from api.schemas.base import Base + # Таблица для получения информации из запроса -class Auth(BaseModel): + +class Auth(Base): login: str password: str -class Refresh(BaseModel): +class AccessToken(Base): + access_token: str + + +class Refresh(Base): refresh_token: str class Access(BaseModel): diff --git a/api/api/schemas/events/list_events.py b/api/api/schemas/events/list_events.py index f70ddf5..2df94c7 100644 --- a/api/api/schemas/events/list_events.py +++ b/api/api/schemas/events/list_events.py @@ -1,8 +1,10 @@ -from pydantic import BaseModel, Field +from pydantic import Field from typing import Dict, Any from datetime import datetime from enum import Enum +from api.schemas.base import Base + class State(Enum): AUTO = "Auto" @@ -14,7 +16,8 @@ class Status(Enum): DISABLED = "Disabled" DELETED = "Deleted" -class ListEvent(BaseModel): + +class ListEvent(Base): id: int name: str = Field(..., max_length=40) title: str = Field(..., max_length=64) diff --git a/api/api/schemas/process/node_link.py b/api/api/schemas/process/node_link.py index 794391d..92d5513 100644 --- a/api/api/schemas/process/node_link.py +++ b/api/api/schemas/process/node_link.py @@ -1,15 +1,19 @@ -from pydantic import BaseModel, Field, conint +from pydantic import Field, conint from typing import Dict, Any from datetime import datetime from enum import Enum +from api.schemas.base import Base + + class Status(Enum): ACTIVE = "Active" STOPPING = "Stopping" STOPPED = "Stopped" DELETED = "Deleted" -class MyModel(BaseModel): + +class MyModel(Base): id: int link_name: str = Field(..., max_length=20) node_id: int diff --git a/api/api/schemas/process/process_schema.py b/api/api/schemas/process/process_schema.py index d4150a4..70f670b 100644 --- a/api/api/schemas/process/process_schema.py +++ b/api/api/schemas/process/process_schema.py @@ -1,15 +1,19 @@ -from pydantic import BaseModel, Field +from pydantic import Field from typing import Dict, Any from datetime import datetime from enum import Enum +from api.schemas.base import Base + + class Status(Enum): ACTIVE = "Active" STOPPING = "Stopping" STOPPED = "Stopped" DELETED = "Deleted" -class ProcessSchema(BaseModel): + +class ProcessSchema(Base): id: int title: str = Field(..., max_length=100) description: str diff --git a/api/api/schemas/process/process_version_archive.py b/api/api/schemas/process/process_version_archive.py index 556e2ff..83afe3b 100644 --- a/api/api/schemas/process/process_version_archive.py +++ b/api/api/schemas/process/process_version_archive.py @@ -1,8 +1,10 @@ -from pydantic import BaseModel, Field from typing import Dict, Any from datetime import datetime -class ProcessStatusSchema(BaseModel): +from api.schemas.base import Base + + +class ProcessStatusSchema(Base): id: int version: int snapshot: Dict[str, Any] diff --git a/api/api/schemas/process/ps_node.py b/api/api/schemas/process/ps_node.py index e9e6c40..0a47f38 100644 --- a/api/api/schemas/process/ps_node.py +++ b/api/api/schemas/process/ps_node.py @@ -1,19 +1,21 @@ -from pydantic import BaseModel from datetime import datetime from typing import Dict, Any from enum import Enum +from api.schemas.base import Base + class NodeType(Enum): - pass + class Status(Enum): ACTIVE = "Active" DISABLED = "Disabled" DELETED = "Deleted" -class Ps_Node(BaseModel): + +class Ps_Node(Base): id: int ps_id: int node_type: NodeType diff --git a/api/api/services/auth.py b/api/api/services/auth.py index dcdfd64..e0b1b6f 100644 --- a/api/api/services/auth.py +++ b/api/api/services/auth.py @@ -1,6 +1,7 @@ from typing import Optional from sqlalchemy.ext.asyncio import AsyncConnection from api.db.logic.auth import get_user + # # from backend.schemas.users.token import TokenData from api.schemas.account.account import User from api.db.tables.account import AccountStatus @@ -8,13 +9,8 @@ from api.db.tables.account import AccountStatus from api.utils.hasher import Hasher - - -async def authenticate_user( - connection: AsyncConnection, username: str, password: str -) -> Optional[User]: - - sql_user,sql_password = await get_user(connection, username) +async def authenticate_user(connection: AsyncConnection, username: str, password: str) -> Optional[User]: + sql_user, sql_password = await get_user(connection, username) if not sql_user or sql_user.status != AccountStatus.ACTIVE : return None diff --git a/api/api/services/middleware.py b/api/api/services/middleware.py index 0d9eb3e..a44070d 100644 --- a/api/api/services/middleware.py +++ b/api/api/services/middleware.py @@ -14,52 +14,43 @@ from re import escape from fastapi_jwt_auth import AuthJWT - class MiddlewareAccessTokenValidadtion(BaseHTTPMiddleware): def __init__(self, app): super().__init__(app) self.prefix = escape(get_settings().PATH_PREFIX) self.excluded_routes = [ - re.compile(r'^' + re.escape(self.prefix) + r'/auth/refresh/?$'), - re.compile(r'^' + re.escape(self.prefix) + r'/auth/?$') + re.compile(r"^" + re.escape(self.prefix) + r"/auth/refresh/?$"), + re.compile(r"^" + re.escape(self.prefix) + r"/auth/?$"), ] - - - async def dispatch(self, - request: Request, - call_next): - + async def dispatch(self, request: Request, call_next): if request.method in ["GET", "POST", "PUT", "DELETE"]: if any(pattern.match(request.url.path) for pattern in self.excluded_routes): return await call_next(request) else: - auth_header = request.headers.get("Authorization") if not auth_header: - return JSONResponse( - status_code=status.HTTP_401_UNAUTHORIZED, - content={"detail": "Missing authorization header."}, - headers={"WWW-Authenticate": "Bearer"} - ) + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + content={"detail": "Missing authorization header."}, + headers={"WWW-Authenticate": "Bearer"}, + ) token = auth_header.split(" ")[1] Authorize = AuthJWT(request) try: - current_user = Authorize.get_jwt_subject() + current_user = Authorize.get_jwt_subject() request.state.current_user = current_user return await call_next(request) except Exception: return JSONResponse( - status_code=status.HTTP_401_UNAUTHORIZED, - content={"detail": "The access token is invalid or expired."}, - headers={"WWW-Authenticate": "Bearer"} - ) - - + status_code=status.HTTP_401_UNAUTHORIZED, + content={"detail": "The access token is invalid or expired."}, + headers={"WWW-Authenticate": "Bearer"}, + ) # async with get_connection() as connection: # authorize_user = await get_user_login(connection, current_user) diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py index 6f29486..e1ce7c6 100644 --- a/api/api/services/update_data_validation.py +++ b/api/api/services/update_data_validation.py @@ -5,6 +5,7 @@ from api.db.tables.account import KeyType,KeyStatus from api.schemas.endpoints.account_keyring import AccountKeyringUpdate from api.db.tables.account import AccountRole,AccountStatus + def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: """ Сравнивает данные для обновления с текущими значениями пользователя. @@ -38,6 +39,7 @@ def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: return changes if changes else None + def update_key_data_changes(update_data: AccountKeyringUpdate, key) -> Optional[dict]: """ Сравнивает данные для обновления с текущими значениями пользователя. diff --git a/api/api/utils/hasher.py b/api/api/utils/hasher.py index 16c16e0..61d4c0e 100644 --- a/api/api/utils/hasher.py +++ b/api/api/utils/hasher.py @@ -2,6 +2,7 @@ import hashlib # Хешер для работы с паролем. + class Hasher: def __init__(self): pass diff --git a/api/api/utils/key_id_gen.py b/api/api/utils/key_id_gen.py index 7879aab..630ea53 100644 --- a/api/api/utils/key_id_gen.py +++ b/api/api/utils/key_id_gen.py @@ -3,6 +3,7 @@ from datetime import datetime # Генератор key_id для таблицы account_keyring + def KeyIdGenerator(): random_number = random.randint(1000, 9999) result = f"{datetime.now().strftime('%Y-%m-%d')}-{random_number}" diff --git a/api/poetry.lock b/api/poetry.lock index 9c8b523..8adc2c4 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "aio-pika" @@ -106,6 +106,18 @@ doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] +[[package]] +name = "certifi" +version = "2025.4.26" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"}, + {file = "certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6"}, +] + [[package]] name = "cffi" version = "1.17.1" @@ -338,14 +350,40 @@ files = [ ] [package.dependencies] +email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} +fastapi-cli = {version = ">=0.0.5", extras = ["standard"], optional = true, markers = "extra == \"standard\""} +httpx = {version = ">=0.23.0", optional = true, markers = "extra == \"standard\""} +jinja2 = {version = ">=3.1.5", optional = true, markers = "extra == \"standard\""} pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +python-multipart = {version = ">=0.0.18", optional = true, markers = "extra == \"standard\""} starlette = ">=0.40.0,<0.47.0" typing-extensions = ">=4.8.0" +uvicorn = {version = ">=0.12.0", extras = ["standard"], optional = true, markers = "extra == \"standard\""} [package.extras] all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "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)"] standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "fastapi-cli" +version = "0.0.7" +description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4"}, + {file = "fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e"}, +] + +[package.dependencies] +rich-toolkit = ">=0.11.1" +typer = ">=0.12.3" +uvicorn = {version = ">=0.15.0", extras = ["standard"]} + +[package.extras] +standard = ["uvicorn[standard] (>=0.15.0)"] + [[package]] name = "fastapi-jwt-auth" version = "0.5.0" @@ -472,6 +510,109 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "httpcore" +version = "1.0.8" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"}, + {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httptools" +version = "0.6.4" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, + {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, + {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, + {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, + {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, + {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, + {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, + {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, +] + +[package.extras] +test = ["Cython (>=0.29.24)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + [[package]] name = "idna" version = "3.10" @@ -487,6 +628,24 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + [[package]] name = "loguru" version = "0.7.3" @@ -526,6 +685,31 @@ babel = ["Babel"] lingua = ["lingua"] testing = ["pytest"] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" version = "3.0.2" @@ -597,6 +781,18 @@ files = [ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + [[package]] name = "multidict" version = "6.2.0" @@ -992,6 +1188,21 @@ azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0 toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] +[[package]] +name = "pygments" +version = "2.19.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "pyjwt" version = "1.7.1" @@ -1052,6 +1263,145 @@ files = [ {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, ] +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "rich" +version = "14.0.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, + {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rich-toolkit" +version = "0.14.7" +description = "Rich toolkit for building command-line applications" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da"}, + {file = "rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e"}, +] + +[package.dependencies] +click = ">=8.1.7" +rich = ">=13.7.1" +typing-extensions = ">=4.12.2" + +[[package]] +name = "ruff" +version = "0.11.10" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.11.10-py3-none-linux_armv6l.whl", hash = "sha256:859a7bfa7bc8888abbea31ef8a2b411714e6a80f0d173c2a82f9041ed6b50f58"}, + {file = "ruff-0.11.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:968220a57e09ea5e4fd48ed1c646419961a0570727c7e069842edd018ee8afed"}, + {file = "ruff-0.11.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1067245bad978e7aa7b22f67113ecc6eb241dca0d9b696144256c3a879663bca"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4854fd09c7aed5b1590e996a81aeff0c9ff51378b084eb5a0b9cd9518e6cff2"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b4564e9f99168c0f9195a0fd5fa5928004b33b377137f978055e40008a082c5"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b6a9cc5b62c03cc1fea0044ed8576379dbaf751d5503d718c973d5418483641"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:607ecbb6f03e44c9e0a93aedacb17b4eb4f3563d00e8b474298a201622677947"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3a522fa389402cd2137df9ddefe848f727250535c70dafa840badffb56b7a4"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f071b0deed7e9245d5820dac235cbdd4ef99d7b12ff04c330a241ad3534319f"}, + {file = "ruff-0.11.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a60e3a0a617eafba1f2e4186d827759d65348fa53708ca547e384db28406a0b"}, + {file = "ruff-0.11.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:da8ec977eaa4b7bf75470fb575bea2cb41a0e07c7ea9d5a0a97d13dbca697bf2"}, + {file = "ruff-0.11.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ddf8967e08227d1bd95cc0851ef80d2ad9c7c0c5aab1eba31db49cf0a7b99523"}, + {file = "ruff-0.11.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5a94acf798a82db188f6f36575d80609072b032105d114b0f98661e1679c9125"}, + {file = "ruff-0.11.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3afead355f1d16d95630df28d4ba17fb2cb9c8dfac8d21ced14984121f639bad"}, + {file = "ruff-0.11.10-py3-none-win32.whl", hash = "sha256:dc061a98d32a97211af7e7f3fa1d4ca2fcf919fb96c28f39551f35fc55bdbc19"}, + {file = "ruff-0.11.10-py3-none-win_amd64.whl", hash = "sha256:5cc725fbb4d25b0f185cb42df07ab6b76c4489b4bfb740a175f3a59c70e8a224"}, + {file = "ruff-0.11.10-py3-none-win_arm64.whl", hash = "sha256:ef69637b35fb8b210743926778d0e45e1bffa850a7c61e428c6b971549b5f5d1"}, + {file = "ruff-0.11.10.tar.gz", hash = "sha256:d522fb204b4959909ecac47da02830daec102eeb100fb50ea9554818d47a5fa6"}, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -1180,6 +1530,24 @@ anyio = ">=3.6.2,<5" [package.extras] full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] +[[package]] +name = "typer" +version = "0.16.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855"}, + {file = "typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + [[package]] name = "typing-extensions" version = "4.12.2" @@ -1221,11 +1589,234 @@ files = [ [package.dependencies] click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" +httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} [package.extras] standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] +[[package]] +name = "uvloop" +version = "0.21.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, + {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, +] + +[package.extras] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + +[[package]] +name = "watchfiles" +version = "1.0.5" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40"}, + {file = "watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb"}, + {file = "watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11"}, + {file = "watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487"}, + {file = "watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256"}, + {file = "watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85"}, + {file = "watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358"}, + {file = "watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614"}, + {file = "watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f"}, + {file = "watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d"}, + {file = "watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff"}, + {file = "watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92"}, + {file = "watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827"}, + {file = "watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4"}, + {file = "watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d"}, + {file = "watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63"}, + {file = "watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418"}, + {file = "watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9"}, + {file = "watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6"}, + {file = "watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25"}, + {file = "watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5"}, + {file = "watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01"}, + {file = "watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246"}, + {file = "watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096"}, + {file = "watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed"}, + {file = "watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2"}, + {file = "watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f"}, + {file = "watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec"}, + {file = "watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21"}, + {file = "watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512"}, + {file = "watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d"}, + {file = "watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6"}, + {file = "watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234"}, + {file = "watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2"}, + {file = "watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663"}, + {file = "watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249"}, + {file = "watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705"}, + {file = "watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417"}, + {file = "watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d"}, + {file = "watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763"}, + {file = "watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40"}, + {file = "watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563"}, + {file = "watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04"}, + {file = "watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f"}, + {file = "watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a"}, + {file = "watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827"}, + {file = "watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a"}, + {file = "watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936"}, + {file = "watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc"}, + {file = "watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11"}, + {file = "watchfiles-1.0.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:2cfb371be97d4db374cba381b9f911dd35bb5f4c58faa7b8b7106c8853e5d225"}, + {file = "watchfiles-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a3904d88955fda461ea2531fcf6ef73584ca921415d5cfa44457a225f4a42bc1"}, + {file = "watchfiles-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b7a21715fb12274a71d335cff6c71fe7f676b293d322722fe708a9ec81d91f5"}, + {file = "watchfiles-1.0.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dfd6ae1c385ab481766b3c61c44aca2b3cd775f6f7c0fa93d979ddec853d29d5"}, + {file = "watchfiles-1.0.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b659576b950865fdad31fa491d31d37cf78b27113a7671d39f919828587b429b"}, + {file = "watchfiles-1.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1909e0a9cd95251b15bff4261de5dd7550885bd172e3536824bf1cf6b121e200"}, + {file = "watchfiles-1.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:832ccc221927c860e7286c55c9b6ebcc0265d5e072f49c7f6456c7798d2b39aa"}, + {file = "watchfiles-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85fbb6102b3296926d0c62cfc9347f6237fb9400aecd0ba6bbda94cae15f2b3b"}, + {file = "watchfiles-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:15ac96dd567ad6c71c71f7b2c658cb22b7734901546cd50a475128ab557593ca"}, + {file = "watchfiles-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b6227351e11c57ae997d222e13f5b6f1f0700d84b8c52304e8675d33a808382"}, + {file = "watchfiles-1.0.5-cp39-cp39-win32.whl", hash = "sha256:974866e0db748ebf1eccab17862bc0f0303807ed9cda465d1324625b81293a18"}, + {file = "watchfiles-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:9848b21ae152fe79c10dd0197304ada8f7b586d3ebc3f27f43c506e5a52a863c"}, + {file = "watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d"}, + {file = "watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034"}, + {file = "watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965"}, + {file = "watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57"}, + {file = "watchfiles-1.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:554389562c29c2c182e3908b149095051f81d28c2fec79ad6c8997d7d63e0009"}, + {file = "watchfiles-1.0.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a74add8d7727e6404d5dc4dcd7fac65d4d82f95928bbee0cf5414c900e86773e"}, + {file = "watchfiles-1.0.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb1489f25b051a89fae574505cc26360c8e95e227a9500182a7fe0afcc500ce0"}, + {file = "watchfiles-1.0.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0901429650652d3f0da90bad42bdafc1f9143ff3605633c455c999a2d786cac"}, + {file = "watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + +[[package]] +name = "websockets" +version = "15.0.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, +] + [[package]] name = "win32-setctime" version = "1.2.0" @@ -1342,4 +1933,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.1" python-versions = ">=3.11,<4.0" -content-hash = "146687a6e082e27748cc339242d924d2fb0741f7f2eb842a025e137f5fb41378" +content-hash = "5ed129fde2c5d7b3518fbb2fe2ce79f0bad2aa1060304d45a7bc26d35f7ab46b" diff --git a/api/pyproject.toml b/api/pyproject.toml index ca3cad5..3a525dd 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "api" -version = "0.0.2" +version = "0.0.3" description = "" authors = [ {name = "Vladislav",email = "vlad.dev@heado.ru"} @@ -11,7 +11,7 @@ dependencies = [ "sqlalchemy[pymysql,aiomysql] (>=2.0.39,<3.0.0)", "alembic (>=1.15.1,<2.0.0)", "aio-pika (>=9.5.5,<10.0.0)", - "fastapi[standart] (>=0.115.11,<0.116.0)", + "fastapi[standard] (>=0.115.11,<0.116.0)", "uvicorn (>=0.34.0,<0.35.0)", "loguru (>=0.7.3,<0.8.0)", "pydantic-settings (>=2.8.1,<3.0.0)", @@ -25,3 +25,10 @@ dependencies = [ [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.11.10" + +[tool.ruff] +line-length = 120 +extend-exclude = ["alembic"]