├── .env.example ├── .github └── workflows │ └── build-and-test.yml ├── .gitignore ├── Dockerfile ├── DockerfileOracleLinux ├── LICENSE ├── Makefile ├── README.md ├── compose-oracle.yml ├── compose.yml ├── greens ├── __init__.py ├── config.py ├── main.py ├── routers │ ├── __init__.py │ ├── exceptions.py │ └── v1 │ │ ├── __init__.py │ │ └── vegs.py ├── schemas │ ├── __init__.py │ └── vegs.py ├── services │ ├── __init__.py │ └── repository.py └── utils.py ├── log-conf.yaml ├── poetry.lock ├── pyproject.tbd ├── pyproject.toml ├── static └── greens.jpg ├── tests ├── __init__.py ├── conftest.py ├── test_routers.py ├── test_schemas.py └── test_vegs_api.py └── uv.lock /.env.example: -------------------------------------------------------------------------------- 1 | PYTHONDONTWRITEBYTECODE=1 2 | PYTHONUNBUFFERED=1 3 | 4 | ENVIRONMENT=local 5 | TESTING=0 6 | UP=up 7 | DOWN=down 8 | WEB_SERVER=web_server 9 | 10 | MONGODB_HOST=mongodb 11 | MONGODB_PORT=27017 12 | MONGODB_USER=farmer 13 | MONGODB_PASSWORD=tractor 14 | MONGODB_DATABASE=greenhouse 15 | MONGODB_COLLECTION=greens 16 | MONGODB_TEST=farmland 17 | MONGO_URL=mongodb://farmer:tractor@mongodb:27017/?retryWrites=true&w=majority 18 | MONGODB_PARAMS: ?authSource=admin&authMechanism=SCRAM-SHA-1&retryWrites=true&w=majority 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | python-version: [ "3.13" ] 16 | 17 | env: 18 | PYTHONDONTWRITEBYTECODE: 1 19 | PYTHONUNBUFFERED: 1 20 | ENVIRONMENT: test 21 | TESTING: 0 22 | UP: up 23 | DOWN: down 24 | WEB_SERVER: web_server 25 | MONGODB_HOST: 127.0.0.1 26 | MONGODB_PORT: 27017 27 | MONGODB_USER: farmer 28 | MONGODB_PASSWORD: tractor 29 | MONGODB_DATABASE: greenhouse 30 | MONGODB_COLLECTION: greens 31 | MONGODB_TEST: farmland 32 | MONGODB_PARAMS: ?authSource=admin&authMechanism=SCRAM-SHA-1&retryWrites=true&w=majority 33 | 34 | services: 35 | mongodb: 36 | image: mongo:7.0.8 37 | env: 38 | MONGO_INITDB_DATABASE: greenhouse 39 | MONGO_INITDB_ROOT_USERNAME: farmer 40 | MONGO_INITDB_ROOT_PASSWORD: tractor 41 | ports: 42 | - 27017:27017 43 | 44 | steps: 45 | - uses: actions/checkout@v4 46 | 47 | - name: Install the latest version of uv and set the python version 48 | uses: astral-sh/setup-uv@v5 49 | with: 50 | python-version: ${{ matrix.python-version }} 51 | 52 | - name: Test with python ${{ matrix.python-version }} 53 | run: uv run --frozen pytest 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .idea/ 132 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:oracular AS build 2 | 3 | RUN apt-get update -qy && apt-get install -qyy \ 4 | -o APT::Install-Recommends=false \ 5 | -o APT::Install-Suggests=false \ 6 | build-essential \ 7 | ca-certificates \ 8 | python3-setuptools \ 9 | python3.13-dev 10 | 11 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv 12 | 13 | ENV UV_LINK_MODE=copy \ 14 | UV_COMPILE_BYTECODE=1 \ 15 | UV_PYTHON_DOWNLOADS=never \ 16 | UV_PYTHON=python3.13 \ 17 | UV_PROJECT_ENVIRONMENT=/app 18 | 19 | COPY pyproject.toml /_lock/ 20 | COPY uv.lock /_lock/ 21 | 22 | RUN --mount=type=cache,target=/root/.cache 23 | RUN cd /_lock && uv sync \ 24 | --locked \ 25 | --no-dev \ 26 | --no-install-project 27 | ########################################################################## 28 | FROM ubuntu:oracular 29 | 30 | ENV PATH=/app/bin:$PATH 31 | 32 | RUN groupadd -r app 33 | RUN useradd -r -d /app -g app -N app 34 | 35 | STOPSIGNAL SIGINT 36 | 37 | RUN apt-get update -qy && apt-get install -qyy \ 38 | -o APT::Install-Recommends=false \ 39 | -o APT::Install-Suggests=false \ 40 | python3.13 \ 41 | libpython3.13 \ 42 | libpcre3 \ 43 | libxml2 44 | 45 | RUN apt-get clean 46 | RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 47 | 48 | COPY --from=build --chown=app:app /app /app 49 | 50 | USER app 51 | WORKDIR /app 52 | COPY /greens/ greens/ 53 | COPY /tests/ tests/ 54 | COPY .env greens/ 55 | 56 | RUN python -V 57 | RUN python -Im site 58 | RUN python -Ic 'import uvicorn' 59 | -------------------------------------------------------------------------------- /DockerfileOracleLinux: -------------------------------------------------------------------------------- 1 | FROM eurolinux/oracle-linux-9:oracle-linux-9-9.4.3-arm64 AS build 2 | 3 | RUN dnf install python3.12 python3.12-devel -y 4 | 5 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv 6 | 7 | ENV UV_LINK_MODE=copy \ 8 | UV_COMPILE_BYTECODE=1 \ 9 | UV_PYTHON_DOWNLOADS=never \ 10 | UV_PYTHON=python3.12 \ 11 | UV_PROJECT_ENVIRONMENT=/app 12 | 13 | COPY pyproject.toml /_lock/ 14 | COPY uv.lock /_lock/ 15 | 16 | RUN --mount=type=cache,target=/root/.cache 17 | RUN cd /_lock && uv sync \ 18 | --locked \ 19 | --no-dev \ 20 | --no-install-project 21 | 22 | # Clean up unnecessary files 23 | RUN dnf clean all 24 | RUN rm -rf /var/cache/dnf /var/lib/dnf/history.* /usr/share/doc /usr/share/man /usr/share/info /usr/share/locale /tmp/* /var/tmp/* /root/.cache 25 | 26 | FROM eurolinux/oracle-linux-9:oracle-linux-9-9.4.3-arm64 27 | 28 | ENV PATH=/app/bin:$PATH 29 | 30 | RUN groupadd -r app 31 | RUN useradd -r -d /app -g app -N app 32 | 33 | STOPSIGNAL SIGINT 34 | 35 | RUN dnf install python3.12 -y 36 | 37 | RUN dnf clean all 38 | RUN rm -rf /var/cache/dnf /var/lib/dnf/history.* /usr/share/doc /usr/share/man /usr/share/info /usr/share/locale /tmp/* /var/tmp/* /root/.cache 39 | 40 | 41 | COPY --from=build --chown=app:app /app /app 42 | 43 | USER app 44 | WORKDIR /app 45 | COPY /greens/ greens/ 46 | COPY /tests/ tests/ 47 | COPY .env greens/ 48 | 49 | RUN python -V 50 | RUN python -Im site 51 | RUN python -Ic 'import uvicorn' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jakub Miazek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help 2 | help: ## Show this help 3 | @egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 4 | 5 | .PHONY: build-app 6 | build-app: ## Build project with compose 7 | docker build . -t fastapi-mongodb-ubuntu-app:latest 8 | 9 | .PHONY: build-oracle-linux-app 10 | build-oracle-linux-app: ## Build project with compose on oracle linux 11 | docker build . --file DockerfileOracleLinux -t fastapi-mongodb-oracle-app:latest 12 | 13 | .PHONY: up 14 | up: ## Run project with compose 15 | docker compose -f compose.yml up 16 | 17 | .PHONY: down 18 | down: ## Reset project containers with compose 19 | docker compose -f compose.yml down -v --remove-orphans 20 | 21 | .PHONY: test 22 | test: ## Run project tests 23 | docker compose -f compose.yml run --rm web pytest -vv tests 24 | 25 | .PHONY: test-snapshot 26 | test-snapshot: ## Run project tests 27 | docker compose -f compose.yml run --rm web pytest --inline-snapshot=fix tests 28 | 29 | .PHONY: mypy 30 | mypy: ## mypy check. 31 | mypy --ignore-missing-imports . 32 | 33 | .PHONY: lint 34 | lint: ## Lint project code. 35 | uv run ruff check --fix . 36 | 37 | .PHONY: safety 38 | safety: ## apply safety check in project. 39 | safety check 40 | 41 | .PHONY: format 42 | format: ## format project code. 43 | black --line-length=120 . 44 | isort -rc -m 3 --tc . 45 | 46 | .PHONY: clean 47 | clean: ## Clean Reset project containers and volumes with compose 48 | docker compose -f compose.yml down -v --remove-orphans | true 49 | docker compose -f compose.yml rm -f 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fastapi-mongodb 2 | 3 | [![developer](https://img.shields.io/badge/Dev-grillazz-green?style)](https://github.com/grillazz) 4 | ![language](https://img.shields.io/badge/language-python-blue?style) 5 | [![license](https://img.shields.io/github/license/grillazz/fastapi-mongodb)](https://github.com/grillazz/fastapi-mongodb/main/LICENSE) 6 | ![visitors](https://visitor-badge.laobi.icu/badge?page_id=grillazz.fastapi-mongodb") 7 | [![CI](https://img.shields.io/github/workflow/status/grillazz/fastapi-mongodb/Unit%20Tests/develop)](https://github.com/grillazz/fastapi-mongodb/actions/workflows/build-and-test.yml?query=event%3Apull_request+branch%3Adevelop) 8 | 9 | ![fastapi-redis](/static/greens.jpg) 10 | 11 | ### Project Description 12 | 13 | ### How to Setup 14 | 15 | ### About logging 16 | 17 | ### UV knowledge and inspirations 18 | - https://docs.astral.sh/uv/ 19 | - https://hynek.me/articles/docker-uv/ 20 | - https://thedataquarry.com/posts/towards-a-unified-python-toolchain/ 21 | - https://www.youtube.com/watch?v=ifj-izwXKRA&t=760s > UV and Ruff: Next-gen Python Tooling 22 | - https://www.youtube.com/watch?v=8UuW8o4bHbw&t=1s > uv IS the Future of Python Packaging! 🐍📦 -------------------------------------------------------------------------------- /compose-oracle.yml: -------------------------------------------------------------------------------- 1 | services: 2 | web: 3 | image: ora:004 4 | env_file: 5 | - .env 6 | command: bash -c " 7 | uvicorn greens.main:app 8 | --host 0.0.0.0 --port 8989 9 | --lifespan=on --use-colors --loop uvloop --http httptools 10 | --reload 11 | " 12 | volumes: 13 | - ./greens:/app/greens 14 | - ./tests:/app/tests 15 | ports: 16 | - "8989:8989" 17 | depends_on: 18 | - mongodb 19 | 20 | mongodb: 21 | image: mongo:7.0.8 22 | env_file: 23 | - .env 24 | ports: 25 | - "27017:27017" 26 | environment: 27 | - "MONGO_INITDB_DATABASE=${MONGODB_DATABASE}" 28 | - "MONGO_INITDB_ROOT_USERNAME=${MONGODB_USER}" 29 | - "MONGO_INITDB_ROOT_PASSWORD=${MONGODB_PASSWORD}" 30 | command: 31 | mongod --quiet --logpath /dev/null -------------------------------------------------------------------------------- /compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | web: 3 | image: ora:004 4 | env_file: 5 | - .env 6 | command: bash -c " 7 | uvicorn greens.main:app 8 | --host 0.0.0.0 --port 8989 9 | --lifespan=on --use-colors --loop uvloop --http httptools 10 | --reload 11 | " 12 | volumes: 13 | - ./greens:/app/greens 14 | - ./tests:/app/tests 15 | ports: 16 | - "8989:8989" 17 | depends_on: 18 | - mongodb 19 | 20 | mongodb: 21 | image: mongo:7.0.8 22 | env_file: 23 | - .env 24 | ports: 25 | - "27017:27017" 26 | environment: 27 | - "MONGO_INITDB_DATABASE=${MONGODB_DATABASE}" 28 | - "MONGO_INITDB_ROOT_USERNAME=${MONGODB_USER}" 29 | - "MONGO_INITDB_ROOT_PASSWORD=${MONGODB_PASSWORD}" 30 | command: 31 | mongod --quiet --logpath /dev/null -------------------------------------------------------------------------------- /greens/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grillazz/fastapi-mongodb/8be744d10244260fcdaf31577bbc04f6fe563766/greens/__init__.py -------------------------------------------------------------------------------- /greens/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from pydantic import MongoDsn, computed_field 4 | from pydantic_core import MultiHostUrl 5 | from pydantic_settings import BaseSettings 6 | 7 | 8 | class Settings(BaseSettings): 9 | """Settings for the application""" 10 | 11 | environment: str = os.getenv("ENVIRONMENT", "local") 12 | testing: str = os.getenv("TESTING", "0") 13 | up: str = os.getenv("UP", "up") 14 | down: str = os.getenv("DOWN", "down") 15 | web_server: str = os.getenv("WEB_SERVER", "web_server") 16 | 17 | mongodb_database: str = os.getenv("MONGODB_DATABASE", "") 18 | mongodb_collection: str = os.getenv("MONGODB_COLLECTION", "") 19 | mongodb_test: str = os.getenv("MONGODB_TEST", "") 20 | 21 | MONGODB_HOST: str 22 | MONGODB_PORT: int 23 | MONGODB_USER: str 24 | MONGODB_PASSWORD: str 25 | MONGODB_PARAMS: str 26 | 27 | @computed_field 28 | @property 29 | def mongodb_url(self) -> MongoDsn: 30 | return MongoDsn.build( 31 | scheme="mongodb", 32 | host=self.MONGODB_HOST, 33 | port=self.MONGODB_PORT, 34 | username=self.MONGODB_USER, 35 | password=self.MONGODB_PASSWORD, 36 | path=self.MONGODB_PARAMS, 37 | ) 38 | 39 | 40 | settings = Settings() 41 | -------------------------------------------------------------------------------- /greens/main.py: -------------------------------------------------------------------------------- 1 | from contextlib import asynccontextmanager 2 | 3 | from fastapi import FastAPI 4 | 5 | from greens.config import settings as global_settings 6 | from greens.routers import router as v1 7 | from greens.services.repository import get_mongo_meta 8 | from greens.utils import get_logger, init_mongo 9 | 10 | if global_settings.environment == "local": 11 | get_logger("uvicorn") 12 | 13 | 14 | @asynccontextmanager 15 | async def lifespan(app: FastAPI): 16 | app.state.logger = get_logger(__name__) 17 | app.state.logger.info("Starting greens on your farmland...mmm") 18 | app.state.mongo_client, app.state.mongo_db, app.state.mongo_collection = await init_mongo( 19 | global_settings.mongodb_database, 20 | global_settings.mongodb_url.unicode_string(), 21 | global_settings.mongodb_collection, 22 | ) 23 | try: 24 | yield 25 | finally: 26 | app.state.logger.info("Parking tractors in garage...") 27 | 28 | 29 | app = FastAPI(lifespan=lifespan, title="Greens API", version="0.5.0") 30 | 31 | app.include_router(v1, prefix="/api/v1") 32 | 33 | 34 | @app.get("/health-check") 35 | async def health_check(): 36 | # # TODO: check settings dependencies passing as args and kwargs 37 | # a = 5 38 | # try: 39 | # assert 5 / 0 40 | # except Exception: 41 | # app.state.logger.exception("My way or highway...") 42 | return await get_mongo_meta() 43 | -------------------------------------------------------------------------------- /greens/routers/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | from greens.routers.v1.vegs import router as vegs_api 4 | 5 | router = APIRouter() 6 | 7 | router.include_router(vegs_api, prefix="/vegs", tags=["vegetables"]) 8 | -------------------------------------------------------------------------------- /greens/routers/exceptions.py: -------------------------------------------------------------------------------- 1 | from fastapi import HTTPException, status 2 | 3 | 4 | class NotFoundHTTPException(HTTPException): 5 | def __init__(self, msg: str): 6 | super().__init__( 7 | status_code=status.HTTP_404_NOT_FOUND, 8 | detail=msg if msg else "Requested resource is not found", 9 | ) 10 | 11 | 12 | class AlreadyExistsHTTPException(HTTPException): 13 | def __init__(self, msg: str): 14 | super().__init__( 15 | status_code=status.HTTP_409_CONFLICT, 16 | detail=msg if msg else "Document with specified id already exists", 17 | ) 18 | -------------------------------------------------------------------------------- /greens/routers/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grillazz/fastapi-mongodb/8be744d10244260fcdaf31577bbc04f6fe563766/greens/routers/v1/__init__.py -------------------------------------------------------------------------------- /greens/routers/v1/vegs.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from starlette.status import HTTP_201_CREATED 3 | 4 | from greens.config import settings as global_settings 5 | from greens.routers.exceptions import NotFoundHTTPException 6 | from greens.schemas.vegs import Document, DocumentResponse, ObjectIdField 7 | from greens.services.repository import create_document, retrieve_document 8 | 9 | collection = global_settings.mongodb_collection 10 | 11 | router = APIRouter() 12 | 13 | 14 | @router.post( 15 | "", 16 | status_code=HTTP_201_CREATED, 17 | response_description="Document created", 18 | response_model=DocumentResponse, 19 | ) 20 | async def add_document(payload: Document): 21 | """ 22 | 23 | :param payload: 24 | :return: 25 | """ 26 | try: 27 | # payload = jsonable_encoder(payload) 28 | document = await create_document(payload, collection) 29 | return {"id": str(document.inserted_id)} 30 | except ValueError as exception: 31 | raise NotFoundHTTPException(msg=str(exception)) from exception 32 | 33 | 34 | @router.get( 35 | "/{object_id}", 36 | response_description="Document retrieved", 37 | response_model=DocumentResponse, 38 | ) 39 | async def get_document(object_id: ObjectIdField): 40 | """ 41 | 42 | :param object_id: 43 | :return: 44 | """ 45 | try: 46 | return await retrieve_document(object_id, collection) 47 | except (ValueError, TypeError) as exception: 48 | raise NotFoundHTTPException(msg=str(exception)) from exception 49 | 50 | 51 | # TODO: PUT for replace aka set PATCH for update ? 52 | -------------------------------------------------------------------------------- /greens/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grillazz/fastapi-mongodb/8be744d10244260fcdaf31577bbc04f6fe563766/greens/schemas/__init__.py -------------------------------------------------------------------------------- /greens/schemas/vegs.py: -------------------------------------------------------------------------------- 1 | from bson import ObjectId as _ObjectId 2 | from pydantic import BaseModel, ConfigDict, BeforeValidator 3 | from typing import Annotated 4 | 5 | 6 | # def check_object_id(value: str) -> str: 7 | # if not _ObjectId.is_valid(value): 8 | # raise ValueError('Invalid ObjectId') 9 | # return value 10 | 11 | 12 | def check_object_id(value: _ObjectId) -> str: 13 | """ 14 | Checks if the given _ObjectId is valid and returns it as a string. 15 | 16 | Args: 17 | value: The _ObjectId to be checked. 18 | 19 | Returns: 20 | str: The _ObjectId as a string. 21 | 22 | Raises: 23 | ValueError: If the _ObjectId is invalid. 24 | """ 25 | 26 | if not _ObjectId.is_valid(value): 27 | raise ValueError("Invalid ObjectId") 28 | return str(value) 29 | 30 | 31 | ObjectIdField = Annotated[str, BeforeValidator(check_object_id)] 32 | 33 | config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True) 34 | 35 | 36 | class Document(BaseModel): 37 | model_config = config 38 | 39 | name: str 40 | desc: str 41 | 42 | 43 | class DocumentResponse(BaseModel): 44 | id: ObjectIdField 45 | -------------------------------------------------------------------------------- /greens/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grillazz/fastapi-mongodb/8be744d10244260fcdaf31577bbc04f6fe563766/greens/services/__init__.py -------------------------------------------------------------------------------- /greens/services/repository.py: -------------------------------------------------------------------------------- 1 | from bson import ObjectId 2 | from pymongo.errors import WriteError 3 | from pymongo.results import InsertOneResult 4 | 5 | import greens.main as greens 6 | from greens.routers.exceptions import AlreadyExistsHTTPException 7 | 8 | 9 | async def document_id_helper(document: dict) -> dict: 10 | document["id"] = document.pop("_id") 11 | return document 12 | 13 | 14 | async def retrieve_document(document_id: str, collection: str) -> dict: 15 | """ 16 | 17 | :param document_id: 18 | :param collection: 19 | :return: 20 | """ 21 | document_filter = {"_id": ObjectId(document_id)} 22 | if document := await greens.app.state.mongo_collection[collection].find_one(document_filter): 23 | return await document_id_helper(document) 24 | else: 25 | raise ValueError(f"No document found for {document_id=} in {collection=}") 26 | 27 | 28 | async def create_document(document, collection: str) -> InsertOneResult: 29 | """ 30 | 31 | :param document: 32 | :param collection: 33 | :return: 34 | """ 35 | try: 36 | document: InsertOneResult = await greens.app.state.mongo_collection[collection].insert_one( 37 | document.model_dump() 38 | ) 39 | return document 40 | except WriteError as e: 41 | # TODO: this not make sense as id from mongo will be always unique if we not pass it 42 | raise AlreadyExistsHTTPException(msg=str(e)) from e 43 | 44 | 45 | async def get_mongo_meta() -> dict: 46 | list_databases = await greens.app.state.mongo_client.list_database_names() 47 | list_of_collections = {} 48 | for db in list_databases: 49 | list_of_collections[db] = await greens.app.state.mongo_client[db].list_collection_names() 50 | mongo_meta = await greens.app.state.mongo_client.server_info() 51 | return { 52 | "version": mongo_meta["version"], 53 | "databases": list_databases, 54 | "collections": list_of_collections, 55 | } 56 | -------------------------------------------------------------------------------- /greens/utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from functools import lru_cache 3 | 4 | from motor.motor_asyncio import AsyncIOMotorClient 5 | from rich.console import Console 6 | from rich.logging import RichHandler 7 | 8 | console = Console(color_system="256", width=150, style="blue") 9 | 10 | 11 | @lru_cache 12 | def get_logger(module_name): 13 | """ 14 | 15 | Args: 16 | module_name: 17 | 18 | Returns: 19 | 20 | """ 21 | logger = logging.getLogger(module_name) 22 | handler = RichHandler(rich_tracebacks=True, console=console, tracebacks_show_locals=True) 23 | handler.setFormatter(logging.Formatter("%(name)s - [ %(threadName)s:%(funcName)s:%(lineno)d ] - %(message)s")) 24 | logger.addHandler(handler) 25 | logger.setLevel(logging.DEBUG) 26 | return logger 27 | 28 | 29 | async def init_mongo(db_name: str, db_url: str, collection: str): 30 | """ 31 | 32 | Args: 33 | db_name: 34 | db_url: 35 | collection: 36 | 37 | Returns: 38 | 39 | """ 40 | mongo_client = AsyncIOMotorClient(db_url) 41 | mongo_database = mongo_client[db_name] 42 | mongo_collections = { 43 | collection: mongo_database.get_collection(collection), 44 | } 45 | # return {0: mongo_client, 1: mongo_database, 2: mongo_collections} 46 | return mongo_client, mongo_database, mongo_collections 47 | -------------------------------------------------------------------------------- /log-conf.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | disable_existing_loggers: False 3 | -------------------------------------------------------------------------------- /pyproject.tbd: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "fastapi-mongodb" 3 | version = "0.6.0" 4 | description = "" 5 | authors = ["Jakub Miazek "] 6 | readme = "README.md" 7 | packages = [{ include = "fastapi_mongodb" }] 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.12" 11 | fastapi = "^0.111.0" 12 | pydantic = { version = "^2.7.0", extras = ["email"] } 13 | pydantic-settings = "^2.2.1" 14 | motor = "^3.4.0" 15 | uvicorn = { version = "^0uv.29.0", extras = ["standard"] } 16 | pytest = "^8.1.1" 17 | pytest-cov = "^5.0.0" 18 | httpx = "^0.27.0" 19 | rich = "^13.7.1" 20 | uvloop = "^0.19.0" 21 | httptools = "^0.6.1" 22 | ruff = "^0.4.4" 23 | inline-snapshot = "^0.9.0" 24 | 25 | [build-system] 26 | requires = ["poetry-core>=1.0.0"] 27 | build-backend = "poetry.core.masonry.api" 28 | 29 | [tool.ruff] 30 | line-length = 120 31 | indent-width = 4 32 | 33 | lint.select = ["E", "F", "UP", "N", "C", "B"] 34 | lint.ignore = ["E501"] 35 | 36 | # Assume Python 3.12 37 | target-version = "py312" 38 | 39 | [tool.ruff.lint.flake8-quotes] 40 | docstring-quotes = "double" 41 | 42 | [tool.ruff.lint.flake8-bugbear] 43 | extend-immutable-calls = ["fastapi.Depends",] 44 | 45 | [tool.pytest.ini_options] 46 | addopts = "-v --doctest-modules --doctest-glob=*.md --cov=. --cov-report html:htmlcov --cov-report=term-missing" 47 | asyncio_mode = "strict" 48 | env_files = [".env"] 49 | 50 | [tool.ruff.format] 51 | # Like Black, use double quotes for strings. 52 | quote-style = "double" 53 | 54 | # Like Black, indent with spaces, rather than tabs. 55 | indent-style = "space" 56 | 57 | # Like Black, respect magic trailing commas. 58 | skip-magic-trailing-comma = false 59 | 60 | # Like Black, automatically detect the appropriate line ending. 61 | line-ending = "auto" -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "fastapi-mongodb" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "fastapi[standard]>=0.115.8", 9 | "httptools>=0.6.4", 10 | "httpx>=0.28.1", 11 | "inline-snapshot>=0.18.2", 12 | "motor>=3.6.0", 13 | "pydantic>=2.11.0a1", 14 | "pydantic-settings>=2.7.1", 15 | "pytest>=8.3.4", 16 | "pytest-cov>=6.0.0", 17 | "rich>=13.9.4", 18 | "ruff>=0.9.4", 19 | "uvicorn>=0.34.0", 20 | "uvloop>=0.21.0", 21 | ] 22 | -------------------------------------------------------------------------------- /static/greens.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grillazz/fastapi-mongodb/8be744d10244260fcdaf31577bbc04f6fe563766/static/greens.jpg -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grillazz/fastapi-mongodb/8be744d10244260fcdaf31577bbc04f6fe563766/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | from collections.abc import AsyncGenerator 2 | 3 | import pytest 4 | from httpx import AsyncClient, ASGITransport 5 | 6 | from greens.config import settings as global_settings 7 | from greens.main import app, init_mongo 8 | from greens.utils import get_logger 9 | 10 | 11 | @pytest.fixture( 12 | params=[ 13 | pytest.param(("asyncio", {"use_uvloop": True}), id="asyncio+uvloop"), 14 | ] 15 | ) 16 | def anyio_backend(request): 17 | return request.param 18 | 19 | 20 | @pytest.fixture 21 | async def client() -> AsyncGenerator[AsyncClient]: 22 | transport = ASGITransport( 23 | app=app, 24 | ) 25 | async with AsyncClient( 26 | base_url="http://testserver", 27 | transport=transport, 28 | ) as client: 29 | app.state.logger = get_logger(__name__) 30 | app.state.mongo_client, app.state.mongo_db, app.state.mongo_collection = await init_mongo( 31 | global_settings.mongodb_test, 32 | global_settings.mongodb_url.unicode_string(), 33 | global_settings.mongodb_collection, 34 | ) 35 | yield client 36 | -------------------------------------------------------------------------------- /tests/test_routers.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from fastapi import status 3 | from httpx import AsyncClient 4 | from inline_snapshot import snapshot 5 | 6 | 7 | @pytest.mark.anyio 8 | async def test_health_check(client: AsyncClient): 9 | response = await client.get("/health-check") 10 | assert response.status_code == status.HTTP_200_OK 11 | assert response.json() == snapshot( 12 | { 13 | "version": "7.0.8", 14 | "databases": [ 15 | "admin", 16 | "config", 17 | # "farmland", 18 | "local" 19 | ], 20 | "collections": { 21 | "admin": ["system.version", "system.users"], 22 | "config": ["system.sessions"], 23 | # "farmland": ["greens"], 24 | "local": ["startup_log"], 25 | }, 26 | } 27 | ) 28 | -------------------------------------------------------------------------------- /tests/test_schemas.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from bson import ObjectId 3 | 4 | from greens.schemas.vegs import DocumentResponse 5 | 6 | 7 | # Since ObjectIdField is not a standard Pydantic field, we'll assume it's a custom field 8 | # that should accept BSON ObjectId instances. We'll need to mock or construct valid and 9 | # invalid ObjectId instances for testing. 10 | 11 | 12 | # Helper function to create a valid ObjectId instance 13 | def create_valid_objectid(): 14 | return ObjectId() 15 | 16 | 17 | # Helper function to create an invalid ObjectId instance 18 | def create_invalid_objectid(): 19 | return "invalid_objectid" 20 | 21 | 22 | # Happy path tests with various realistic test values 23 | @pytest.mark.parametrize( 24 | "test_id, object_id", 25 | [ 26 | ("HP-1", create_valid_objectid()), 27 | # Add more test cases with different valid ObjectIds if necessary 28 | ], 29 | ) 30 | def test_document_response_with_valid_id(test_id, object_id): 31 | # Act 32 | document_response = DocumentResponse(id=object_id) 33 | 34 | # Assert 35 | assert document_response.id == str( 36 | object_id 37 | ), f"Test case {test_id} failed: The id field did not match the input ObjectId." 38 | 39 | 40 | # Edge cases 41 | # Assuming edge cases would be related to the boundaries of ObjectId creation and representation 42 | # Since ObjectId is a specific BSON type, edge cases might not be as relevant here, 43 | # but we can still test for unusual but valid ObjectIds 44 | 45 | 46 | # Error cases 47 | @pytest.mark.parametrize( 48 | "test_id, object_id, expected_exception", 49 | [ 50 | ("EC-1", create_invalid_objectid(), ValueError), # Invalid ObjectId format 51 | ("EC-2", None, ValueError), # None as an ObjectId 52 | ("EC-3", 12345, ValueError), # Integer as an ObjectId 53 | # Add more test cases with different invalid ObjectIds if necessary 54 | ], 55 | ) 56 | def test_document_response_with_invalid_id(test_id, object_id, expected_exception): 57 | # Act and Assert 58 | with pytest.raises(expected_exception) as exc_info: 59 | DocumentResponse(id=object_id) 60 | 61 | assert str(exc_info.value), f"Test case {test_id} failed: Expected exception {expected_exception} was not raised." 62 | -------------------------------------------------------------------------------- /tests/test_vegs_api.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from bson import ObjectId 3 | from fastapi import status 4 | from httpx import AsyncClient 5 | 6 | pytestmark = pytest.mark.anyio 7 | 8 | 9 | @pytest.mark.parametrize( 10 | "payload, status_code", 11 | ( 12 | ( 13 | {"name": "Corn", "desc": "Corn on the cob"}, 14 | status.HTTP_201_CREATED, 15 | ), 16 | ), 17 | ) 18 | # Test document create endpoint 19 | async def test_add_document(client: AsyncClient, payload: dict, status_code: int): 20 | # Send POST request 21 | response = await client.post("/api/v1/vegs", json=payload) 22 | # Assert HTTP code and if received document id is valid 23 | assert response.status_code == status_code 24 | assert ObjectId.is_valid(response.json()["id"]) 25 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.12" 3 | 4 | [[package]] 5 | name = "annotated-types" 6 | version = "0.7.0" 7 | source = { registry = "https://pypi.org/simple" } 8 | sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } 9 | wheels = [ 10 | { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, 11 | ] 12 | 13 | [[package]] 14 | name = "anyio" 15 | version = "4.8.0" 16 | source = { registry = "https://pypi.org/simple" } 17 | dependencies = [ 18 | { name = "idna" }, 19 | { name = "sniffio" }, 20 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 21 | ] 22 | sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } 23 | wheels = [ 24 | { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, 25 | ] 26 | 27 | [[package]] 28 | name = "asttokens" 29 | version = "3.0.0" 30 | source = { registry = "https://pypi.org/simple" } 31 | sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } 32 | wheels = [ 33 | { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, 34 | ] 35 | 36 | [[package]] 37 | name = "black" 38 | version = "24.10.0" 39 | source = { registry = "https://pypi.org/simple" } 40 | dependencies = [ 41 | { name = "click" }, 42 | { name = "mypy-extensions" }, 43 | { name = "packaging" }, 44 | { name = "pathspec" }, 45 | { name = "platformdirs" }, 46 | ] 47 | sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } 48 | wheels = [ 49 | { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, 50 | { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, 51 | { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, 52 | { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, 53 | { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, 54 | { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, 55 | { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, 56 | { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, 57 | { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, 58 | ] 59 | 60 | [[package]] 61 | name = "certifi" 62 | version = "2024.12.14" 63 | source = { registry = "https://pypi.org/simple" } 64 | sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } 65 | wheels = [ 66 | { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, 67 | ] 68 | 69 | [[package]] 70 | name = "click" 71 | version = "8.1.8" 72 | source = { registry = "https://pypi.org/simple" } 73 | dependencies = [ 74 | { name = "colorama", marker = "sys_platform == 'win32'" }, 75 | ] 76 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } 77 | wheels = [ 78 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, 79 | ] 80 | 81 | [[package]] 82 | name = "colorama" 83 | version = "0.4.6" 84 | source = { registry = "https://pypi.org/simple" } 85 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 86 | wheels = [ 87 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 88 | ] 89 | 90 | [[package]] 91 | name = "coverage" 92 | version = "7.6.10" 93 | source = { registry = "https://pypi.org/simple" } 94 | sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 } 95 | wheels = [ 96 | { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 }, 97 | { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 }, 98 | { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 }, 99 | { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 }, 100 | { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 }, 101 | { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 }, 102 | { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 }, 103 | { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 }, 104 | { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 }, 105 | { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 }, 106 | { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 }, 107 | { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 }, 108 | { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 }, 109 | { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 }, 110 | { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 }, 111 | { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 }, 112 | { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 }, 113 | { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 }, 114 | { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 }, 115 | { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 }, 116 | { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 }, 117 | { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 }, 118 | { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 }, 119 | { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 }, 120 | { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 }, 121 | { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 }, 122 | { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 }, 123 | { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 }, 124 | { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 }, 125 | { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 }, 126 | ] 127 | 128 | [[package]] 129 | name = "dnspython" 130 | version = "2.7.0" 131 | source = { registry = "https://pypi.org/simple" } 132 | sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } 133 | wheels = [ 134 | { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, 135 | ] 136 | 137 | [[package]] 138 | name = "email-validator" 139 | version = "2.2.0" 140 | source = { registry = "https://pypi.org/simple" } 141 | dependencies = [ 142 | { name = "dnspython" }, 143 | { name = "idna" }, 144 | ] 145 | sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 } 146 | wheels = [ 147 | { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, 148 | ] 149 | 150 | [[package]] 151 | name = "executing" 152 | version = "2.1.0" 153 | source = { registry = "https://pypi.org/simple" } 154 | sdist = { url = "https://files.pythonhosted.org/packages/8c/e3/7d45f492c2c4a0e8e0fad57d081a7c8a0286cdd86372b070cca1ec0caa1e/executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab", size = 977485 } 155 | wheels = [ 156 | { url = "https://files.pythonhosted.org/packages/b5/fd/afcd0496feca3276f509df3dbd5dae726fcc756f1a08d9e25abe1733f962/executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", size = 25805 }, 157 | ] 158 | 159 | [[package]] 160 | name = "fastapi" 161 | version = "0.115.8" 162 | source = { registry = "https://pypi.org/simple" } 163 | dependencies = [ 164 | { name = "pydantic" }, 165 | { name = "starlette" }, 166 | { name = "typing-extensions" }, 167 | ] 168 | sdist = { url = "https://files.pythonhosted.org/packages/a2/b2/5a5dc4affdb6661dea100324e19a7721d5dc524b464fe8e366c093fd7d87/fastapi-0.115.8.tar.gz", hash = "sha256:0ce9111231720190473e222cdf0f07f7206ad7e53ea02beb1d2dc36e2f0741e9", size = 295403 } 169 | wheels = [ 170 | { url = "https://files.pythonhosted.org/packages/8f/7d/2d6ce181d7a5f51dedb8c06206cbf0ec026a99bf145edd309f9e17c3282f/fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf", size = 94814 }, 171 | ] 172 | 173 | [package.optional-dependencies] 174 | standard = [ 175 | { name = "email-validator" }, 176 | { name = "fastapi-cli", extra = ["standard"] }, 177 | { name = "httpx" }, 178 | { name = "jinja2" }, 179 | { name = "python-multipart" }, 180 | { name = "uvicorn", extra = ["standard"] }, 181 | ] 182 | 183 | [[package]] 184 | name = "fastapi-cli" 185 | version = "0.0.7" 186 | source = { registry = "https://pypi.org/simple" } 187 | dependencies = [ 188 | { name = "rich-toolkit" }, 189 | { name = "typer" }, 190 | { name = "uvicorn", extra = ["standard"] }, 191 | ] 192 | sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753 } 193 | wheels = [ 194 | { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705 }, 195 | ] 196 | 197 | [package.optional-dependencies] 198 | standard = [ 199 | { name = "uvicorn", extra = ["standard"] }, 200 | ] 201 | 202 | [[package]] 203 | name = "fastapi-mongodb" 204 | version = "0.1.0" 205 | source = { virtual = "." } 206 | dependencies = [ 207 | { name = "fastapi", extra = ["standard"] }, 208 | { name = "httptools" }, 209 | { name = "httpx" }, 210 | { name = "inline-snapshot" }, 211 | { name = "motor" }, 212 | { name = "pydantic" }, 213 | { name = "pydantic-settings" }, 214 | { name = "pytest" }, 215 | { name = "pytest-cov" }, 216 | { name = "rich" }, 217 | { name = "ruff" }, 218 | { name = "uvicorn" }, 219 | { name = "uvloop" }, 220 | ] 221 | 222 | [package.metadata] 223 | requires-dist = [ 224 | { name = "fastapi", extras = ["standard"], specifier = ">=0.115.8" }, 225 | { name = "httptools", specifier = ">=0.6.4" }, 226 | { name = "httpx", specifier = ">=0.28.1" }, 227 | { name = "inline-snapshot", specifier = ">=0.18.2" }, 228 | { name = "motor", specifier = ">=3.6.0" }, 229 | { name = "pydantic", specifier = ">=2.11.0a1" }, 230 | { name = "pydantic-settings", specifier = ">=2.7.1" }, 231 | { name = "pytest", specifier = ">=8.3.4" }, 232 | { name = "pytest-cov", specifier = ">=6.0.0" }, 233 | { name = "rich", specifier = ">=13.9.4" }, 234 | { name = "ruff", specifier = ">=0.9.4" }, 235 | { name = "uvicorn", specifier = ">=0.34.0" }, 236 | { name = "uvloop", specifier = ">=0.21.0" }, 237 | ] 238 | 239 | [[package]] 240 | name = "h11" 241 | version = "0.14.0" 242 | source = { registry = "https://pypi.org/simple" } 243 | sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } 244 | wheels = [ 245 | { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, 246 | ] 247 | 248 | [[package]] 249 | name = "httpcore" 250 | version = "1.0.7" 251 | source = { registry = "https://pypi.org/simple" } 252 | dependencies = [ 253 | { name = "certifi" }, 254 | { name = "h11" }, 255 | ] 256 | sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } 257 | wheels = [ 258 | { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, 259 | ] 260 | 261 | [[package]] 262 | name = "httptools" 263 | version = "0.6.4" 264 | source = { registry = "https://pypi.org/simple" } 265 | sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 } 266 | wheels = [ 267 | { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683 }, 268 | { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337 }, 269 | { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796 }, 270 | { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/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", size = 510837 }, 271 | { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 }, 272 | { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 }, 273 | { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 }, 274 | { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 }, 275 | { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 }, 276 | { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 }, 277 | { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/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", size = 473805 }, 278 | { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 }, 279 | { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 }, 280 | { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 }, 281 | ] 282 | 283 | [[package]] 284 | name = "httpx" 285 | version = "0.28.1" 286 | source = { registry = "https://pypi.org/simple" } 287 | dependencies = [ 288 | { name = "anyio" }, 289 | { name = "certifi" }, 290 | { name = "httpcore" }, 291 | { name = "idna" }, 292 | ] 293 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } 294 | wheels = [ 295 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, 296 | ] 297 | 298 | [[package]] 299 | name = "idna" 300 | version = "3.10" 301 | source = { registry = "https://pypi.org/simple" } 302 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 303 | wheels = [ 304 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 305 | ] 306 | 307 | [[package]] 308 | name = "iniconfig" 309 | version = "2.0.0" 310 | source = { registry = "https://pypi.org/simple" } 311 | sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } 312 | wheels = [ 313 | { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, 314 | ] 315 | 316 | [[package]] 317 | name = "inline-snapshot" 318 | version = "0.18.2" 319 | source = { registry = "https://pypi.org/simple" } 320 | dependencies = [ 321 | { name = "asttokens" }, 322 | { name = "black" }, 323 | { name = "click" }, 324 | { name = "executing" }, 325 | { name = "rich" }, 326 | { name = "typing-extensions" }, 327 | ] 328 | sdist = { url = "https://files.pythonhosted.org/packages/c8/2d/c4cec2ae99d2d5d3689cd236018a4730bda75f3576e1c5cc04a4cca44dd7/inline_snapshot-0.18.2.tar.gz", hash = "sha256:1be34afa453b75d120e12e8fb4724e28cb23f71b8f0fb0a7bc822a78c97ff826", size = 225777 } 329 | wheels = [ 330 | { url = "https://files.pythonhosted.org/packages/38/8d/45b249bea2884082360af8cb0c5860a0b9b7ce98291a588067906e70b1aa/inline_snapshot-0.18.2-py3-none-any.whl", hash = "sha256:fd5328a38ab089c565f35abac91bb6bc0bbc54cc7b55b1b2a86a7168146225ca", size = 42325 }, 331 | ] 332 | 333 | [[package]] 334 | name = "jinja2" 335 | version = "3.1.5" 336 | source = { registry = "https://pypi.org/simple" } 337 | dependencies = [ 338 | { name = "markupsafe" }, 339 | ] 340 | sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } 341 | wheels = [ 342 | { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, 343 | ] 344 | 345 | [[package]] 346 | name = "markdown-it-py" 347 | version = "3.0.0" 348 | source = { registry = "https://pypi.org/simple" } 349 | dependencies = [ 350 | { name = "mdurl" }, 351 | ] 352 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } 353 | wheels = [ 354 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, 355 | ] 356 | 357 | [[package]] 358 | name = "markupsafe" 359 | version = "3.0.2" 360 | source = { registry = "https://pypi.org/simple" } 361 | sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } 362 | wheels = [ 363 | { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, 364 | { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, 365 | { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, 366 | { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, 367 | { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, 368 | { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, 369 | { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, 370 | { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, 371 | { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, 372 | { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, 373 | { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, 374 | { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, 375 | { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, 376 | { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, 377 | { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, 378 | { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, 379 | { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, 380 | { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, 381 | { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, 382 | { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, 383 | { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, 384 | { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, 385 | { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, 386 | { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, 387 | { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, 388 | { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, 389 | { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, 390 | { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, 391 | { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, 392 | { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, 393 | ] 394 | 395 | [[package]] 396 | name = "mdurl" 397 | version = "0.1.2" 398 | source = { registry = "https://pypi.org/simple" } 399 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } 400 | wheels = [ 401 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, 402 | ] 403 | 404 | [[package]] 405 | name = "motor" 406 | version = "3.6.0" 407 | source = { registry = "https://pypi.org/simple" } 408 | dependencies = [ 409 | { name = "pymongo" }, 410 | ] 411 | sdist = { url = "https://files.pythonhosted.org/packages/6a/d1/06af0527fd02d49b203db70dba462e47275a3c1094f830fdaf090f0cb20c/motor-3.6.0.tar.gz", hash = "sha256:0ef7f520213e852bf0eac306adf631aabe849227d8aec900a2612512fb9c5b8d", size = 278447 } 412 | wheels = [ 413 | { url = "https://files.pythonhosted.org/packages/b4/c2/bba4dce0dc56e49d95c270c79c9330ed19e6b71a2a633aecf53e7e1f04c9/motor-3.6.0-py3-none-any.whl", hash = "sha256:9f07ed96f1754963d4386944e1b52d403a5350c687edc60da487d66f98dbf894", size = 74802 }, 414 | ] 415 | 416 | [[package]] 417 | name = "mypy-extensions" 418 | version = "1.0.0" 419 | source = { registry = "https://pypi.org/simple" } 420 | sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } 421 | wheels = [ 422 | { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, 423 | ] 424 | 425 | [[package]] 426 | name = "packaging" 427 | version = "24.2" 428 | source = { registry = "https://pypi.org/simple" } 429 | sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } 430 | wheels = [ 431 | { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, 432 | ] 433 | 434 | [[package]] 435 | name = "pathspec" 436 | version = "0.12.1" 437 | source = { registry = "https://pypi.org/simple" } 438 | sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } 439 | wheels = [ 440 | { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, 441 | ] 442 | 443 | [[package]] 444 | name = "platformdirs" 445 | version = "4.3.6" 446 | source = { registry = "https://pypi.org/simple" } 447 | sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } 448 | wheels = [ 449 | { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, 450 | ] 451 | 452 | [[package]] 453 | name = "pluggy" 454 | version = "1.5.0" 455 | source = { registry = "https://pypi.org/simple" } 456 | sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } 457 | wheels = [ 458 | { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, 459 | ] 460 | 461 | [[package]] 462 | name = "pydantic" 463 | version = "2.11.0a1" 464 | source = { registry = "https://pypi.org/simple" } 465 | dependencies = [ 466 | { name = "annotated-types" }, 467 | { name = "pydantic-core" }, 468 | { name = "typing-extensions" }, 469 | ] 470 | sdist = { url = "https://files.pythonhosted.org/packages/3f/c6/b2a9935c6ce86a462b1fe3a544ffdf1076f7bae98e9060cb134da719ed00/pydantic-2.11.0a1.tar.gz", hash = "sha256:0c3987792f6201adcded4316fce0968f09d5b4fc85fb4e2f5c30107f5c910da4", size = 766922 } 471 | wheels = [ 472 | { url = "https://files.pythonhosted.org/packages/6c/93/4f5ebb854f9e5fc37f8fa6f62004ec809209248928e2a29ea142ee217ada/pydantic-2.11.0a1-py3-none-any.whl", hash = "sha256:32e3095ed0b21aa87be80fbe5a8d114133a4f40432d8594d88930a0a000ad7aa", size = 435838 }, 473 | ] 474 | 475 | [[package]] 476 | name = "pydantic-core" 477 | version = "2.28.0" 478 | source = { registry = "https://pypi.org/simple" } 479 | dependencies = [ 480 | { name = "typing-extensions" }, 481 | ] 482 | sdist = { url = "https://files.pythonhosted.org/packages/24/23/efff2ea25900c6c0ca3c39603df1768cca512cc3e5193ca217cba164ed6c/pydantic_core-2.28.0.tar.gz", hash = "sha256:4aea61530f9fdc8f128a4772c0fdbce9159ecea03201c16fe2e4ba7ebd11b173", size = 414268 } 483 | wheels = [ 484 | { url = "https://files.pythonhosted.org/packages/48/ff/af9edb525c757afbc36eabae0377a4381c4d2b095a11107943491eeb0391/pydantic_core-2.28.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8357aa0ab28f6ce186592af4e3c5db5b40591d64241cad8a8ece2abf5da1fbd7", size = 2014586 }, 485 | { url = "https://files.pythonhosted.org/packages/03/eb/772772ec9e485e3bf8aa815ba28b209ee3efdfc930023468b9b361adbcd5/pydantic_core-2.28.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e0edfd71fa3eb872395c8b6d366fc9047c12b82252a0512e9173d7be53489649", size = 1880566 }, 486 | { url = "https://files.pythonhosted.org/packages/36/a8/3302977e0d604ff89ad774ec437d125cd3456408813d4dbffd414eb6fc55/pydantic_core-2.28.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba5caeeea45dfc0ae3b66f84268419dfe90a201e0ce5179662f4b8b019e82e7", size = 1896220 }, 487 | { url = "https://files.pythonhosted.org/packages/24/f3/d74e3ced8c5694b6abbe383dd0db84137ceb4aab6051ced65aeb06f53ff6/pydantic_core-2.28.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f4af4a355d8833e2e40ced000b1532173d7568325372bd0fa120f830d4d5c56", size = 1977576 }, 488 | { url = "https://files.pythonhosted.org/packages/1e/d9/0e3ed173f396b46d30599dc134b206b3044f52f9b116d1165aa97faba73e/pydantic_core-2.28.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6beb7a89fa2a895f5e2d4c961585a5fee8fca8d48630d1c696e1653facfe053f", size = 2116041 }, 489 | { url = "https://files.pythonhosted.org/packages/c6/ec/085686b45f1575641bbf06df00b29ea5063b8cce4a9b1b05a2147956b9e1/pydantic_core-2.28.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea2291429639edf31dd569226ce74733228ae507334c1065650f67785f0351f0", size = 2708425 }, 490 | { url = "https://files.pythonhosted.org/packages/e3/3f/d07209148ea27bd6128f04f86018e5c01916dc5c0f695d5a540e5a13f6b8/pydantic_core-2.28.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8406884e7ab057f0f2075f42fdd5083cecc1fe160b6377d128f47efc606ef708", size = 2044887 }, 491 | { url = "https://files.pythonhosted.org/packages/20/a0/fb7cf7317ef8884df60267f3209aa3beb976b62b83bccf8393ab7b02b3b8/pydantic_core-2.28.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:38d3ac50fa89e68ebacc80b9873c6ff2267dd14b4ee62d5aecc9685eb785148f", size = 2117464 }, 492 | { url = "https://files.pythonhosted.org/packages/fe/01/b9512590c73ce2403a531a0894698f8d9f48e523ac7fb7a6db6ec61f7ed9/pydantic_core-2.28.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bb97942c9f74e2b49a8d3d37e4f8d9a88418d738bb0adeb5b4ff565736156bfe", size = 2056680 }, 493 | { url = "https://files.pythonhosted.org/packages/cc/c1/0716633ddd23f57b5b09d64bbdbefb91e08b67060ccd6b932e0738e04a26/pydantic_core-2.28.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:70ae7812009086b951854198ddd5f051af63a7ac2df62aa74b09c2078ee74617", size = 2227133 }, 494 | { url = "https://files.pythonhosted.org/packages/ee/50/f091210616d3253eefa7754284a51baf7357f9573a7306cfeebc335004a7/pydantic_core-2.28.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:24954bfa4884983b8186fcf0277758abc1db458b589fc527244b7935efaa149a", size = 2226946 }, 495 | { url = "https://files.pythonhosted.org/packages/83/d4/9087a5b75ce47659d47c139235e993b6560d5b98d65faf36b9bff568c360/pydantic_core-2.28.0-cp312-cp312-win32.whl", hash = "sha256:778050dcaddc94a27e9494076a52dec9906c00f983a9f31749ebd23a7802b12e", size = 1908917 }, 496 | { url = "https://files.pythonhosted.org/packages/62/a3/160b9e8dc1560e831b17af3a5774212afa8e6abb9a3e54ed641a69994eb3/pydantic_core-2.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:d7157fe9c6a61f583eb34702e4ced5c88f8909ae8d9da04a6ed20c42c38fe93b", size = 2000833 }, 497 | { url = "https://files.pythonhosted.org/packages/c8/60/b011ae498c68440aa51cc0c1b2e48b55c16c7c065c381c4ba21f44c734ea/pydantic_core-2.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:ba839090a6d51a4e23a63d89adc34184a0678b99ed70d88ad771c0b4788fef7c", size = 1893667 }, 498 | { url = "https://files.pythonhosted.org/packages/27/ac/ad0db96ea692c41f79cc88ee1a789758f59145c1b3b62f1f459de9b58c93/pydantic_core-2.28.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:52ced3f0e3bf82a16ebaccf0c5e344e883b18ae0cabec50b8c7536b78a9e1985", size = 2019869 }, 499 | { url = "https://files.pythonhosted.org/packages/dd/f9/bad9edb48c81356db1a4f345ba9dbfce4588a8ddbcb7a40688e2deb4823c/pydantic_core-2.28.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2030511a3f4cf9579c8c64ac9ad6884ff8183e307e01a13263c6eee38613e5c5", size = 1878000 }, 500 | { url = "https://files.pythonhosted.org/packages/6c/0e/76155117c0a93345b3dd53b7f91fa5c07b0dfdfc8623e2337025074336eb/pydantic_core-2.28.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd17656fe8380503e8bd7ca52c046bc880777baeecf39b4fb6da3d67a723c001", size = 1900780 }, 501 | { url = "https://files.pythonhosted.org/packages/09/8f/8195f479f00f64d7f754221f4dc902be3ac5fe0da207897f260cc1716314/pydantic_core-2.28.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:853cfdb508521d165d257ea8599cb97b2fd0e002077cbc602fe7fe1013fe474f", size = 1985068 }, 502 | { url = "https://files.pythonhosted.org/packages/4c/30/80726e083e8971d3cc2cfa1bed0089a687e3bacddcc1376f0ff46f555013/pydantic_core-2.28.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28cfde9285867d593893168157dbe3e41a29a5e19104e62c5170922986131f6c", size = 2116529 }, 503 | { url = "https://files.pythonhosted.org/packages/43/c0/3225b271d7ad30dc2e238765890cf690922fb8a3f3dcbbce1e0c3a052d89/pydantic_core-2.28.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:146f9d4fa7be4d8e61e0bd8216165c88d599b349ef5fdacf709e0c95e6e90836", size = 2708955 }, 504 | { url = "https://files.pythonhosted.org/packages/af/2b/60129f17d71b248ac61df1b2cbde93ede678e4834e660ed20465f19cc2e0/pydantic_core-2.28.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe6bbdec0d997f2fd61ace5db1484aae40410df0102cd36fa4eede7a592f8f6", size = 2041650 }, 505 | { url = "https://files.pythonhosted.org/packages/b9/46/6adb00dddd64846e3dd682d507ff885914541672d0e7fb4176266e1294b2/pydantic_core-2.28.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1a56e1546770a5888c92986166f341f271afa8f75d84eb033c7e2fe14527721", size = 2123019 }, 506 | { url = "https://files.pythonhosted.org/packages/cb/23/a8a0c5a4cfc4bfd60f06f4f2699b74472c497d1590cb9d825ea350a49c49/pydantic_core-2.28.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:efd093aaa03704ac52805a931720827ed21b55382b380d85379b245aad638c8e", size = 2062084 }, 507 | { url = "https://files.pythonhosted.org/packages/2b/37/a0e30fe8eaaf58f714d0a1364d972d03ff8425b27cfb6307fa0bf28cf133/pydantic_core-2.28.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:44aeccdf8e62b071ae3694f9bc6451cb8d3857b3d092d10faa402ac1498f73e2", size = 2236546 }, 508 | { url = "https://files.pythonhosted.org/packages/8c/6f/8494dd72f6d96718b297a22e45e5a1e99c70c4fde64ae6d0bb1b35c8ea83/pydantic_core-2.28.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d925a056b850ff36a474c642cdc7fd8480f77be30b49d6dedb342b7c855f6bae", size = 2232645 }, 509 | { url = "https://files.pythonhosted.org/packages/f3/d9/3fbcf3a8150b4305407989c1443fcd4d6034420a03541b0843068da73046/pydantic_core-2.28.0-cp313-cp313-win32.whl", hash = "sha256:19197465bc206931820b132e99660647ef5316793063b2837fc971934c5587ec", size = 1915993 }, 510 | { url = "https://files.pythonhosted.org/packages/32/96/819d3705999e41cf77c70f729b3cf056612b1c4265f2d45546e7665e4ce9/pydantic_core-2.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:9b86cfcd45d88b723d34d2920bc136cc26ec050273a24fab69876a31573c7de6", size = 2001692 }, 511 | { url = "https://files.pythonhosted.org/packages/a9/21/6c1e0ac8331d95bd2dae92da8a5b196f5110a1a41604c2cb55afce420473/pydantic_core-2.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:7c60696a424819b800964afde63a51d3d7f1eab949660bfed6f4f4f560e119c9", size = 1899280 }, 512 | ] 513 | 514 | [[package]] 515 | name = "pydantic-settings" 516 | version = "2.7.1" 517 | source = { registry = "https://pypi.org/simple" } 518 | dependencies = [ 519 | { name = "pydantic" }, 520 | { name = "python-dotenv" }, 521 | ] 522 | sdist = { url = "https://files.pythonhosted.org/packages/73/7b/c58a586cd7d9ac66d2ee4ba60ca2d241fa837c02bca9bea80a9a8c3d22a9/pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93", size = 79920 } 523 | wheels = [ 524 | { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718 }, 525 | ] 526 | 527 | [[package]] 528 | name = "pygments" 529 | version = "2.19.1" 530 | source = { registry = "https://pypi.org/simple" } 531 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } 532 | wheels = [ 533 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, 534 | ] 535 | 536 | [[package]] 537 | name = "pymongo" 538 | version = "4.9.2" 539 | source = { registry = "https://pypi.org/simple" } 540 | dependencies = [ 541 | { name = "dnspython" }, 542 | ] 543 | sdist = { url = "https://files.pythonhosted.org/packages/fb/43/d5e8993bd43e6f9cbe985e8ae1398eb73309e88694ac2ea618eacbc9cea2/pymongo-4.9.2.tar.gz", hash = "sha256:3e63535946f5df7848307b9031aa921f82bb0cbe45f9b0c3296f2173f9283eb0", size = 1889366 } 544 | wheels = [ 545 | { url = "https://files.pythonhosted.org/packages/a1/08/7d95aab0463dc5a2c460a0b4e50a45a743afbe20986f47f87a9a88f43c0c/pymongo-4.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8083bbe8cb10bb33dca4d93f8223dd8d848215250bb73867374650bac5fe69e1", size = 941617 }, 546 | { url = "https://files.pythonhosted.org/packages/bb/28/40613d8d97fc33bf2b9187446a6746925623aa04a9a27c9b058e97076f7a/pymongo-4.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1b8c636bf557c7166e3799bbf1120806ca39e3f06615b141c88d9c9ceae4d8c", size = 941394 }, 547 | { url = "https://files.pythonhosted.org/packages/df/b2/7f1a0d75f538c0dcaa004ea69e28706fa3ca72d848e0a5a7dafd30939fff/pymongo-4.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8aac5dce28454f47576063fbad31ea9789bba67cab86c95788f97aafd810e65b", size = 1907396 }, 548 | { url = "https://files.pythonhosted.org/packages/ba/70/9304bae47a361a4b12adb5be714bad41478c0e5bc3d6cf403b328d6398a0/pymongo-4.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1d5e7123af1fddf15b2b53e58f20bf5242884e671bcc3860f5e954fe13aeddd", size = 1986029 }, 549 | { url = "https://files.pythonhosted.org/packages/ae/51/ac0378d001995c4a705da64a4a2b8e1732f95de5080b752d69f452930cc7/pymongo-4.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe97c847b56d61e533a7af0334193d6b28375b9189effce93129c7e4733794a9", size = 1949088 }, 550 | { url = "https://files.pythonhosted.org/packages/1a/30/e93dc808039dc29fc47acee64f128aa650aacae3e4b57b68e01ff1001cda/pymongo-4.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ad54433a996e2d1985a9cd8fc82538ca8747c95caae2daf453600cc8c317f9", size = 1910516 }, 551 | { url = "https://files.pythonhosted.org/packages/2b/34/895b9cad3bd5342d5ab51a853ed3a814840ce281d55c6928968e9f3f49f5/pymongo-4.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98b9cade40f5b13e04492a42ae215c3721099be1014ddfe0fbd23f27e4f62c0c", size = 1860499 }, 552 | { url = "https://files.pythonhosted.org/packages/24/7e/167818f324bf2122d45551680671a3c6406a345d3fcace4e737f57bda4e4/pymongo-4.9.2-cp312-cp312-win32.whl", hash = "sha256:dde6068ae7c62ea8ee2c5701f78c6a75618cada7e11f03893687df87709558de", size = 901282 }, 553 | { url = "https://files.pythonhosted.org/packages/12/6b/b7ffa7114177fc1c60ae529512b82629ff7e25d19be88e97f2d0ddd16717/pymongo-4.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:e1ab6cd7cd2d38ffc7ccdc79fdc166c7a91a63f844a96e3e6b2079c054391c68", size = 924925 }, 554 | { url = "https://files.pythonhosted.org/packages/5b/d6/b57ef5f376e2e171218a98b8c30dfd001aa5cac6338aa7f3ca76e6315667/pymongo-4.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1ad79d6a74f439a068caf9a1e2daeabc20bf895263435484bbd49e90fbea7809", size = 995233 }, 555 | { url = "https://files.pythonhosted.org/packages/32/80/4ec79e36e99f86a063d297a334883fb5115ad70e9af46142b8dc33f636fa/pymongo-4.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:877699e21703717507cbbea23e75b419f81a513b50b65531e1698df08b2d7094", size = 995025 }, 556 | { url = "https://files.pythonhosted.org/packages/c4/fd/8f5464321fdf165700f10aec93b07a75c3537be593291ac2f8c8f5f69bd0/pymongo-4.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc9322ce7cf116458a637ac10517b0c5926a8211202be6dbdc51dab4d4a9afc8", size = 2167429 }, 557 | { url = "https://files.pythonhosted.org/packages/da/42/0f749d805d17f5b17f48f2ee1aaf2a74e67939607b87b245e5ec9b4c1452/pymongo-4.9.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cca029f46acf475504eedb33c7839f030c4bc4f946dcba12d9a954cc48850b79", size = 2258834 }, 558 | { url = "https://files.pythonhosted.org/packages/b8/52/b0c1b8e9cbeae234dd1108a906f30b680755533b7229f9f645d7e7adad25/pymongo-4.9.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c8c861e77527eec5a4b7363c16030dd0374670b620b08a5300f97594bbf5a40", size = 2216412 }, 559 | { url = "https://files.pythonhosted.org/packages/4d/20/53395473a1023bb6a670b68fbfa937664c75b354c2444463075ff43523e2/pymongo-4.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fc70326ae71b3c7b8d6af82f46bb71dafdba3c8f335b29382ae9cf263ef3a5c", size = 2168891 }, 560 | { url = "https://files.pythonhosted.org/packages/01/b7/fa4030279d8a4a9c0a969a719b6b89da8a59795b5cdf129ef553fce6d1f2/pymongo-4.9.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba9d2f6df977fee24437f82f7412460b0628cd6b961c4235c9cff71577a5b61f", size = 2109380 }, 561 | { url = "https://files.pythonhosted.org/packages/f3/55/f252972a039fc6bfca748625c5080d6f88801eb61f118fe79cde47342d6a/pymongo-4.9.2-cp313-cp313-win32.whl", hash = "sha256:b3254769e708bc4aa634745c262081d13c841a80038eff3afd15631540a1d227", size = 946962 }, 562 | { url = "https://files.pythonhosted.org/packages/7b/36/88d8438699ba09b714dece00a4a7462330c1d316f5eaa28db450572236f6/pymongo-4.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:169b85728cc17800344ba17d736375f400ef47c9fbb4c42910c4b3e7c0247382", size = 975113 }, 563 | ] 564 | 565 | [[package]] 566 | name = "pytest" 567 | version = "8.3.4" 568 | source = { registry = "https://pypi.org/simple" } 569 | dependencies = [ 570 | { name = "colorama", marker = "sys_platform == 'win32'" }, 571 | { name = "iniconfig" }, 572 | { name = "packaging" }, 573 | { name = "pluggy" }, 574 | ] 575 | sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } 576 | wheels = [ 577 | { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, 578 | ] 579 | 580 | [[package]] 581 | name = "pytest-cov" 582 | version = "6.0.0" 583 | source = { registry = "https://pypi.org/simple" } 584 | dependencies = [ 585 | { name = "coverage" }, 586 | { name = "pytest" }, 587 | ] 588 | sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } 589 | wheels = [ 590 | { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, 591 | ] 592 | 593 | [[package]] 594 | name = "python-dotenv" 595 | version = "1.0.1" 596 | source = { registry = "https://pypi.org/simple" } 597 | sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } 598 | wheels = [ 599 | { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, 600 | ] 601 | 602 | [[package]] 603 | name = "python-multipart" 604 | version = "0.0.20" 605 | source = { registry = "https://pypi.org/simple" } 606 | sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 } 607 | wheels = [ 608 | { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 }, 609 | ] 610 | 611 | [[package]] 612 | name = "pyyaml" 613 | version = "6.0.2" 614 | source = { registry = "https://pypi.org/simple" } 615 | sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } 616 | wheels = [ 617 | { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, 618 | { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, 619 | { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, 620 | { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, 621 | { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, 622 | { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, 623 | { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, 624 | { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, 625 | { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, 626 | { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, 627 | { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, 628 | { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, 629 | { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, 630 | { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, 631 | { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, 632 | { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, 633 | { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, 634 | { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, 635 | ] 636 | 637 | [[package]] 638 | name = "rich" 639 | version = "13.9.4" 640 | source = { registry = "https://pypi.org/simple" } 641 | dependencies = [ 642 | { name = "markdown-it-py" }, 643 | { name = "pygments" }, 644 | ] 645 | sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } 646 | wheels = [ 647 | { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, 648 | ] 649 | 650 | [[package]] 651 | name = "rich-toolkit" 652 | version = "0.12.0" 653 | source = { registry = "https://pypi.org/simple" } 654 | dependencies = [ 655 | { name = "click" }, 656 | { name = "rich" }, 657 | { name = "typing-extensions" }, 658 | ] 659 | sdist = { url = "https://files.pythonhosted.org/packages/d2/88/58c193e2e353b0ef8b4b9a91031bbcf8a9a3b431f5ebb4f55c3f3b1992e8/rich_toolkit-0.12.0.tar.gz", hash = "sha256:facb0b40418010309f77abd44e2583b4936656f6ee5c8625da807564806a6c40", size = 71673 } 660 | wheels = [ 661 | { url = "https://files.pythonhosted.org/packages/ac/3c/3b66696fc8a6c980674851108d7d57fbcbfedbefb3d8b61a64166dc9b18e/rich_toolkit-0.12.0-py3-none-any.whl", hash = "sha256:a2da4416384410ae871e890db7edf8623e1f5e983341dbbc8cc03603ce24f0ab", size = 13012 }, 662 | ] 663 | 664 | [[package]] 665 | name = "ruff" 666 | version = "0.9.4" 667 | source = { registry = "https://pypi.org/simple" } 668 | sdist = { url = "https://files.pythonhosted.org/packages/c0/17/529e78f49fc6f8076f50d985edd9a2cf011d1dbadb1cdeacc1d12afc1d26/ruff-0.9.4.tar.gz", hash = "sha256:6907ee3529244bb0ed066683e075f09285b38dd5b4039370df6ff06041ca19e7", size = 3599458 } 669 | wheels = [ 670 | { url = "https://files.pythonhosted.org/packages/b6/f8/3fafb7804d82e0699a122101b5bee5f0d6e17c3a806dcbc527bb7d3f5b7a/ruff-0.9.4-py3-none-linux_armv6l.whl", hash = "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706", size = 11668400 }, 671 | { url = "https://files.pythonhosted.org/packages/2e/a6/2efa772d335da48a70ab2c6bb41a096c8517ca43c086ea672d51079e3d1f/ruff-0.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf", size = 11628395 }, 672 | { url = "https://files.pythonhosted.org/packages/dc/d7/cd822437561082f1c9d7225cc0d0fbb4bad117ad7ac3c41cd5d7f0fa948c/ruff-0.9.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:54499fb08408e32b57360f6f9de7157a5fec24ad79cb3f42ef2c3f3f728dfe2b", size = 11090052 }, 673 | { url = "https://files.pythonhosted.org/packages/9e/67/3660d58e893d470abb9a13f679223368ff1684a4ef40f254a0157f51b448/ruff-0.9.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37c892540108314a6f01f105040b5106aeb829fa5fb0561d2dcaf71485021137", size = 11882221 }, 674 | { url = "https://files.pythonhosted.org/packages/79/d1/757559995c8ba5f14dfec4459ef2dd3fcea82ac43bc4e7c7bf47484180c0/ruff-0.9.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de9edf2ce4b9ddf43fd93e20ef635a900e25f622f87ed6e3047a664d0e8f810e", size = 11424862 }, 675 | { url = "https://files.pythonhosted.org/packages/c0/96/7915a7c6877bb734caa6a2af424045baf6419f685632469643dbd8eb2958/ruff-0.9.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87c90c32357c74f11deb7fbb065126d91771b207bf9bfaaee01277ca59b574ec", size = 12626735 }, 676 | { url = "https://files.pythonhosted.org/packages/0e/cc/dadb9b35473d7cb17c7ffe4737b4377aeec519a446ee8514123ff4a26091/ruff-0.9.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56acd6c694da3695a7461cc55775f3a409c3815ac467279dfa126061d84b314b", size = 13255976 }, 677 | { url = "https://files.pythonhosted.org/packages/5f/c3/ad2dd59d3cabbc12df308cced780f9c14367f0321e7800ca0fe52849da4c/ruff-0.9.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0c93e7d47ed951b9394cf352d6695b31498e68fd5782d6cbc282425655f687a", size = 12752262 }, 678 | { url = "https://files.pythonhosted.org/packages/c7/17/5f1971e54bd71604da6788efd84d66d789362b1105e17e5ccc53bba0289b/ruff-0.9.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4c8772670aecf037d1bf7a07c39106574d143b26cfe5ed1787d2f31e800214", size = 14401648 }, 679 | { url = "https://files.pythonhosted.org/packages/30/24/6200b13ea611b83260501b6955b764bb320e23b2b75884c60ee7d3f0b68e/ruff-0.9.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfc5f1d7afeda8d5d37660eeca6d389b142d7f2b5a1ab659d9214ebd0e025231", size = 12414702 }, 680 | { url = "https://files.pythonhosted.org/packages/34/cb/f5d50d0c4ecdcc7670e348bd0b11878154bc4617f3fdd1e8ad5297c0d0ba/ruff-0.9.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faa935fc00ae854d8b638c16a5f1ce881bc3f67446957dd6f2af440a5fc8526b", size = 11859608 }, 681 | { url = "https://files.pythonhosted.org/packages/d6/f4/9c8499ae8426da48363bbb78d081b817b0f64a9305f9b7f87eab2a8fb2c1/ruff-0.9.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a6c634fc6f5a0ceae1ab3e13c58183978185d131a29c425e4eaa9f40afe1e6d6", size = 11485702 }, 682 | { url = "https://files.pythonhosted.org/packages/18/59/30490e483e804ccaa8147dd78c52e44ff96e1c30b5a95d69a63163cdb15b/ruff-0.9.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:433dedf6ddfdec7f1ac7575ec1eb9844fa60c4c8c2f8887a070672b8d353d34c", size = 12067782 }, 683 | { url = "https://files.pythonhosted.org/packages/3d/8c/893fa9551760b2f8eb2a351b603e96f15af167ceaf27e27ad873570bc04c/ruff-0.9.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d612dbd0f3a919a8cc1d12037168bfa536862066808960e0cc901404b77968f0", size = 12483087 }, 684 | { url = "https://files.pythonhosted.org/packages/23/15/f6751c07c21ca10e3f4a51ea495ca975ad936d780c347d9808bcedbd7182/ruff-0.9.4-py3-none-win32.whl", hash = "sha256:db1192ddda2200671f9ef61d9597fcef89d934f5d1705e571a93a67fb13a4402", size = 9852302 }, 685 | { url = "https://files.pythonhosted.org/packages/12/41/2d2d2c6a72e62566f730e49254f602dfed23019c33b5b21ea8f8917315a1/ruff-0.9.4-py3-none-win_amd64.whl", hash = "sha256:05bebf4cdbe3ef75430d26c375773978950bbf4ee3c95ccb5448940dc092408e", size = 10850051 }, 686 | { url = "https://files.pythonhosted.org/packages/c6/e6/3d6ec3bc3d254e7f005c543a661a41c3e788976d0e52a1ada195bd664344/ruff-0.9.4-py3-none-win_arm64.whl", hash = "sha256:585792f1e81509e38ac5123492f8875fbc36f3ede8185af0a26df348e5154f41", size = 10078251 }, 687 | ] 688 | 689 | [[package]] 690 | name = "shellingham" 691 | version = "1.5.4" 692 | source = { registry = "https://pypi.org/simple" } 693 | sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } 694 | wheels = [ 695 | { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, 696 | ] 697 | 698 | [[package]] 699 | name = "sniffio" 700 | version = "1.3.1" 701 | source = { registry = "https://pypi.org/simple" } 702 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } 703 | wheels = [ 704 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, 705 | ] 706 | 707 | [[package]] 708 | name = "starlette" 709 | version = "0.41.3" 710 | source = { registry = "https://pypi.org/simple" } 711 | dependencies = [ 712 | { name = "anyio" }, 713 | ] 714 | sdist = { url = "https://files.pythonhosted.org/packages/1a/4c/9b5764bd22eec91c4039ef4c55334e9187085da2d8a2df7bd570869aae18/starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", size = 2574159 } 715 | wheels = [ 716 | { url = "https://files.pythonhosted.org/packages/96/00/2b325970b3060c7cecebab6d295afe763365822b1306a12eeab198f74323/starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7", size = 73225 }, 717 | ] 718 | 719 | [[package]] 720 | name = "typer" 721 | version = "0.15.1" 722 | source = { registry = "https://pypi.org/simple" } 723 | dependencies = [ 724 | { name = "click" }, 725 | { name = "rich" }, 726 | { name = "shellingham" }, 727 | { name = "typing-extensions" }, 728 | ] 729 | sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/dca7b219718afd37a0068f4f2530a727c2b74a8b6e8e0c0080a4c0de4fcd/typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a", size = 99789 } 730 | wheels = [ 731 | { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 }, 732 | ] 733 | 734 | [[package]] 735 | name = "typing-extensions" 736 | version = "4.12.2" 737 | source = { registry = "https://pypi.org/simple" } 738 | sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } 739 | wheels = [ 740 | { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, 741 | ] 742 | 743 | [[package]] 744 | name = "uvicorn" 745 | version = "0.34.0" 746 | source = { registry = "https://pypi.org/simple" } 747 | dependencies = [ 748 | { name = "click" }, 749 | { name = "h11" }, 750 | ] 751 | sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } 752 | wheels = [ 753 | { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 }, 754 | ] 755 | 756 | [package.optional-dependencies] 757 | standard = [ 758 | { name = "colorama", marker = "sys_platform == 'win32'" }, 759 | { name = "httptools" }, 760 | { name = "python-dotenv" }, 761 | { name = "pyyaml" }, 762 | { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, 763 | { name = "watchfiles" }, 764 | { name = "websockets" }, 765 | ] 766 | 767 | [[package]] 768 | name = "uvloop" 769 | version = "0.21.0" 770 | source = { registry = "https://pypi.org/simple" } 771 | sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 } 772 | wheels = [ 773 | { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284 }, 774 | { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349 }, 775 | { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089 }, 776 | { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 }, 777 | { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 }, 778 | { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 }, 779 | { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 }, 780 | { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 }, 781 | { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 }, 782 | { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 }, 783 | { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 }, 784 | { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 }, 785 | ] 786 | 787 | [[package]] 788 | name = "watchfiles" 789 | version = "1.0.3" 790 | source = { registry = "https://pypi.org/simple" } 791 | dependencies = [ 792 | { name = "anyio" }, 793 | ] 794 | sdist = { url = "https://files.pythonhosted.org/packages/3c/7e/4569184ea04b501840771b8fcecee19b2233a8b72c196061263c0ef23c0b/watchfiles-1.0.3.tar.gz", hash = "sha256:f3ff7da165c99a5412fe5dd2304dd2dbaaaa5da718aad942dcb3a178eaa70c56", size = 38185 } 795 | wheels = [ 796 | { url = "https://files.pythonhosted.org/packages/bf/a9/c8b5ab33444306e1a324cb2b51644f8458dd459e30c3841f925012893e6a/watchfiles-1.0.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:93436ed550e429da007fbafb723e0769f25bae178fbb287a94cb4ccdf42d3af3", size = 391395 }, 797 | { url = "https://files.pythonhosted.org/packages/ad/d3/403af5f07359863c03951796ddab265ee8cce1a6147510203d0bf43950e7/watchfiles-1.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c18f3502ad0737813c7dad70e3e1cc966cc147fbaeef47a09463bbffe70b0a00", size = 381432 }, 798 | { url = "https://files.pythonhosted.org/packages/f6/5f/921f2f2beabaf24b1ad81ac22bb69df8dd5771fdb68d6f34a5912a420941/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a5bc3ca468bb58a2ef50441f953e1f77b9a61bd1b8c347c8223403dc9b4ac9a", size = 441448 }, 799 | { url = "https://files.pythonhosted.org/packages/63/d7/67d0d750b246f248ccdb400a85a253e93e419ea5b6cbe968fa48b97a5f30/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d1ec043f02ca04bf21b1b32cab155ce90c651aaf5540db8eb8ad7f7e645cba8", size = 446852 }, 800 | { url = "https://files.pythonhosted.org/packages/53/7c/d7cd94c7d0905f1e2f1c2232ea9bc39b1a48affd007e09c547ead96edb8f/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f58d3bfafecf3d81c15d99fc0ecf4319e80ac712c77cf0ce2661c8cf8bf84066", size = 471662 }, 801 | { url = "https://files.pythonhosted.org/packages/26/81/738f8e66f7525753996b8aa292f78dcec1ef77887d62e6cdfb04cc2f352f/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1df924ba82ae9e77340101c28d56cbaff2c991bd6fe8444a545d24075abb0a87", size = 493765 }, 802 | { url = "https://files.pythonhosted.org/packages/d2/50/78e21f5da24ab39114e9b24f7b0945ea1c6fc7bc9ae86cd87f8eaeb47325/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:632a52dcaee44792d0965c17bdfe5dc0edad5b86d6a29e53d6ad4bf92dc0ff49", size = 490558 }, 803 | { url = "https://files.pythonhosted.org/packages/a8/93/1873fea6354b2858eae8970991d64e9a449d87726d596490d46bf00af8ed/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bf4b459d94a0387617a1b499f314aa04d8a64b7a0747d15d425b8c8b151da0", size = 442808 }, 804 | { url = "https://files.pythonhosted.org/packages/4f/b4/2fc4c92fb28b029f66d04a4d430fe929284e9ff717b04bb7a3bb8a7a5605/watchfiles-1.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca94c85911601b097d53caeeec30201736ad69a93f30d15672b967558df02885", size = 615287 }, 805 | { url = "https://files.pythonhosted.org/packages/1e/d4/93da24db39257e440240d338b617c5153ad11d361c34108f5c0e1e0743eb/watchfiles-1.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65ab1fb635476f6170b07e8e21db0424de94877e4b76b7feabfe11f9a5fc12b5", size = 612812 }, 806 | { url = "https://files.pythonhosted.org/packages/c6/67/9fd3661c2dc0309abd6021876653d91e8b64fb279529e2cadaa3520ef3e3/watchfiles-1.0.3-cp312-cp312-win32.whl", hash = "sha256:49bc1bc26abf4f32e132652f4b3bfeec77d8f8f62f57652703ef127e85a3e38d", size = 271642 }, 807 | { url = "https://files.pythonhosted.org/packages/ae/aa/8c887edb78cd67f5d4d6a35c3aeb46d748643ebf962163130fb1871e2ee0/watchfiles-1.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:48681c86f2cb08348631fed788a116c89c787fdf1e6381c5febafd782f6c3b44", size = 285505 }, 808 | { url = "https://files.pythonhosted.org/packages/7b/31/d212fa6390f0e73a91913ada0b925b294a78d67794795371208baf73f0b5/watchfiles-1.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:9e080cf917b35b20c889225a13f290f2716748362f6071b859b60b8847a6aa43", size = 277263 }, 809 | { url = "https://files.pythonhosted.org/packages/36/77/0ceb864c854c59bc5326484f88a900c70b4a05e3792e0ce340689988dd5e/watchfiles-1.0.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e153a690b7255c5ced17895394b4f109d5dcc2a4f35cb809374da50f0e5c456a", size = 391061 }, 810 | { url = "https://files.pythonhosted.org/packages/00/66/327046cfe276a6e4af1a9a58fc99321e25783e501dc68c4c82de2d1bd3a7/watchfiles-1.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac1be85fe43b4bf9a251978ce5c3bb30e1ada9784290441f5423a28633a958a7", size = 381177 }, 811 | { url = "https://files.pythonhosted.org/packages/66/8a/420e2833deaa88e8ca7d94a497ec60fde610c66206a1776f049dc5ad3a4e/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec98e31e1844eac860e70d9247db9d75440fc8f5f679c37d01914568d18721", size = 441293 }, 812 | { url = "https://files.pythonhosted.org/packages/58/56/2627795ecdf3f0f361458cfa74c583d5041615b9ad81bc25f8c66a6c44a2/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0179252846be03fa97d4d5f8233d1c620ef004855f0717712ae1c558f1974a16", size = 446209 }, 813 | { url = "https://files.pythonhosted.org/packages/8f/d0/11c8dcd8a9995f0c075d76f1d06068bbb7a17583a19c5be75361497a4074/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:995c374e86fa82126c03c5b4630c4e312327ecfe27761accb25b5e1d7ab50ec8", size = 471227 }, 814 | { url = "https://files.pythonhosted.org/packages/cb/8f/baa06574eaf48173882c4cdc3636993d0854661be7d88193e015ef996c73/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29b9cb35b7f290db1c31fb2fdf8fc6d3730cfa4bca4b49761083307f441cac5a", size = 493205 }, 815 | { url = "https://files.pythonhosted.org/packages/ee/e8/9af886b4d3daa281047b542ffd2eb8f76dae9dd6ca0e21c5df4593b98574/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f8dc09ae69af50bead60783180f656ad96bd33ffbf6e7a6fce900f6d53b08f1", size = 489090 }, 816 | { url = "https://files.pythonhosted.org/packages/81/02/62085db54b151fc02e22d47b288d19e99031dc9af73151289a7ab6621f9a/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:489b80812f52a8d8c7b0d10f0d956db0efed25df2821c7a934f6143f76938bd6", size = 442610 }, 817 | { url = "https://files.pythonhosted.org/packages/61/81/980439c5d3fd3c69ba7124a56e1016d0b824ced2192ffbfe7062d53f524b/watchfiles-1.0.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:228e2247de583475d4cebf6b9af5dc9918abb99d1ef5ee737155bb39fb33f3c0", size = 614781 }, 818 | { url = "https://files.pythonhosted.org/packages/55/98/e11401d8e9cd5d2bd0e95e9bf750f397489681965ee0c72fb84732257912/watchfiles-1.0.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1550be1a5cb3be08a3fb84636eaafa9b7119b70c71b0bed48726fd1d5aa9b868", size = 612637 }, 819 | { url = "https://files.pythonhosted.org/packages/50/be/8393b68f2add0f839be6863f151bd6a7b242efc6eb2ce0c9f7d135d529cc/watchfiles-1.0.3-cp313-cp313-win32.whl", hash = "sha256:16db2d7e12f94818cbf16d4c8938e4d8aaecee23826344addfaaa671a1527b07", size = 271170 }, 820 | { url = "https://files.pythonhosted.org/packages/f0/da/725f97a8b1b4e7b3e4331cce3ef921b12568af3af403b9f0f61ede036898/watchfiles-1.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:160eff7d1267d7b025e983ca8460e8cc67b328284967cbe29c05f3c3163711a3", size = 285246 }, 821 | ] 822 | 823 | [[package]] 824 | name = "websockets" 825 | version = "14.1" 826 | source = { registry = "https://pypi.org/simple" } 827 | sdist = { url = "https://files.pythonhosted.org/packages/f4/1b/380b883ce05bb5f45a905b61790319a28958a9ab1e4b6b95ff5464b60ca1/websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8", size = 162840 } 828 | wheels = [ 829 | { url = "https://files.pythonhosted.org/packages/55/64/55698544ce29e877c9188f1aee9093712411a8fc9732cca14985e49a8e9c/websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed", size = 161957 }, 830 | { url = "https://files.pythonhosted.org/packages/a2/b1/b088f67c2b365f2c86c7b48edb8848ac27e508caf910a9d9d831b2f343cb/websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d", size = 159620 }, 831 | { url = "https://files.pythonhosted.org/packages/c1/89/2a09db1bbb40ba967a1b8225b07b7df89fea44f06de9365f17f684d0f7e6/websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707", size = 159852 }, 832 | { url = "https://files.pythonhosted.org/packages/ca/c1/f983138cd56e7d3079f1966e81f77ce6643f230cd309f73aa156bb181749/websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a", size = 169675 }, 833 | { url = "https://files.pythonhosted.org/packages/c1/c8/84191455d8660e2a0bdb33878d4ee5dfa4a2cedbcdc88bbd097303b65bfa/websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45", size = 168619 }, 834 | { url = "https://files.pythonhosted.org/packages/8d/a7/62e551fdcd7d44ea74a006dc193aba370505278ad76efd938664531ce9d6/websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58", size = 169042 }, 835 | { url = "https://files.pythonhosted.org/packages/ad/ed/1532786f55922c1e9c4d329608e36a15fdab186def3ca9eb10d7465bc1cc/websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058", size = 169345 }, 836 | { url = "https://files.pythonhosted.org/packages/ea/fb/160f66960d495df3de63d9bcff78e1b42545b2a123cc611950ffe6468016/websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4", size = 168725 }, 837 | { url = "https://files.pythonhosted.org/packages/cf/53/1bf0c06618b5ac35f1d7906444b9958f8485682ab0ea40dee7b17a32da1e/websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05", size = 168712 }, 838 | { url = "https://files.pythonhosted.org/packages/e5/22/5ec2f39fff75f44aa626f86fa7f20594524a447d9c3be94d8482cd5572ef/websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0", size = 162838 }, 839 | { url = "https://files.pythonhosted.org/packages/74/27/28f07df09f2983178db7bf6c9cccc847205d2b92ced986cd79565d68af4f/websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f", size = 163277 }, 840 | { url = "https://files.pythonhosted.org/packages/34/77/812b3ba5110ed8726eddf9257ab55ce9e85d97d4aa016805fdbecc5e5d48/websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9", size = 161966 }, 841 | { url = "https://files.pythonhosted.org/packages/8d/24/4fcb7aa6986ae7d9f6d083d9d53d580af1483c5ec24bdec0978307a0f6ac/websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b", size = 159625 }, 842 | { url = "https://files.pythonhosted.org/packages/f8/47/2a0a3a2fc4965ff5b9ce9324d63220156bd8bedf7f90824ab92a822e65fd/websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3", size = 159857 }, 843 | { url = "https://files.pythonhosted.org/packages/dd/c8/d7b425011a15e35e17757e4df75b25e1d0df64c0c315a44550454eaf88fc/websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59", size = 169635 }, 844 | { url = "https://files.pythonhosted.org/packages/93/39/6e3b5cffa11036c40bd2f13aba2e8e691ab2e01595532c46437b56575678/websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2", size = 168578 }, 845 | { url = "https://files.pythonhosted.org/packages/cf/03/8faa5c9576299b2adf34dcccf278fc6bbbcda8a3efcc4d817369026be421/websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da", size = 169018 }, 846 | { url = "https://files.pythonhosted.org/packages/8c/05/ea1fec05cc3a60defcdf0bb9f760c3c6bd2dd2710eff7ac7f891864a22ba/websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9", size = 169383 }, 847 | { url = "https://files.pythonhosted.org/packages/21/1d/eac1d9ed787f80754e51228e78855f879ede1172c8b6185aca8cef494911/websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7", size = 168773 }, 848 | { url = "https://files.pythonhosted.org/packages/0e/1b/e808685530185915299740d82b3a4af3f2b44e56ccf4389397c7a5d95d39/websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a", size = 168757 }, 849 | { url = "https://files.pythonhosted.org/packages/b6/19/6ab716d02a3b068fbbeb6face8a7423156e12c446975312f1c7c0f4badab/websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6", size = 162834 }, 850 | { url = "https://files.pythonhosted.org/packages/6c/fd/ab6b7676ba712f2fc89d1347a4b5bdc6aa130de10404071f2b2606450209/websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0", size = 163277 }, 851 | { url = "https://files.pythonhosted.org/packages/b0/0b/c7e5d11020242984d9d37990310520ed663b942333b83a033c2f20191113/websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", size = 156277 }, 852 | ] 853 | --------------------------------------------------------------------------------